mirror of
https://github.com/SuspiciousActivity/ByteEdit.git
synced 2026-08-13 17:56:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46c0596768 | ||
|
|
74e9491fcf | ||
|
|
198c76823b | ||
|
|
1c6a72d951 | ||
|
|
ed9b6a177b | ||
|
|
a9612c058c | ||
|
|
b86e8658e2 | ||
|
|
a0b955a6ae | ||
|
|
97422300c8 | ||
|
|
8832d67d8b | ||
|
|
71c224f83f | ||
|
|
71437eac81 | ||
|
|
5a5cb6425f | ||
|
|
a85171624b | ||
|
|
c2e22e55ad | ||
|
|
ea282d240e | ||
|
|
5bec62789e | ||
|
|
be2930f720 | ||
|
|
e665527182 | ||
|
|
3a30fbdd78 | ||
|
|
bc0ec73071 | ||
|
|
b2267947c8 | ||
|
|
15c581ceb6 | ||
|
|
c0005493fd | ||
|
|
fb4da77359 | ||
|
|
d1710ea6a5 | ||
|
|
ad55d6793c | ||
|
|
ac247a89ca | ||
|
|
b5e4847be5 | ||
|
|
30c9c81d38 | ||
|
|
65235c6b5b | ||
|
|
d8096a4ec5 | ||
|
|
add82951e6 |
No files matched your search
@@ -2,8 +2,6 @@
|
|||||||
A simple, text based Java Bytecode Editor.
|
A simple, text based Java Bytecode Editor.
|
||||||
It uses ObjectWeb ASM (http://asm.ow2.org/) and the RSyntaxTextArea from https://github.com/bobbylight/RSyntaxTextArea
|
It uses ObjectWeb ASM (http://asm.ow2.org/) and the RSyntaxTextArea from https://github.com/bobbylight/RSyntaxTextArea
|
||||||
|
|
||||||
Get the precompiled version from here: https://github.com/SuspiciousActivity/Random-Java-Stuff/blob/master/ByteEdit.jar
|
|
||||||
|
|
||||||
To open up a file, drag it onto the left side. To save a class, press CTRL + S on the right side, to save the jar file, press on the left side. With F5 you can reload either the file or only the class.
|
To open up a file, drag it onto the left side. To save a class, press CTRL + S on the right side, to save the jar file, press on the left side. With F5 you can reload either the file or only the class.
|
||||||
|
|
||||||
To search/replace in a file, press CTRL + F.
|
To search/replace in a file, press CTRL + F.
|
||||||
@@ -12,12 +10,10 @@ To open a class, press CTRL + T.
|
|||||||
|
|
||||||
To change settings like auto-computation of stack frames and max locals/stack press CTRL + O.
|
To change settings like auto-computation of stack frames and max locals/stack press CTRL + O.
|
||||||
|
|
||||||
To go to the field/method definition in the selected line press CTRL + G.
|
|
||||||
|
|
||||||
To (un-)escape unicode characters, press CTRL + U.
|
To (un-)escape unicode characters, press CTRL + U.
|
||||||
|
|
||||||
To rename a field/method with attention to references in the selected line, press CTRL + R.
|
To rename a field/method with attention to references in the selected line, press CTRL + R.
|
||||||
|
|
||||||
To quickly compile some java code, press CTRL + E.
|
To quickly compile some java code, press CTRL + E.
|
||||||
|
|
||||||
To switch between light and dark theme, press CTRL + B.
|
To switch between themes, press CTRL + B.
|
||||||
@@ -15,6 +15,8 @@ import java.io.StringWriter;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
@@ -32,7 +34,8 @@ import org.fife.ui.rtextarea.RTextScrollPane;
|
|||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import me.ByteEdit.edit.Disassembler;
|
import me.ByteEdit.decompiler.EnumDecompiler;
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.main.ThemeManager;
|
import me.ByteEdit.main.ThemeManager;
|
||||||
|
|
||||||
@@ -105,6 +108,8 @@ public class CompilationBox extends JFrame {
|
|||||||
null, Arrays.asList(new JavaSourceFromString("Compiled", source))).call();
|
null, Arrays.asList(new JavaSourceFromString("Compiled", source))).call();
|
||||||
String res = out.toString();
|
String res = out.toString();
|
||||||
if (res.isEmpty()) {
|
if (res.isEmpty()) {
|
||||||
|
SingleThreadedExecutor.submit(() -> {
|
||||||
|
try {
|
||||||
File clazz = new File(tmpFolder, "Compiled.class");
|
File clazz = new File(tmpFolder, "Compiled.class");
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
InputStream is = new FileInputStream(clazz);
|
InputStream is = new FileInputStream(clazz);
|
||||||
@@ -114,10 +119,18 @@ public class CompilationBox extends JFrame {
|
|||||||
baos.write(tmp, 0, r);
|
baos.write(tmp, 0, r);
|
||||||
}
|
}
|
||||||
is.close();
|
is.close();
|
||||||
|
|
||||||
ClassReader read = new ClassReader(baos.toByteArray());
|
ClassReader read = new ClassReader(baos.toByteArray());
|
||||||
ClassNode node = new ClassNode();
|
ClassNode node = new ClassNode();
|
||||||
read.accept(node, 0);
|
read.accept(node, 0);
|
||||||
String dis = Disassembler.disassemble(node);
|
EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||||
|
ClassNode mainNode = node;
|
||||||
|
|
||||||
|
Map<String, ClassNode> classNodes;
|
||||||
|
synchronized (Main.classNodes) {
|
||||||
|
classNodes = new HashMap<>(Main.classNodes);
|
||||||
|
}
|
||||||
|
classNodes.put("Compiled", node);
|
||||||
File[] files = tmpFolder.listFiles();
|
File[] files = tmpFolder.listFiles();
|
||||||
if (files != null)
|
if (files != null)
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
@@ -132,17 +145,26 @@ public class CompilationBox extends JFrame {
|
|||||||
read = new ClassReader(baos.toByteArray());
|
read = new ClassReader(baos.toByteArray());
|
||||||
node = new ClassNode();
|
node = new ClassNode();
|
||||||
read.accept(node, 0);
|
read.accept(node, 0);
|
||||||
dis += "\n" + Disassembler.disassemble(node);
|
classNodes.put(node.name, node);
|
||||||
}
|
}
|
||||||
compSuccess.textArea.setText(dis);
|
compSuccess.textArea
|
||||||
|
.setText(decompiler.getDecompiler().decompile(mainNode, classNodes));
|
||||||
compSuccess.setVisible(true);
|
compSuccess.setVisible(true);
|
||||||
} else {
|
} catch (IOException e2) {
|
||||||
JOptionPane.showMessageDialog(CompilationBox.this, res, "Error!", JOptionPane.ERROR_MESSAGE);
|
e2.printStackTrace();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
for (File f : tmpFolder.listFiles()) {
|
for (File f : tmpFolder.listFiles()) {
|
||||||
Files.delete(f.toPath());
|
Files.delete(f.toPath());
|
||||||
}
|
}
|
||||||
Files.delete(tmpFolder.toPath());
|
Files.delete(tmpFolder.toPath());
|
||||||
|
} catch (IOException e2) {
|
||||||
|
e2.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
JOptionPane.showMessageDialog(CompilationBox.this, res, "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -150,7 +172,7 @@ public class CompilationBox extends JFrame {
|
|||||||
}, ctrlS, JComponent.WHEN_FOCUSED);
|
}, ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaSourceFromString extends SimpleJavaFileObject {
|
private static class JavaSourceFromString extends SimpleJavaFileObject {
|
||||||
final String code;
|
final String code;
|
||||||
|
|
||||||
public JavaSourceFromString(String name, String code) {
|
public JavaSourceFromString(String name, String code) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package me.ByteEdit.boxes;
|
package me.ByteEdit.boxes;
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -18,6 +16,7 @@ import javax.swing.KeyStroke;
|
|||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.AnnotationNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldInsnNode;
|
import org.objectweb.asm.tree.FieldInsnNode;
|
||||||
import org.objectweb.asm.tree.LdcInsnNode;
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
@@ -59,13 +58,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
contentPane.add(lblFind);
|
contentPane.add(lblFind);
|
||||||
txtString = new JTextField();
|
txtString = new JTextField();
|
||||||
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
||||||
txtString.registerKeyboardAction(new ActionListener() {
|
txtString.registerKeyboardAction(e -> find(), enter, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
}, enter, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
||||||
txtString.setBounds(91, 22, 149, 20);
|
txtString.setBounds(91, 22, 149, 20);
|
||||||
contentPane.add(txtString);
|
contentPane.add(txtString);
|
||||||
txtString.setColumns(10);
|
txtString.setColumns(10);
|
||||||
@@ -73,12 +66,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
chckbxCaseSensitive.setBounds(10, 199, 114, 23);
|
chckbxCaseSensitive.setBounds(10, 199, 114, 23);
|
||||||
contentPane.add(chckbxCaseSensitive);
|
contentPane.add(chckbxCaseSensitive);
|
||||||
JButton btnFind = new JButton("Find");
|
JButton btnFind = new JButton("Find");
|
||||||
btnFind.addActionListener(new ActionListener() {
|
btnFind.addActionListener(e -> find());
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnFind.setBounds(130, 199, 110, 23);
|
btnFind.setBounds(130, 199, 110, 23);
|
||||||
contentPane.add(btnFind);
|
contentPane.add(btnFind);
|
||||||
|
|
||||||
@@ -91,12 +79,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
contentPane.add(lblOwner);
|
contentPane.add(lblOwner);
|
||||||
|
|
||||||
txtOwner = new JTextField();
|
txtOwner = new JTextField();
|
||||||
txtOwner.addActionListener(new ActionListener() {
|
txtOwner.addActionListener(e -> find());
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtOwner.setColumns(10);
|
txtOwner.setColumns(10);
|
||||||
txtOwner.setBounds(91, 78, 149, 20);
|
txtOwner.setBounds(91, 78, 149, 20);
|
||||||
contentPane.add(txtOwner);
|
contentPane.add(txtOwner);
|
||||||
@@ -106,12 +89,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
contentPane.add(lblName);
|
contentPane.add(lblName);
|
||||||
|
|
||||||
txtName = new JTextField();
|
txtName = new JTextField();
|
||||||
txtName.addActionListener(new ActionListener() {
|
txtName.addActionListener(e -> find());
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtName.setColumns(10);
|
txtName.setColumns(10);
|
||||||
txtName.setBounds(91, 106, 149, 20);
|
txtName.setBounds(91, 106, 149, 20);
|
||||||
contentPane.add(txtName);
|
contentPane.add(txtName);
|
||||||
@@ -121,12 +99,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
contentPane.add(lblDesc);
|
contentPane.add(lblDesc);
|
||||||
|
|
||||||
txtDesc = new JTextField();
|
txtDesc = new JTextField();
|
||||||
txtDesc.addActionListener(new ActionListener() {
|
txtDesc.addActionListener(e -> find());
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtDesc.setColumns(10);
|
txtDesc.setColumns(10);
|
||||||
txtDesc.setBounds(91, 134, 149, 20);
|
txtDesc.setBounds(91, 134, 149, 20);
|
||||||
contentPane.add(txtDesc);
|
contentPane.add(txtDesc);
|
||||||
@@ -137,10 +110,11 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
openBox.model.clear();
|
openBox.model.clear();
|
||||||
Set<Info> set = new HashSet<>();
|
Set<Info> set = new HashSet<>();
|
||||||
if (!txtString.getText().isEmpty()) {
|
if (!txtString.getText().isEmpty()) {
|
||||||
String str = UnicodeUtils.unescape(txtString.getText());
|
String str = UnicodeUtils.unescape(null, txtString.getText(), true);
|
||||||
if (ignoreCase) {
|
if (ignoreCase) {
|
||||||
str = str.toLowerCase();
|
str = str.toLowerCase();
|
||||||
}
|
}
|
||||||
|
String fstr = str;
|
||||||
for (ClassNode cn : Main.classNodes.values()) {
|
for (ClassNode cn : Main.classNodes.values()) {
|
||||||
for (MethodNode mn : cn.methods) {
|
for (MethodNode mn : cn.methods) {
|
||||||
for (AbstractInsnNode insn : mn.instructions.toArray()) {
|
for (AbstractInsnNode insn : mn.instructions.toArray()) {
|
||||||
@@ -154,14 +128,23 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mn.visibleAnnotations != null) {
|
||||||
|
for (AnnotationNode anno : mn.visibleAnnotations) {
|
||||||
|
if (anno.values == null)
|
||||||
|
continue;
|
||||||
|
anno.values.stream().filter(o -> o instanceof String).map(o -> (String) o)
|
||||||
|
.map(s -> ignoreCase ? s.toLowerCase() : s).filter(s -> s.contains(fstr))
|
||||||
|
.forEach(s -> set.add(new Info(cn.name, mn.name, mn.desc, mn)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String owner = UnicodeUtils.unescape(txtOwner.getText());
|
String owner = UnicodeUtils.unescape(null, txtOwner.getText(), true);
|
||||||
boolean wildCardOwner = owner.isEmpty();
|
boolean wildCardOwner = owner.isEmpty();
|
||||||
String name = UnicodeUtils.unescape(txtName.getText());
|
String name = UnicodeUtils.unescape(null, txtName.getText(), true);
|
||||||
boolean wildCardName = name.isEmpty();
|
boolean wildCardName = name.isEmpty();
|
||||||
String desc = UnicodeUtils.unescape(txtDesc.getText());
|
String desc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
|
||||||
boolean wildCardDesc = desc.isEmpty();
|
boolean wildCardDesc = desc.isEmpty();
|
||||||
for (ClassNode cn : Main.classNodes.values()) {
|
for (ClassNode cn : Main.classNodes.values()) {
|
||||||
for (MethodNode mn : cn.methods) {
|
for (MethodNode mn : cn.methods) {
|
||||||
@@ -183,9 +166,7 @@ public class GlobalSearchBox extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Info s : set) {
|
set.forEach(openBox.model::addElement);
|
||||||
openBox.model.addElement(s);
|
|
||||||
}
|
|
||||||
openBox.setVisible(true);
|
openBox.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,10 +11,10 @@ import javax.swing.ListSelectionModel;
|
|||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.text.BadLocationException;
|
|
||||||
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
|
|
||||||
public class GlobalSearchOpenBox extends JFrame {
|
public class GlobalSearchOpenBox extends JFrame {
|
||||||
@@ -36,18 +36,10 @@ public class GlobalSearchOpenBox extends JFrame {
|
|||||||
model = new DefaultListModel<>();
|
model = new DefaultListModel<>();
|
||||||
JList<Info> list = new JList(model);
|
JList<Info> list = new JList(model);
|
||||||
list.addListSelectionListener(new ListSelectionListener() {
|
list.addListSelectionListener(new ListSelectionListener() {
|
||||||
|
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
Info val = list.getSelectedValue();
|
Info val = list.getSelectedValue();
|
||||||
if (val != null && !val.owner.equals(Main.currentNodeName)) {
|
if (!e.getValueIsAdjusting() && val != null && !val.owner.equals(Main.currentNodeName)) {
|
||||||
int lineFound = Main.selectFileWithSearch(val.nodePath, val.mn);
|
SingleThreadedExecutor.submit(() -> Main.selectFile(val.owner + ".class"));
|
||||||
if (lineFound != -1) {
|
|
||||||
try {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -65,14 +57,12 @@ public class GlobalSearchOpenBox extends JFrame {
|
|||||||
String name;
|
String name;
|
||||||
String desc;
|
String desc;
|
||||||
MethodNode mn;
|
MethodNode mn;
|
||||||
String nodePath;
|
|
||||||
|
|
||||||
public Info(String owner, String name, String desc, MethodNode mn) {
|
public Info(String owner, String name, String desc, MethodNode mn) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.desc = desc;
|
this.desc = desc;
|
||||||
this.mn = mn;
|
this.mn = mn;
|
||||||
nodePath = Main.getFullName(owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.objectweb.asm.tree.FieldNode;
|
|||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import me.ByteEdit.edit.Disassembler;
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
@@ -79,13 +79,13 @@ public class RenameBox extends JFrame {
|
|||||||
JOptionPane.showMessageDialog(null, "Desc not set!", "Error!", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "Desc not set!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ClassNode clazz = Main.classNodes.get(Main.getFullName(className));
|
ClassNode clazz = Main.classNodes.get(className);
|
||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "ClassNode not found!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String newName = UnicodeUtils.unescape(txtName.getText());
|
String newName = UnicodeUtils.unescape(null, txtName.getText(), true);
|
||||||
String newDesc = UnicodeUtils.unescape(txtDesc.getText());
|
String newDesc = UnicodeUtils.unescape(null, txtDesc.getText(), true);
|
||||||
if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) {
|
if (ClassUtil.isObjectClassMethod(newName, newDesc, true)) {
|
||||||
JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "Invalid name!", "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
@@ -94,7 +94,7 @@ public class RenameBox extends JFrame {
|
|||||||
if (newDesc.startsWith("(")) { // method
|
if (newDesc.startsWith("(")) { // method
|
||||||
ClassNode lastHit = clazz;
|
ClassNode lastHit = clazz;
|
||||||
while (clazz != null && clazz.superName != null) {
|
while (clazz != null && clazz.superName != null) {
|
||||||
ClassNode tmp = Main.classNodes.get(Main.getFullName(clazz.superName));
|
ClassNode tmp = Main.classNodes.get(clazz.superName);
|
||||||
if (tmp != null) {
|
if (tmp != null) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (MethodNode mn : clazz.methods) {
|
for (MethodNode mn : clazz.methods) {
|
||||||
@@ -127,7 +127,7 @@ public class RenameBox extends JFrame {
|
|||||||
extendsMyClass = true;
|
extendsMyClass = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ClassNode tmp = Main.classNodes.get(Main.getFullName(checkCN.superName));
|
ClassNode tmp = Main.classNodes.get(checkCN.superName);
|
||||||
if (tmp != null) {
|
if (tmp != null) {
|
||||||
checkCN = tmp;
|
checkCN = tmp;
|
||||||
} else {
|
} else {
|
||||||
@@ -210,27 +210,14 @@ public class RenameBox extends JFrame {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try { // refresh
|
|
||||||
ClassNode classNode = Main.classNodes.get(Main.currentNodeName);
|
SingleThreadedExecutor.submit(() -> {
|
||||||
int prev = Main.txtByteEditView.getCaretPosition();
|
// refresh
|
||||||
String dis = Disassembler.disassemble(classNode);
|
Main.decompileCurrentNode();
|
||||||
String substr = Main.currentNodeName.substring(0, Main.currentNodeName.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
|
||||||
if (key.contains("$")) {
|
|
||||||
String[] split = key.split("\\$");
|
|
||||||
if (split[0].equals(substr)) {
|
|
||||||
dis += "\n" + Disassembler.disassemble(Main.classNodes.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Main.txtByteEditView.setText(dis);
|
|
||||||
Main.txtByteEditView.setCaretPosition(prev);
|
|
||||||
} catch (Exception e2) {
|
|
||||||
e2.printStackTrace();
|
|
||||||
}
|
|
||||||
name = newName;
|
name = newName;
|
||||||
desc = newDesc;
|
desc = newDesc;
|
||||||
RenameBox.this.setVisible(false);
|
RenameBox.this.setVisible(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
btnRename.setBounds(345, 237, 89, 23);
|
btnRename.setBounds(345, 237, 89, 23);
|
||||||
|
|||||||
@@ -123,13 +123,16 @@ public class SearchBox extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void replace() {
|
public void replace() {
|
||||||
String txt = Main.txtByteEditView.getText();
|
if (!Main.decompiler.isEditable())
|
||||||
|
return;
|
||||||
int startPos = Main.txtByteEditView.getSelectionStart();
|
int startPos = Main.txtByteEditView.getSelectionStart();
|
||||||
Main.txtByteEditView.replaceSelection(txtReplace.getText());
|
Main.txtByteEditView.replaceSelection(txtReplace.getText());
|
||||||
Main.txtByteEditView.select(startPos, startPos + txtReplace.getText().length());
|
Main.txtByteEditView.select(startPos, startPos + txtReplace.getText().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replaceAll() {
|
public void replaceAll() {
|
||||||
|
if (!Main.decompiler.isEditable())
|
||||||
|
return;
|
||||||
String toFind = txtFind.getText();
|
String toFind = txtFind.getText();
|
||||||
String toReplace = txtReplace.getText();
|
String toReplace = txtReplace.getText();
|
||||||
String txt = Main.txtByteEditView.getText();
|
String txt = Main.txtByteEditView.getText();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import javax.swing.event.DocumentListener;
|
|||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.main.Main;
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
|
|
||||||
@@ -39,11 +40,11 @@ public class TypeOpenBox extends JFrame {
|
|||||||
DefaultListModel<String> model = new DefaultListModel<>();
|
DefaultListModel<String> model = new DefaultListModel<>();
|
||||||
JList<String> list = new JList(model);
|
JList<String> list = new JList(model);
|
||||||
list.addListSelectionListener(new ListSelectionListener() {
|
list.addListSelectionListener(new ListSelectionListener() {
|
||||||
|
@Override
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
String val = list.getSelectedValue();
|
String val = list.getSelectedValue();
|
||||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
if (!e.getValueIsAdjusting() && val != null && !val.equals(Main.currentNodeName)) {
|
||||||
Main.selectFile(val);
|
SingleThreadedExecutor.submit(() -> Main.selectFile(val + ".class"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -76,21 +77,19 @@ public class TypeOpenBox extends JFrame {
|
|||||||
if (txtSearch.getText().isEmpty()) {
|
if (txtSearch.getText().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String search = UnicodeUtils.unescape(txtSearch.getText()).toLowerCase();
|
String search = UnicodeUtils.unescape(null, txtSearch.getText(), true).toLowerCase();
|
||||||
if (search.contains("/")) {
|
if (search.contains("/")) {
|
||||||
for (String s : Main.classNodes.keySet()) {
|
for (String fullName : Main.classNodes.keySet()) {
|
||||||
String className = s.substring(0, s.length() - 6);
|
if (!fullName.contains("$") && fullName.toLowerCase().startsWith(search)) {
|
||||||
if (!className.contains("$") && className.toLowerCase().startsWith(search)) {
|
model.addElement(fullName);
|
||||||
model.addElement(s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (String s : Main.classNodes.keySet()) {
|
for (String fullName : Main.classNodes.keySet()) {
|
||||||
String[] split = s.split("/");
|
String[] split = fullName.split("/");
|
||||||
String className = split[split.length - 1];
|
String className = split[split.length - 1];
|
||||||
className = className.substring(0, className.length() - 6);
|
|
||||||
if (!className.contains("$") && className.toLowerCase().startsWith(search)) {
|
if (!className.contains("$") && className.toLowerCase().startsWith(search)) {
|
||||||
model.addElement(s);
|
model.addElement(fullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class UnicodeBox extends JFrame {
|
|||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
try {
|
try {
|
||||||
textArea.setText(UnicodeUtils.escape(textArea.getText()));
|
textArea.setText(UnicodeUtils.escape(null, textArea.getText(), true));
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
Main.showError(ex.getMessage());
|
Main.showError(ex.getMessage());
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ public class UnicodeBox extends JFrame {
|
|||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
try {
|
try {
|
||||||
textArea.setText(UnicodeUtils.unescape(textArea.getText()));
|
textArea.setText(UnicodeUtils.unescape(null, textArea.getText(), true));
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
Main.showError(ex.getMessage());
|
Main.showError(ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.benf.cfr.reader.PluginRunner;
|
||||||
|
import org.benf.cfr.reader.api.ClassFileSource;
|
||||||
|
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
|
||||||
|
import org.benf.cfr.reader.state.ClassFileSourceImpl;
|
||||||
|
import org.benf.cfr.reader.util.MiscConstants.Version;
|
||||||
|
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public class CFRDecompiler implements IDecompiler {
|
||||||
|
|
||||||
|
public static final HashMap<String, String> options = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
options.put("aexagg", "false");
|
||||||
|
options.put("allowcorrecting", "true");
|
||||||
|
options.put("arrayiter", "true");
|
||||||
|
options.put("caseinsensitivefs", "false");
|
||||||
|
options.put("clobber", "false");
|
||||||
|
options.put("collectioniter", "true");
|
||||||
|
options.put("commentmonitors", "false");
|
||||||
|
options.put("decodeenumswitch", "true");
|
||||||
|
options.put("decodefinally", "true");
|
||||||
|
options.put("decodelambdas", "true");
|
||||||
|
options.put("decodestringswitch", "true");
|
||||||
|
options.put("dumpclasspath", "false");
|
||||||
|
options.put("eclipse", "true");
|
||||||
|
options.put("elidescala", "false");
|
||||||
|
options.put("forcecondpropagate", "false");
|
||||||
|
options.put("forceexceptionprune", "false");
|
||||||
|
options.put("forcereturningifs", "false");
|
||||||
|
options.put("forcetopsort", "false");
|
||||||
|
options.put("forcetopsortaggress", "false");
|
||||||
|
options.put("forloopaggcapture", "false");
|
||||||
|
options.put("hidebridgemethods", "false");
|
||||||
|
options.put("hidelangimports", "true");
|
||||||
|
options.put("hidelongstrings", "false");
|
||||||
|
options.put("hideutf", "true");
|
||||||
|
options.put("innerclasses", "true");
|
||||||
|
options.put("j14classobj", "false");
|
||||||
|
options.put("labelledblocks", "true");
|
||||||
|
options.put("lenient", "false");
|
||||||
|
options.put("liftconstructorinit", "true");
|
||||||
|
options.put("override", "true");
|
||||||
|
options.put("pullcodecase", "false");
|
||||||
|
options.put("recover", "true");
|
||||||
|
options.put("recovertypeclash", "false");
|
||||||
|
options.put("recovertypehints", "false");
|
||||||
|
options.put("relinkconststring", "true");
|
||||||
|
options.put("removebadgenerics", "true");
|
||||||
|
options.put("removeboilerplate", "true");
|
||||||
|
options.put("removedeadmethods", "true");
|
||||||
|
options.put("removeinnerclasssynthetics", "true");
|
||||||
|
options.put("rename", "false");
|
||||||
|
options.put("renamedupmembers", "false");
|
||||||
|
options.put("renameenumidents", "false");
|
||||||
|
options.put("renameillegalidents", "false");
|
||||||
|
options.put("showinferrable", "false");
|
||||||
|
options.put("silent", "false");
|
||||||
|
options.put("stringbuffer", "false");
|
||||||
|
options.put("stringbuilder", "true");
|
||||||
|
options.put("sugarasserts", "true");
|
||||||
|
options.put("sugarboxing", "true");
|
||||||
|
options.put("sugarenums", "true");
|
||||||
|
options.put("tidymonitors", "true");
|
||||||
|
options.put("usenametable", "true");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field f = Version.class.getDeclaredField("version");
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(null, "ByteEdit");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn, Map<String, ClassNode> classNodes) {
|
||||||
|
return doDecompilation(cn, IDecompiler.getBytes(cn), classNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String doDecompilation(ClassNode cn, byte[] b, Map<String, ClassNode> classNodes) {
|
||||||
|
try {
|
||||||
|
HashMap<String, String> ops = options;
|
||||||
|
ClassFileSource cfs = new ClassFileSourceImpl(new OptionsImpl(Collections.EMPTY_MAP)) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAnalysisRelativePathDetail(String a, String b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPossiblyRenamedPath(String path) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<byte[], String> getClassFileContent(String path) throws IOException {
|
||||||
|
String name = path.substring(0, path.length() - 6);
|
||||||
|
if (name.equals(cn.name))
|
||||||
|
return Pair.make(b, name);
|
||||||
|
// try loading other classes from jar
|
||||||
|
ClassNode node;
|
||||||
|
synchronized (classNodes) {
|
||||||
|
node = classNodes.get(name);
|
||||||
|
}
|
||||||
|
if (node != null)
|
||||||
|
return Pair.make(IDecompiler.getBytes(node), name);
|
||||||
|
return super.getClassFileContent(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> addJar(String arg0) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
String decompilation = new PluginRunner(ops, cfs).getDecompilationFor(cn.name);
|
||||||
|
System.gc(); // cfr has a performance bug
|
||||||
|
return decompilation;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.Disassembler;
|
||||||
|
|
||||||
|
public enum EnumDecompiler {
|
||||||
|
BYTEEDIT("ByteEdit", new Disassembler(), false), PROCYON("Procyon", new ProcyonDecompiler()),
|
||||||
|
JD_GUI("JD-GUI", new JDDecompiler()), CFR("CFR", new CFRDecompiler());
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final IDecompiler decompiler;
|
||||||
|
private final String syntaxStyle;
|
||||||
|
private final boolean isEditable;
|
||||||
|
|
||||||
|
private EnumDecompiler(String name, IDecompiler decompiler) {
|
||||||
|
this(name, decompiler, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumDecompiler(String name, IDecompiler decompiler, boolean isDecompiler) {
|
||||||
|
this.name = name;
|
||||||
|
this.decompiler = decompiler;
|
||||||
|
this.syntaxStyle = isDecompiler ? SyntaxConstants.SYNTAX_STYLE_JAVA
|
||||||
|
: SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE;
|
||||||
|
this.isEditable = !isDecompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDecompiler getDecompiler() {
|
||||||
|
return decompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSyntaxStyle() {
|
||||||
|
return syntaxStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEditable() {
|
||||||
|
return isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public interface IDecompiler {
|
||||||
|
|
||||||
|
String decompile(ClassNode cn, Map<String, ClassNode> classNodes);
|
||||||
|
|
||||||
|
static byte[] getBytes(ClassNode cn) {
|
||||||
|
ClassWriter classWriter = new ClassWriter(0);
|
||||||
|
cn.accept(classWriter);
|
||||||
|
return classWriter.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jd.core.v1.ClassFileToJavaSourceDecompiler;
|
||||||
|
import org.jd.core.v1.api.loader.Loader;
|
||||||
|
import org.jd.core.v1.api.loader.LoaderException;
|
||||||
|
import org.jd.core.v1.api.printer.Printer;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public class JDDecompiler implements Loader, Printer, IDecompiler {
|
||||||
|
|
||||||
|
protected static final String TAB = " ";
|
||||||
|
protected static final String NEWLINE = "\n";
|
||||||
|
|
||||||
|
protected int indentationCount = 0;
|
||||||
|
protected StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
private Map<String, ClassNode> classNodes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn, Map<String, ClassNode> classNodes) {
|
||||||
|
this.classNodes = classNodes;
|
||||||
|
ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler();
|
||||||
|
try {
|
||||||
|
decompiler.decompile(this, this, cn.name);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
String str = e.getClass().getName() + " - " + e.getMessage() + System.lineSeparator();
|
||||||
|
for (int i = 0; i < e.getStackTrace().length; i++) {
|
||||||
|
str += e.getStackTrace()[i].toString() + System.lineSeparator();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
String decomp = toString();
|
||||||
|
indentationCount = 0;
|
||||||
|
sb = new StringBuilder();
|
||||||
|
return decomp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canLoad(String internalName) {
|
||||||
|
synchronized (classNodes) {
|
||||||
|
return classNodes.containsKey(internalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] load(String internalName) throws LoaderException {
|
||||||
|
ClassNode node;
|
||||||
|
synchronized (classNodes) {
|
||||||
|
node = classNodes.get(internalName);
|
||||||
|
}
|
||||||
|
if (node != null)
|
||||||
|
return IDecompiler.getBytes(node);
|
||||||
|
throw new LoaderException("Failed to load '" + internalName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(int maxLineNumber, int majorVersion, int minorVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printText(String text) {
|
||||||
|
sb.append(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printNumericConstant(String constant) {
|
||||||
|
sb.append(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printStringConstant(String constant, String ownerInternalName) {
|
||||||
|
sb.append(constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printKeyword(String keyword) {
|
||||||
|
sb.append(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
|
||||||
|
sb.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void printReference(int type, String internalTypeName, String name, String descriptor,
|
||||||
|
String ownerInternalName) {
|
||||||
|
sb.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void indent() {
|
||||||
|
this.indentationCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unindent() {
|
||||||
|
this.indentationCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startLine(int lineNumber) {
|
||||||
|
for (int i = 0; i < indentationCount; i++)
|
||||||
|
sb.append(TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endLine() {
|
||||||
|
sb.append(NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extraLine(int count) {
|
||||||
|
while (count-- > 0)
|
||||||
|
sb.append(NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMarker(int type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMarker(int type) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
import com.strobel.assembler.InputTypeLoader;
|
||||||
|
import com.strobel.assembler.metadata.Buffer;
|
||||||
|
import com.strobel.assembler.metadata.ITypeLoader;
|
||||||
|
import com.strobel.assembler.metadata.MetadataSystem;
|
||||||
|
import com.strobel.assembler.metadata.TypeDefinition;
|
||||||
|
import com.strobel.assembler.metadata.TypeReference;
|
||||||
|
import com.strobel.decompiler.DecompilationOptions;
|
||||||
|
import com.strobel.decompiler.DecompilerSettings;
|
||||||
|
import com.strobel.decompiler.PlainTextOutput;
|
||||||
|
|
||||||
|
public class ProcyonDecompiler implements IDecompiler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String decompile(ClassNode cn, Map<String, ClassNode> classNodes) {
|
||||||
|
return doDecompilation(cn, IDecompiler.getBytes(cn), classNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String doDecompilation(ClassNode cn, byte[] b, Map<String, ClassNode> classNodes) {
|
||||||
|
try {
|
||||||
|
// TODO decompile method only
|
||||||
|
DecompilerSettings settings = new DecompilerSettings();
|
||||||
|
try {
|
||||||
|
for (Field f : settings.getClass().getDeclaredFields()) {
|
||||||
|
if (f.getType() == boolean.class) {
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.setBoolean(settings, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
settings.setShowSyntheticMembers(true);
|
||||||
|
MetadataSystem metadataSystem = new MetadataSystem(new ITypeLoader() {
|
||||||
|
private InputTypeLoader backLoader = new InputTypeLoader();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLoadType(String s, Buffer buffer) {
|
||||||
|
if (s.equals(cn.name)) {
|
||||||
|
buffer.putByteArray(b, 0, b.length);
|
||||||
|
buffer.position(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ClassNode node;
|
||||||
|
synchronized (classNodes) {
|
||||||
|
node = classNodes.get(s);
|
||||||
|
}
|
||||||
|
if (node != null) {
|
||||||
|
byte[] data = IDecompiler.getBytes(node);
|
||||||
|
buffer.putByteArray(data, 0, data.length);
|
||||||
|
buffer.position(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return backLoader.tryLoadType(s, buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
TypeReference type = metadataSystem.lookupType(cn.name);
|
||||||
|
DecompilationOptions decompilationOptions = new DecompilationOptions();
|
||||||
|
decompilationOptions.setSettings(DecompilerSettings.javaDefaults());
|
||||||
|
decompilationOptions.setFullDecompilation(true);
|
||||||
|
TypeDefinition resolvedType = null;
|
||||||
|
if (type == null || ((resolvedType = type.resolve()) == null)) {
|
||||||
|
return "error";
|
||||||
|
}
|
||||||
|
StringWriter stringwriter = new StringWriter();
|
||||||
|
settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions);
|
||||||
|
String decompiledSource = stringwriter.toString();
|
||||||
|
return decompiledSource;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
e.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package me.ByteEdit.decompiler;
|
||||||
|
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
public class SingleThreadedExecutor {
|
||||||
|
|
||||||
|
// We don't need to run every Runnable,
|
||||||
|
// we only care about the last submitted Runnable.
|
||||||
|
private static final Object lock = new Object();
|
||||||
|
private static Runnable runnable;
|
||||||
|
private static final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
private static final Thread thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
Runnable r = null;
|
||||||
|
synchronized (lock) {
|
||||||
|
while (runnable == null)
|
||||||
|
lock.wait();
|
||||||
|
r = runnable;
|
||||||
|
runnable = null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}, "SingleThreadedExecutor");
|
||||||
|
|
||||||
|
static {
|
||||||
|
thread.setPriority(Thread.MAX_PRIORITY);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void submit(Runnable r) {
|
||||||
|
synchronized (lock) {
|
||||||
|
runnable = r;
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+196
-217
@@ -1,5 +1,6 @@
|
|||||||
package me.ByteEdit.edit;
|
package me.ByteEdit.edit;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -9,6 +10,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.swing.text.BadLocationException;
|
import javax.swing.text.BadLocationException;
|
||||||
|
|
||||||
@@ -51,30 +53,48 @@ import me.ByteEdit.utils.UnicodeUtils;
|
|||||||
|
|
||||||
public class Assembler {
|
public class Assembler {
|
||||||
|
|
||||||
|
public static final Pattern SPACE = Pattern.compile(" ");
|
||||||
|
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
|
||||||
|
|
||||||
public static ClassNode assemble(String input) {
|
public static ClassNode assemble(String input) {
|
||||||
Main.txtByteEditView.removeAllLineHighlights();
|
Main.txtByteEditView.removeAllLineHighlights();
|
||||||
CustomBufferedReader read = null;
|
CustomBufferedReader read = null;
|
||||||
try {
|
try {
|
||||||
ClassNode clazz = new ClassNode();
|
ClassNode clazz = new ClassNode();
|
||||||
|
HugeStringsRev hsr = new HugeStringsRev();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new StringReader(input))) {
|
||||||
|
String s;
|
||||||
|
while (!(s = reader.readLine()).startsWith("// #SourceFile: ")) {
|
||||||
|
}
|
||||||
|
while (!(s = reader.readLine()).equals("// #Fields")) {
|
||||||
|
if (s.startsWith("#")) {
|
||||||
|
String[] split = SPACE.split(s, 2);
|
||||||
|
hsr.add(Integer.parseInt(split[0].substring(1, split[0].length() - 1)),
|
||||||
|
UnicodeUtils.unescape(null, split[1], true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
read = new CustomBufferedReader(new StringReader(input));
|
read = new CustomBufferedReader(new StringReader(input));
|
||||||
String s;
|
String s;
|
||||||
while (!(s = read.readLine()).startsWith("// #Class v:")) {
|
while (!(s = read.readLine()).startsWith("// #Class v:")) {
|
||||||
if (clazz.visibleAnnotations == null) {
|
if (clazz.visibleAnnotations == null) {
|
||||||
clazz.visibleAnnotations = new ArrayList<>();
|
clazz.visibleAnnotations = new ArrayList<>();
|
||||||
}
|
}
|
||||||
clazz.visibleAnnotations.add(parseAnnotation(s));
|
clazz.visibleAnnotations.add(parseAnnotation(hsr, s));
|
||||||
}
|
}
|
||||||
clazz.version = Integer.parseInt(s.substring(12));
|
clazz.version = Integer.parseInt(s.substring(12));
|
||||||
while ((s = read.readLine()).startsWith("// ")) {
|
while ((s = read.readLine()).startsWith("// ")) {
|
||||||
if (s.startsWith("// #Signature: ")) {
|
if (s.startsWith("// #Signature: ")) {
|
||||||
clazz.signature = s.substring(15).equals("null") ? null : UnicodeUtils.unescape(s.substring(15));
|
clazz.signature = s.substring(15).equals("null") ? null
|
||||||
|
: UnicodeUtils.unescape(hsr, s.substring(15));
|
||||||
} else if (s.startsWith("// #OuterClass: ")) {
|
} else if (s.startsWith("// #OuterClass: ")) {
|
||||||
clazz.outerClass = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(s.substring(16));
|
clazz.outerClass = s.substring(16).equals("null") ? null
|
||||||
|
: UnicodeUtils.unescape(hsr, s.substring(16));
|
||||||
} else if (s.startsWith("// #OuterMethod: ")) {
|
} else if (s.startsWith("// #OuterMethod: ")) {
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
if (split.length > 3) {
|
if (split.length > 3) {
|
||||||
clazz.outerMethod = UnicodeUtils.unescape(split[2]);
|
clazz.outerMethod = UnicodeUtils.unescape(hsr, split[2]);
|
||||||
clazz.outerMethodDesc = UnicodeUtils.unescape(split[3]);
|
clazz.outerMethodDesc = UnicodeUtils.unescape(hsr, split[3]);
|
||||||
}
|
}
|
||||||
} else if (s.equals("// #InnerClasses:")) {
|
} else if (s.equals("// #InnerClasses:")) {
|
||||||
clazz.innerClasses = new ArrayList<>();
|
clazz.innerClasses = new ArrayList<>();
|
||||||
@@ -137,9 +157,9 @@ public class Assembler {
|
|||||||
access ^= ClassUtil.ACC_MANDATED;
|
access ^= ClassUtil.ACC_MANDATED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clazz.innerClasses.add(new InnerClassNode(UnicodeUtils.unescape(split[1]),
|
clazz.innerClasses.add(new InnerClassNode(UnicodeUtils.unescape(hsr, split[1]),
|
||||||
split[2].equals("null") ? null : UnicodeUtils.unescape(split[2]),
|
split[2].equals("null") ? null : UnicodeUtils.unescape(hsr, split[2]),
|
||||||
split[3].equals("null") ? null : UnicodeUtils.unescape(split[3]), access));
|
split[3].equals("null") ? null : UnicodeUtils.unescape(hsr, split[3]), access));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -148,14 +168,14 @@ public class Assembler {
|
|||||||
String interfaces = s.substring(s.lastIndexOf(" implements ") + 12);
|
String interfaces = s.substring(s.lastIndexOf(" implements ") + 12);
|
||||||
clazz.interfaces = new ArrayList<>();
|
clazz.interfaces = new ArrayList<>();
|
||||||
for (String interf : interfaces.split(", ")) {
|
for (String interf : interfaces.split(", ")) {
|
||||||
clazz.interfaces.add(UnicodeUtils.unescape(interf));
|
clazz.interfaces.add(UnicodeUtils.unescape(hsr, interf));
|
||||||
}
|
}
|
||||||
s = s.substring(0, s.lastIndexOf(" implements "));
|
s = s.substring(0, s.lastIndexOf(" implements "));
|
||||||
}
|
}
|
||||||
clazz.superName = UnicodeUtils.unescape(s.substring(s.lastIndexOf(" extends ") + 9));
|
clazz.superName = UnicodeUtils.unescape(hsr, s.substring(s.lastIndexOf(" extends ") + 9));
|
||||||
s = s.substring(0, s.lastIndexOf(" extends "));
|
s = s.substring(0, s.lastIndexOf(" extends "));
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
clazz.name = UnicodeUtils.unescape(split[split.length - 1]);
|
clazz.name = UnicodeUtils.unescape(hsr, split[split.length - 1]);
|
||||||
clazz.access = ClassUtil.ACC_SUPER;
|
clazz.access = ClassUtil.ACC_SUPER;
|
||||||
switch (split[split.length - 2]) {
|
switch (split[split.length - 2]) {
|
||||||
case "class":
|
case "class":
|
||||||
@@ -192,7 +212,7 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = read.readLine();
|
s = read.readLine();
|
||||||
clazz.sourceFile = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(s.substring(16));
|
clazz.sourceFile = s.substring(16).equals("null") ? null : UnicodeUtils.unescape(hsr, s.substring(16));
|
||||||
while (!(s = read.readLine()).equals("// #Fields")) {
|
while (!(s = read.readLine()).equals("// #Fields")) {
|
||||||
}
|
}
|
||||||
clazz.fields = new ArrayList<>();
|
clazz.fields = new ArrayList<>();
|
||||||
@@ -207,7 +227,7 @@ public class Assembler {
|
|||||||
annotationsForNext.add(s);
|
annotationsForNext.add(s);
|
||||||
} else {
|
} else {
|
||||||
if (s.startsWith("// #Signature: ")) {
|
if (s.startsWith("// #Signature: ")) {
|
||||||
signature = UnicodeUtils.unescape(s.substring(15));
|
signature = UnicodeUtils.unescape(hsr, s.substring(15));
|
||||||
} else {
|
} else {
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
boolean hasValue = false;
|
boolean hasValue = false;
|
||||||
@@ -218,9 +238,9 @@ public class Assembler {
|
|||||||
if (hasValue) {
|
if (hasValue) {
|
||||||
split = s.substring(0, s.indexOf(" = ")).split(" ");
|
split = s.substring(0, s.indexOf(" = ")).split(" ");
|
||||||
}
|
}
|
||||||
String name = UnicodeUtils.unescape(split[split.length - 1]);
|
String name = UnicodeUtils.unescape(hsr, split[split.length - 1]);
|
||||||
String desc = UnicodeUtils.unescape(split[split.length - 2]);
|
String desc = UnicodeUtils.unescape(hsr, split[split.length - 2]);
|
||||||
value = getValue((String) value, desc);
|
value = getValue(hsr, (String) value, desc);
|
||||||
int access = 0;
|
int access = 0;
|
||||||
if (split.length > 2) {
|
if (split.length > 2) {
|
||||||
String cons = consolidateStrings(split, 0, split.length - 2);
|
String cons = consolidateStrings(split, 0, split.length - 2);
|
||||||
@@ -283,7 +303,7 @@ public class Assembler {
|
|||||||
node.visibleAnnotations = new ArrayList<>();
|
node.visibleAnnotations = new ArrayList<>();
|
||||||
}
|
}
|
||||||
for (String anno : annotationsForNext) {
|
for (String anno : annotationsForNext) {
|
||||||
node.visibleAnnotations.add(parseAnnotation(anno));
|
node.visibleAnnotations.add(parseAnnotation(hsr, anno));
|
||||||
}
|
}
|
||||||
annotationsForNext.clear();
|
annotationsForNext.clear();
|
||||||
}
|
}
|
||||||
@@ -319,7 +339,9 @@ public class Assembler {
|
|||||||
tryCatchBlocksToParse.clear();
|
tryCatchBlocksToParse.clear();
|
||||||
stage = 0;
|
stage = 0;
|
||||||
} else if (s.startsWith("// #Signature: ")) {
|
} else if (s.startsWith("// #Signature: ")) {
|
||||||
node.signature = UnicodeUtils.unescape(s.substring(15));
|
if (node == null)
|
||||||
|
throw new IllegalStateException("node is null");
|
||||||
|
node.signature = UnicodeUtils.unescape(hsr, s.substring(15));
|
||||||
} else if (s.equals("// #TryCatch:")) {
|
} else if (s.equals("// #TryCatch:")) {
|
||||||
stage = 1;
|
stage = 1;
|
||||||
} else if (s.equals("// #LocalVars:")) {
|
} else if (s.equals("// #LocalVars:")) {
|
||||||
@@ -332,12 +354,14 @@ public class Assembler {
|
|||||||
localVarsToParse.add(s);
|
localVarsToParse.add(s);
|
||||||
}
|
}
|
||||||
} else if (s.equals("}")) {
|
} else if (s.equals("}")) {
|
||||||
|
if (node == null)
|
||||||
|
throw new IllegalStateException("node is null");
|
||||||
if (!annotationsForNext.isEmpty()) {
|
if (!annotationsForNext.isEmpty()) {
|
||||||
if (node.visibleAnnotations == null) {
|
if (node.visibleAnnotations == null) {
|
||||||
node.visibleAnnotations = new ArrayList<>();
|
node.visibleAnnotations = new ArrayList<>();
|
||||||
}
|
}
|
||||||
for (String anno : annotationsForNext) {
|
for (String anno : annotationsForNext) {
|
||||||
node.visibleAnnotations.add(parseAnnotation(anno));
|
node.visibleAnnotations.add(parseAnnotation(hsr, anno));
|
||||||
}
|
}
|
||||||
annotationsForNext.clear();
|
annotationsForNext.clear();
|
||||||
}
|
}
|
||||||
@@ -345,7 +369,7 @@ public class Assembler {
|
|||||||
String[] sp = st.split(":");
|
String[] sp = st.split(":");
|
||||||
int start = Integer.parseInt(sp[3].substring(0, sp[3].length() - 2));
|
int start = Integer.parseInt(sp[3].substring(0, sp[3].length() - 2));
|
||||||
int end = Integer.parseInt(sp[4].substring(0, sp[4].length() - 4));
|
int end = Integer.parseInt(sp[4].substring(0, sp[4].length() - 4));
|
||||||
String signat = sp[5].equals("null") ? null : UnicodeUtils.unescape(sp[5]);
|
String signat = sp[5].equals("null") ? null : UnicodeUtils.unescape(hsr, sp[5]);
|
||||||
LabelNode _start = null;
|
LabelNode _start = null;
|
||||||
LabelNode _end = null;
|
LabelNode _end = null;
|
||||||
for (Entry<LabelNode, Integer> entry : methodLabelMap.entrySet()) {
|
for (Entry<LabelNode, Integer> entry : methodLabelMap.entrySet()) {
|
||||||
@@ -356,9 +380,9 @@ public class Assembler {
|
|||||||
_end = entry.getKey();
|
_end = entry.getKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.localVariables.add(new LocalVariableNode(UnicodeUtils.unescape(sp[0]),
|
node.localVariables.add(new LocalVariableNode(UnicodeUtils.unescape(hsr, sp[0]),
|
||||||
UnicodeUtils.unescape(sp[1].substring(1, sp[1].length() - 2)), signat, _start, _end,
|
UnicodeUtils.unescape(hsr, sp[1].substring(1, sp[1].length() - 2)), signat, _start,
|
||||||
Integer.parseInt(sp[2].substring(0, sp[2].length() - 2))));
|
_end, Integer.parseInt(sp[2].substring(0, sp[2].length() - 2))));
|
||||||
}
|
}
|
||||||
for (String st : tryCatchBlocksToParse) {
|
for (String st : tryCatchBlocksToParse) {
|
||||||
String[] sp = st.split(" ");
|
String[] sp = st.split(" ");
|
||||||
@@ -380,21 +404,23 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.tryCatchBlocks.add(new TryCatchBlockNode(_start, _end, _handler,
|
node.tryCatchBlocks.add(new TryCatchBlockNode(_start, _end, _handler,
|
||||||
sp[0].equals("null") ? null : UnicodeUtils.unescape(sp[0])));
|
sp[0].equals("null") ? null : UnicodeUtils.unescape(hsr, sp[0])));
|
||||||
}
|
}
|
||||||
clazz.methods.add(node);
|
clazz.methods.add(node);
|
||||||
} else if (!s.startsWith("\t")) {
|
} else if (!s.startsWith("\t")) {
|
||||||
|
if (node == null)
|
||||||
|
throw new IllegalStateException("node is null");
|
||||||
s = s.substring(0, s.length() - 2);
|
s = s.substring(0, s.length() - 2);
|
||||||
if (s.contains(" throws ")) {
|
if (s.contains(" throws ")) {
|
||||||
String exceptions = s.substring(s.lastIndexOf(" throws ") + 8);
|
String exceptions = s.substring(s.lastIndexOf(" throws ") + 8);
|
||||||
for (String excp : exceptions.split(", ")) {
|
for (String excp : exceptions.split(", ")) {
|
||||||
node.exceptions.add(UnicodeUtils.unescape(excp));
|
node.exceptions.add(UnicodeUtils.unescape(hsr, excp));
|
||||||
}
|
}
|
||||||
s = s.substring(0, s.lastIndexOf(" throws "));
|
s = s.substring(0, s.lastIndexOf(" throws "));
|
||||||
}
|
}
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
node.desc = UnicodeUtils.unescape(split[split.length - 1]);
|
node.desc = UnicodeUtils.unescape(hsr, split[split.length - 1]);
|
||||||
node.name = UnicodeUtils.unescape(split[split.length - 2]);
|
node.name = UnicodeUtils.unescape(hsr, split[split.length - 2]);
|
||||||
int access = 0;
|
int access = 0;
|
||||||
if (split.length > 2) {
|
if (split.length > 2) {
|
||||||
String cons = consolidateStrings(split, 0, split.length - 2);
|
String cons = consolidateStrings(split, 0, split.length - 2);
|
||||||
@@ -457,8 +483,10 @@ public class Assembler {
|
|||||||
s = s.substring(1);
|
s = s.substring(1);
|
||||||
if (!temp.isEmpty()) {
|
if (!temp.isEmpty()) {
|
||||||
if (s.equals("]")) {
|
if (s.equals("]")) {
|
||||||
|
if (node == null)
|
||||||
|
throw new IllegalStateException("node is null");
|
||||||
temp += s;
|
temp += s;
|
||||||
node.instructions.add(getNode(temp, methodLabelMap));
|
node.instructions.add(getNode(hsr, temp, methodLabelMap));
|
||||||
temp = "";
|
temp = "";
|
||||||
} else {
|
} else {
|
||||||
temp += s + "\n";
|
temp += s + "\n";
|
||||||
@@ -467,7 +495,9 @@ public class Assembler {
|
|||||||
if (s.endsWith("[")) {
|
if (s.endsWith("[")) {
|
||||||
temp += s + "\n";
|
temp += s + "\n";
|
||||||
} else {
|
} else {
|
||||||
node.instructions.add(getNode(s, methodLabelMap));
|
if (node == null)
|
||||||
|
throw new IllegalStateException("node is null");
|
||||||
|
node.instructions.add(getNode(hsr, s, methodLabelMap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -475,17 +505,20 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
return clazz;
|
return clazz;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
if (read != null) {
|
||||||
System.err.println("Error at line: " + read.currentLine);
|
System.err.println("Error at line: " + read.currentLine);
|
||||||
try {
|
try {
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
|
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(read.currentLine));
|
||||||
} catch (BadLocationException e1) {
|
} catch (BadLocationException e1) {
|
||||||
System.err.println("Can't show line!");
|
System.err.println("Can't show line!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Main.showError(e.getMessage());
|
Main.showError(e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
|
if (read != null)
|
||||||
read.close();
|
read.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
@@ -496,31 +529,37 @@ public class Assembler {
|
|||||||
ArrayList<String> ret = new ArrayList<>();
|
ArrayList<String> ret = new ArrayList<>();
|
||||||
String[] split = s.split(", ");
|
String[] split = s.split(", ");
|
||||||
String building = null;
|
String building = null;
|
||||||
|
boolean inString = false;
|
||||||
|
|
||||||
for (int i = 0; i < split.length; i++) {
|
for (int i = 0; i < split.length; i++) {
|
||||||
if (split[i].startsWith("(")) {
|
if (split[i].startsWith("(")) {
|
||||||
ret.add(split[i]);
|
ret.add(split[i]);
|
||||||
} else if (split[i].endsWith("\"")) {
|
} else if (split[i].startsWith("\"") && split[i].endsWith("\"")) {
|
||||||
|
ret.add(split[i]);
|
||||||
|
} else if (split[i].endsWith("\"") && inString) {
|
||||||
if (building == null)
|
if (building == null)
|
||||||
ret.add(split[i]);
|
ret.add(split[i]);
|
||||||
else
|
else
|
||||||
ret.add(building + ", " + split[i]);
|
ret.add(building + ", " + split[i]);
|
||||||
building = null;
|
building = null;
|
||||||
} else {
|
} else if (inString || split[i].startsWith("\"")) {
|
||||||
|
inString = true;
|
||||||
if (building == null)
|
if (building == null)
|
||||||
building = split[i];
|
building = split[i];
|
||||||
else
|
else
|
||||||
building += ", " + split[i];
|
building += ", " + split[i];
|
||||||
|
} else {
|
||||||
|
ret.add(split[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret.toArray(new String[0]);
|
return ret.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AnnotationNode parseAnnotation(String s) {
|
private static AnnotationNode parseAnnotation(HugeStringsRev hsr, String s) {
|
||||||
s = s.substring(1);
|
s = s.substring(1);
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
AnnotationNode node = new AnnotationNode(UnicodeUtils.unescape(split[0]));
|
AnnotationNode node = new AnnotationNode(UnicodeUtils.unescape(hsr, split[0]));
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
if (node.values == null) {
|
if (node.values == null) {
|
||||||
node.values = new ArrayList<>();
|
node.values = new ArrayList<>();
|
||||||
@@ -538,7 +577,7 @@ public class Assembler {
|
|||||||
String split3[] = splitWithStrings(value.substring(2, value.length() - 2));
|
String split3[] = splitWithStrings(value.substring(2, value.length() - 2));
|
||||||
List<Object> list = new ArrayList<>();
|
List<Object> list = new ArrayList<>();
|
||||||
for (String rofl : split3) {
|
for (String rofl : split3) {
|
||||||
rofl = UnicodeUtils.unescape(rofl);
|
rofl = UnicodeUtils.unescape(hsr, rofl);
|
||||||
if (rofl.startsWith("\"")) {
|
if (rofl.startsWith("\"")) {
|
||||||
int index = rofl.lastIndexOf("\"");
|
int index = rofl.lastIndexOf("\"");
|
||||||
list.add(rofl.substring(1, index));
|
list.add(rofl.substring(1, index));
|
||||||
@@ -552,7 +591,7 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
node.values.add(list);
|
node.values.add(list);
|
||||||
} else {
|
} else {
|
||||||
value = UnicodeUtils.unescape(value);
|
value = UnicodeUtils.unescape(hsr, value);
|
||||||
if (value.startsWith("\"")) {
|
if (value.startsWith("\"")) {
|
||||||
int index = value.lastIndexOf("\"");
|
int index = value.lastIndexOf("\"");
|
||||||
node.values.add(value.substring(1, index));
|
node.values.add(value.substring(1, index));
|
||||||
@@ -574,29 +613,31 @@ public class Assembler {
|
|||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String ret = args[start];
|
StringBuilder sb = new StringBuilder(args[start]);
|
||||||
if (args.length > start + 1) {
|
if (args.length > start + 1) {
|
||||||
for (int i = start + 1; i < args.length; i++) {
|
for (int i = start + 1; i < args.length; i++) {
|
||||||
ret = ret + " " + args[i];
|
sb.append(' ');
|
||||||
|
sb.append(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String consolidateStrings(String[] args, int start, int end) {
|
private static String consolidateStrings(String[] args, int start, int end) {
|
||||||
if (end == 0) {
|
if (end == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String ret = args[start];
|
StringBuilder sb = new StringBuilder(args[start]);
|
||||||
if (end > start + 1) {
|
if (end > start + 1) {
|
||||||
for (int i = start + 1; i < end; i++) {
|
for (int i = start + 1; i < end; i++) {
|
||||||
ret = ret + " " + args[i];
|
sb.append(' ');
|
||||||
|
sb.append(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object getValue(String s, String to) {
|
private static Object getValue(HugeStringsRev hsr, String s, String to) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -618,14 +659,15 @@ public class Assembler {
|
|||||||
case "S":
|
case "S":
|
||||||
return Short.parseShort(s);
|
return Short.parseShort(s);
|
||||||
case "Ljava/lang/String;":
|
case "Ljava/lang/String;":
|
||||||
return UnicodeUtils.unescape(s.substring(1, s.length() - 1));
|
return UnicodeUtils.unescape(hsr, s.substring(1, s.length() - 1));
|
||||||
default: {
|
default: {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractInsnNode getNode(String s, HashMap<LabelNode, Integer> labels) throws Exception {
|
private static AbstractInsnNode getNode(HugeStringsRev hsr, String s, HashMap<LabelNode, Integer> labels)
|
||||||
|
throws Exception {
|
||||||
if (s.startsWith("// label ")) {
|
if (s.startsWith("// label ")) {
|
||||||
int labelNr = Integer.parseInt(s.substring(9));
|
int labelNr = Integer.parseInt(s.substring(9));
|
||||||
for (Map.Entry<LabelNode, Integer> entry : labels.entrySet()) {
|
for (Map.Entry<LabelNode, Integer> entry : labels.entrySet()) {
|
||||||
@@ -648,124 +690,41 @@ public class Assembler {
|
|||||||
labels.put(ln, labelNr);
|
labels.put(ln, labelNr);
|
||||||
return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), ln);
|
return new LineNumberNode(Integer.parseInt(s.split(" ")[0]), ln);
|
||||||
} else if (s.startsWith("// frame ")) {
|
} else if (s.startsWith("// frame ")) {
|
||||||
String str1 = s.substring(7);
|
String str1 = s.substring(9);
|
||||||
String str = str1.substring(str1.indexOf(' ', 3) + 1);
|
String[] split = str1.split(" ", 2);
|
||||||
Object[] local;
|
|
||||||
Object[] stack;
|
|
||||||
ArrayList<Object> arr = new ArrayList<>();
|
|
||||||
if (str.startsWith("l:null")) {
|
|
||||||
local = new Object[0];
|
|
||||||
} else {
|
|
||||||
String l = str.substring(3, str.indexOf("s:") - 2);
|
|
||||||
if (l.isEmpty()) {
|
|
||||||
local = new Object[0];
|
|
||||||
} else {
|
|
||||||
for (String asd : l.split(", ")) {
|
|
||||||
if (!asd.startsWith("(")) {
|
|
||||||
int frameType = ClassUtil.getFrameTypeByName(asd);
|
|
||||||
if (frameType != -1)
|
|
||||||
arr.add(new Integer(frameType));
|
|
||||||
else {
|
|
||||||
String frame = UnicodeUtils.unescape(asd);
|
|
||||||
frame = frame.substring(1, frame.length() - 1);
|
|
||||||
arr.add(frame);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (asd.startsWith("(label) ")) {
|
|
||||||
int labelNr = Integer.parseInt(asd.split(" ")[1]);
|
|
||||||
boolean found = false;
|
|
||||||
for (Map.Entry<LabelNode, Integer> entry : labels.entrySet()) {
|
|
||||||
if (entry.getValue() == labelNr) {
|
|
||||||
arr.add(entry.getKey());
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
LabelNode ln = new LabelNode(new Label());
|
|
||||||
labels.put(ln, labelNr);
|
|
||||||
arr.add(ln);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arr.add(ClassUtil.getCastedValue(asd.split(" ")[1], asd.split("\\) ")[0].substring(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local = new Object[arr.size()];
|
|
||||||
int c = 0;
|
|
||||||
for (Object o : arr) {
|
|
||||||
local[c] = o;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arr.clear();
|
|
||||||
if (str.endsWith("s:null")) {
|
|
||||||
stack = new Object[0];
|
|
||||||
} else {
|
|
||||||
String st = str.substring(str.indexOf("s:") + 3, str.length() - 1);
|
|
||||||
if (st.isEmpty()) {
|
|
||||||
stack = new Object[0];
|
|
||||||
} else {
|
|
||||||
for (String asd : st.split(", ")) {
|
|
||||||
if (!asd.startsWith("(")) {
|
|
||||||
int frameType = ClassUtil.getFrameTypeByName(asd);
|
|
||||||
if (frameType != -1)
|
|
||||||
arr.add(new Integer(frameType));
|
|
||||||
else {
|
|
||||||
String frame = UnicodeUtils.unescape(asd);
|
|
||||||
frame = frame.substring(1, frame.length() - 1);
|
|
||||||
arr.add(frame);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (asd.startsWith("(label) ")) {
|
|
||||||
int labelNr = Integer.parseInt(asd.split(" ")[1]);
|
|
||||||
boolean found = false;
|
|
||||||
for (Map.Entry<LabelNode, Integer> entry : labels.entrySet()) {
|
|
||||||
if (entry.getValue() == labelNr) {
|
|
||||||
arr.add(entry.getKey());
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
LabelNode ln = new LabelNode(new Label());
|
|
||||||
labels.put(ln, labelNr);
|
|
||||||
arr.add(ln);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arr.add(ClassUtil.getCastedValue(asd.split(" ")[1], asd.split("\\) ")[0].substring(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stack = new Object[arr.size()];
|
|
||||||
int c = 0;
|
|
||||||
for (Object o : arr) {
|
|
||||||
stack[c] = o;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
switch (str1.substring(str1.indexOf(' ', 1) + 1, str1.indexOf(' ', 3))) {
|
Object[] local = null;
|
||||||
case "NEW":
|
Object[] stack = null;
|
||||||
type = Opcodes.F_NEW;
|
int localLen = 0;
|
||||||
break;
|
int stackLen = 0;
|
||||||
case "FULL":
|
switch (split[0].toUpperCase()) {
|
||||||
type = Opcodes.F_FULL;
|
|
||||||
break;
|
|
||||||
case "APPEND":
|
|
||||||
type = Opcodes.F_APPEND;
|
|
||||||
break;
|
|
||||||
case "CHOP":
|
|
||||||
type = Opcodes.F_CHOP;
|
|
||||||
break;
|
|
||||||
case "SAME":
|
case "SAME":
|
||||||
type = Opcodes.F_SAME;
|
type = Opcodes.F_SAME;
|
||||||
break;
|
break;
|
||||||
case "SAME1":
|
case "SAME1":
|
||||||
type = Opcodes.F_SAME1;
|
type = Opcodes.F_SAME1;
|
||||||
|
stack = parseFrameList(hsr, split[1], labels);
|
||||||
|
stackLen = stack.length;
|
||||||
|
break;
|
||||||
|
case "CHOP":
|
||||||
|
type = Opcodes.F_CHOP;
|
||||||
|
localLen = Integer.parseInt(split[1]);
|
||||||
|
break;
|
||||||
|
case "APPEND":
|
||||||
|
type = Opcodes.F_APPEND;
|
||||||
|
local = parseFrameList(hsr, split[1], labels);
|
||||||
|
localLen = local.length;
|
||||||
|
break;
|
||||||
|
case "FULL":
|
||||||
|
type = Opcodes.F_FULL;
|
||||||
|
split = split[1].split("\\] \\[", 2);
|
||||||
|
local = parseFrameList(hsr, split[0] + "]", labels);
|
||||||
|
localLen = local.length;
|
||||||
|
stack = parseFrameList(hsr, "[" + split[1], labels);
|
||||||
|
stackLen = stack.length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new FrameNode(type, local.length, local, stack.length, stack);
|
return new FrameNode(type, localLen, local, stackLen, stack);
|
||||||
} else {
|
} else {
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
String command = split[0];
|
String command = split[0];
|
||||||
@@ -803,25 +762,21 @@ public class Assembler {
|
|||||||
case "dconst_1":
|
case "dconst_1":
|
||||||
return new InsnNode(15);
|
return new InsnNode(15);
|
||||||
case "bipush": {
|
case "bipush": {
|
||||||
return new IntInsnNode(16, Integer.parseInt(split[1]));
|
return new IntInsnNode(16, (byte) Integer.parseInt(split[1]));
|
||||||
}
|
}
|
||||||
case "sipush": {
|
case "sipush": {
|
||||||
return new IntInsnNode(17, Integer.parseInt(split[1]));
|
return new IntInsnNode(17, (short) Integer.parseInt(split[1]));
|
||||||
}
|
}
|
||||||
case "ldc": {
|
case "ldc": {
|
||||||
String str = consolidateStrings(split, 1);
|
String str = consolidateStrings(split, 1);
|
||||||
Object val;
|
Object val;
|
||||||
try {
|
try {
|
||||||
if (str.startsWith("Type: ")) {
|
if (str.startsWith("Type ")) {
|
||||||
str = str.substring(8, str.length() - 2);
|
val = Type.getType(UnicodeUtils.unescape(hsr, str.substring(6, str.length() - 1), true));
|
||||||
String[] split2 = str.split("\n\t");
|
|
||||||
String type = split2[0].substring(7);
|
|
||||||
// Reflection
|
|
||||||
val = new Type(ClassUtil.getIDFromClassNameForType(type),
|
|
||||||
UnicodeUtils.unescape(split2[3].substring(6, split2[3].length() - 1)),
|
|
||||||
Integer.parseInt(split2[1].substring(7)), Integer.parseInt(split2[2].substring(5)));
|
|
||||||
} else if (str.startsWith("\"") && str.endsWith("\"")) {
|
} else if (str.startsWith("\"") && str.endsWith("\"")) {
|
||||||
val = UnicodeUtils.unescape(str.substring(1, str.length() - 1));
|
val = UnicodeUtils.unescape(hsr, str.substring(1, str.length() - 1), true);
|
||||||
|
} else if (str.startsWith("#")) {
|
||||||
|
val = UnicodeUtils.unescape(hsr, str);
|
||||||
} else if (str.endsWith("l")) {
|
} else if (str.endsWith("l")) {
|
||||||
val = Long.parseLong(str.substring(0, str.length() - 1));
|
val = Long.parseLong(str.substring(0, str.length() - 1));
|
||||||
} else if (str.endsWith("f")) {
|
} else if (str.endsWith("f")) {
|
||||||
@@ -1437,50 +1392,54 @@ public class Assembler {
|
|||||||
case "getstatic": {
|
case "getstatic": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new FieldInsnNode(178, UnicodeUtils.unescape(target.substring(0, index)),
|
return new FieldInsnNode(178, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]));
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "putstatic": {
|
case "putstatic": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new FieldInsnNode(179, UnicodeUtils.unescape(target.substring(0, index)),
|
return new FieldInsnNode(179, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]));
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "getfield": {
|
case "getfield": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new FieldInsnNode(180, UnicodeUtils.unescape(target.substring(0, index)),
|
return new FieldInsnNode(180, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]));
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "putfield": {
|
case "putfield": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new FieldInsnNode(181, UnicodeUtils.unescape(target.substring(0, index)),
|
return new FieldInsnNode(181, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]));
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "invokevirtual": {
|
case "invokevirtual": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new MethodInsnNode(182, UnicodeUtils.unescape(target.substring(0, index)),
|
return new MethodInsnNode(182, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false);
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
case "invokespecial": {
|
case "invokespecial": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new MethodInsnNode(183, UnicodeUtils.unescape(target.substring(0, index)),
|
return new MethodInsnNode(183, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false);
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
case "invokestatic": {
|
case "invokestatic": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new MethodInsnNode(184, UnicodeUtils.unescape(target.substring(0, index)),
|
return new MethodInsnNode(184, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), false);
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
case "invokeinterface": {
|
case "invokeinterface": {
|
||||||
String target = split[2];
|
String target = split[2];
|
||||||
int index = target.lastIndexOf("/");
|
int index = target.lastIndexOf("/");
|
||||||
return new MethodInsnNode(185, UnicodeUtils.unescape(target.substring(0, index)),
|
return new MethodInsnNode(185, UnicodeUtils.unescape(hsr, target.substring(0, index)),
|
||||||
UnicodeUtils.unescape(target.substring(index + 1)), UnicodeUtils.unescape(split[1]), true);
|
UnicodeUtils.unescape(hsr, target.substring(index + 1)), UnicodeUtils.unescape(hsr, split[1]),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
case "invokedynamic": {
|
case "invokedynamic": {
|
||||||
String str = s.substring(16, s.length() - 2).replace("", "");
|
String str = s.substring(16, s.length() - 2).replace("", "");
|
||||||
@@ -1491,30 +1450,17 @@ public class Assembler {
|
|||||||
for (int i = 10; i < sp.length - 1; i++) {
|
for (int i = 10; i < sp.length - 1; i++) {
|
||||||
String st = sp[i].substring(1);
|
String st = sp[i].substring(1);
|
||||||
if (st.equals("]")) {
|
if (st.equals("]")) {
|
||||||
if (stage == 1) {
|
if (stage == 2) {
|
||||||
try {
|
|
||||||
// Reflection
|
|
||||||
args.add(new Type(ClassUtil.getIDFromClassNameForType(vals.get(0).substring(6)),
|
|
||||||
UnicodeUtils.unescape(vals.get(3).substring(6, vals.get(3).length() - 1)),
|
|
||||||
Integer.parseInt(vals.get(1).substring(7)),
|
|
||||||
Integer.parseInt(vals.get(2).substring(5))));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else if (stage == 2) {
|
|
||||||
args.add(new Handle(OpcodesReverse.getHandleOpcode(vals.get(4).substring(5)),
|
args.add(new Handle(OpcodesReverse.getHandleOpcode(vals.get(4).substring(5)),
|
||||||
UnicodeUtils.unescape(vals.get(1).substring(7)),
|
UnicodeUtils.unescape(hsr, vals.get(1).substring(7)),
|
||||||
UnicodeUtils.unescape(vals.get(0).substring(6)),
|
UnicodeUtils.unescape(hsr, vals.get(0).substring(6)),
|
||||||
UnicodeUtils.unescape(vals.get(2).substring(6)),
|
UnicodeUtils.unescape(hsr, vals.get(2).substring(6)),
|
||||||
Boolean.parseBoolean(vals.get(3).substring(13))));
|
Boolean.parseBoolean(vals.get(3).substring(13))));
|
||||||
vals.clear();
|
vals.clear();
|
||||||
}
|
}
|
||||||
stage = 0;
|
stage = 0;
|
||||||
} else if (st.equals("Type: [")) {
|
} else if (st.startsWith("Type ")) {
|
||||||
stage = 1;
|
args.add(Type.getType(UnicodeUtils.unescape(hsr, st.substring(6, st.length() - 1), true)));
|
||||||
} else if (stage == 1) {
|
|
||||||
st = st.substring(1);
|
|
||||||
vals.add(st);
|
|
||||||
} else if (st.equals("Handle: [")) {
|
} else if (st.equals("Handle: [")) {
|
||||||
vals.clear();
|
vals.clear();
|
||||||
stage = 2;
|
stage = 2;
|
||||||
@@ -1523,7 +1469,7 @@ public class Assembler {
|
|||||||
vals.add(st);
|
vals.add(st);
|
||||||
} else if (stage == 0) {
|
} else if (stage == 0) {
|
||||||
if (st.startsWith("\"") && st.endsWith("\"")) {
|
if (st.startsWith("\"") && st.endsWith("\"")) {
|
||||||
args.add(UnicodeUtils.unescape(st.substring(1, st.length() - 1)));
|
args.add(UnicodeUtils.unescape(hsr, st.substring(1, st.length() - 1)));
|
||||||
} else if (st.endsWith("l")) {
|
} else if (st.endsWith("l")) {
|
||||||
args.add(Long.parseLong(st.substring(0, st.length() - 1)));
|
args.add(Long.parseLong(st.substring(0, st.length() - 1)));
|
||||||
} else if (st.endsWith("f")) {
|
} else if (st.endsWith("f")) {
|
||||||
@@ -1535,27 +1481,23 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object[] _args = new Object[args.size()];
|
return new InvokeDynamicInsnNode(UnicodeUtils.unescape(hsr, sp[0].substring(7)),
|
||||||
stage = 0;
|
UnicodeUtils.unescape(hsr, sp[1].substring(6)),
|
||||||
for (Object o : args) {
|
|
||||||
_args[stage] = o;
|
|
||||||
stage++;
|
|
||||||
}
|
|
||||||
return new InvokeDynamicInsnNode(UnicodeUtils.unescape(sp[0].substring(7)),
|
|
||||||
UnicodeUtils.unescape(sp[1].substring(6)),
|
|
||||||
new Handle(OpcodesReverse.getHandleOpcode(sp[7].substring(6)),
|
new Handle(OpcodesReverse.getHandleOpcode(sp[7].substring(6)),
|
||||||
UnicodeUtils.unescape(sp[4].substring(8)), UnicodeUtils.unescape(sp[3].substring(7)),
|
UnicodeUtils.unescape(hsr, sp[4].substring(8)),
|
||||||
UnicodeUtils.unescape(sp[5].substring(7)), Boolean.parseBoolean(sp[6].substring(14))),
|
UnicodeUtils.unescape(hsr, sp[3].substring(7)),
|
||||||
_args);
|
UnicodeUtils.unescape(hsr, sp[5].substring(7)),
|
||||||
|
Boolean.parseBoolean(sp[6].substring(14))),
|
||||||
|
args.toArray(new Object[args.size()]));
|
||||||
}
|
}
|
||||||
case "new": {
|
case "new": {
|
||||||
return new TypeInsnNode(187, UnicodeUtils.unescape(split[1]));
|
return new TypeInsnNode(187, UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "newarray": {
|
case "newarray": {
|
||||||
return new IntInsnNode(188, ClassUtil.getArrayIDByType(split[1]));
|
return new IntInsnNode(188, ClassUtil.getArrayIDByType(split[1]));
|
||||||
}
|
}
|
||||||
case "anewarray": {
|
case "anewarray": {
|
||||||
return new TypeInsnNode(189, UnicodeUtils.unescape(split[1]));
|
return new TypeInsnNode(189, UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "arraylength": {
|
case "arraylength": {
|
||||||
return new InsnNode(190);
|
return new InsnNode(190);
|
||||||
@@ -1564,10 +1506,10 @@ public class Assembler {
|
|||||||
return new InsnNode(191);
|
return new InsnNode(191);
|
||||||
}
|
}
|
||||||
case "checkcast": {
|
case "checkcast": {
|
||||||
return new TypeInsnNode(192, UnicodeUtils.unescape(split[1]));
|
return new TypeInsnNode(192, UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "instanceof": {
|
case "instanceof": {
|
||||||
return new TypeInsnNode(193, UnicodeUtils.unescape(split[1]));
|
return new TypeInsnNode(193, UnicodeUtils.unescape(hsr, split[1]));
|
||||||
}
|
}
|
||||||
case "monitorenter": {
|
case "monitorenter": {
|
||||||
return new InsnNode(194);
|
return new InsnNode(194);
|
||||||
@@ -1576,7 +1518,7 @@ public class Assembler {
|
|||||||
return new InsnNode(195);
|
return new InsnNode(195);
|
||||||
}
|
}
|
||||||
case "multianewarray": {
|
case "multianewarray": {
|
||||||
return new MultiANewArrayInsnNode(UnicodeUtils.unescape(split[1]), Integer.parseInt(split[2]));
|
return new MultiANewArrayInsnNode(UnicodeUtils.unescape(hsr, split[1]), Integer.parseInt(split[2]));
|
||||||
}
|
}
|
||||||
case "ifnull": {
|
case "ifnull": {
|
||||||
int labelNr = Integer.parseInt(s.split(" ")[1]);
|
int labelNr = Integer.parseInt(s.split(" ")[1]);
|
||||||
@@ -1605,4 +1547,41 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object[] parseFrameList(HugeStringsRev hsr, String str, HashMap<LabelNode, Integer> labels) {
|
||||||
|
ArrayList<Object> list = new ArrayList<>();
|
||||||
|
String l = str.substring(1, str.length() - 1);
|
||||||
|
if (l.isEmpty())
|
||||||
|
return EMPTY_OBJECT_ARRAY;
|
||||||
|
|
||||||
|
for (String asd : l.split(", ")) {
|
||||||
|
if (!asd.startsWith("(")) {
|
||||||
|
int frameType = ClassUtil.getFrameTypeByName(asd);
|
||||||
|
if (frameType != -1)
|
||||||
|
list.add(Integer.valueOf(frameType));
|
||||||
|
else
|
||||||
|
list.add(UnicodeUtils.unescape(hsr, asd.substring(1, asd.length() - 1)));
|
||||||
|
} else {
|
||||||
|
if (asd.startsWith("(label) ")) {
|
||||||
|
int labelNr = Integer.parseInt(asd.split(" ")[1]);
|
||||||
|
boolean found = false;
|
||||||
|
for (Map.Entry<LabelNode, Integer> entry : labels.entrySet()) {
|
||||||
|
if (entry.getValue() == labelNr) {
|
||||||
|
list.add(entry.getKey());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
LabelNode ln = new LabelNode(new Label());
|
||||||
|
labels.put(ln, labelNr);
|
||||||
|
list.add(ln);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list.add(ClassUtil.getCastedValue(asd.split(" ")[1], asd.split("\\) ")[0].substring(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.toArray(new Object[list.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,34 @@
|
|||||||
package me.ByteEdit.edit;
|
package me.ByteEdit.edit;
|
||||||
|
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.FRAME;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.INVOKE_DYNAMIC_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.LABEL;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.LINE;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.MULTIANEWARRAY_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN;
|
||||||
|
import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.FutureTask;
|
||||||
|
|
||||||
import org.objectweb.asm.Handle;
|
import org.objectweb.asm.Handle;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
@@ -23,7 +42,7 @@ import org.objectweb.asm.tree.FieldNode;
|
|||||||
import org.objectweb.asm.tree.FrameNode;
|
import org.objectweb.asm.tree.FrameNode;
|
||||||
import org.objectweb.asm.tree.IincInsnNode;
|
import org.objectweb.asm.tree.IincInsnNode;
|
||||||
import org.objectweb.asm.tree.InnerClassNode;
|
import org.objectweb.asm.tree.InnerClassNode;
|
||||||
import org.objectweb.asm.tree.InsnNode;
|
import org.objectweb.asm.tree.InsnList;
|
||||||
import org.objectweb.asm.tree.IntInsnNode;
|
import org.objectweb.asm.tree.IntInsnNode;
|
||||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||||
import org.objectweb.asm.tree.JumpInsnNode;
|
import org.objectweb.asm.tree.JumpInsnNode;
|
||||||
@@ -40,111 +59,108 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
|
|||||||
import org.objectweb.asm.tree.TypeInsnNode;
|
import org.objectweb.asm.tree.TypeInsnNode;
|
||||||
import org.objectweb.asm.tree.VarInsnNode;
|
import org.objectweb.asm.tree.VarInsnNode;
|
||||||
|
|
||||||
|
import me.ByteEdit.decompiler.IDecompiler;
|
||||||
|
import me.ByteEdit.main.Main;
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.OpcodesReverse;
|
import me.ByteEdit.utils.OpcodesReverse;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
|
|
||||||
public class Disassembler {
|
public class Disassembler implements IDecompiler {
|
||||||
|
|
||||||
private static final ExecutorService exec = Executors
|
private static final ExecutorService exec = Executors
|
||||||
.newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2);
|
.newFixedThreadPool((Runtime.getRuntime().availableProcessors() + 1) / 2);
|
||||||
|
|
||||||
public static String disassemble(ClassNode classNode) {
|
@Override
|
||||||
return disassemble(classNode, null).getDisassembly();
|
public String decompile(ClassNode cn, Map<String, ClassNode> classNodes) {
|
||||||
|
String name = cn.name;
|
||||||
|
StringBuilder dis = new StringBuilder(disassemble(cn));
|
||||||
|
synchronized (classNodes) {
|
||||||
|
for (Entry<String, ClassNode> entry : classNodes.entrySet()) {
|
||||||
|
if (entry.getKey().contains("$")) {
|
||||||
|
String[] split = entry.getKey().split("\\$");
|
||||||
|
if (split[0].equals(name)) {
|
||||||
|
dis.append('\n');
|
||||||
|
dis.append(disassemble(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dis.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DisassembleTuple {
|
private static String disassemble(ClassNode classNode) {
|
||||||
|
|
||||||
private final String dis;
|
|
||||||
private final int line;
|
|
||||||
|
|
||||||
public DisassembleTuple(String dis) {
|
|
||||||
this.dis = dis;
|
|
||||||
this.line = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DisassembleTuple(String dis, int line) {
|
|
||||||
this.dis = dis;
|
|
||||||
this.line = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisassembly() {
|
|
||||||
return dis;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLine() {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisassembleTuple disassemble(ClassNode classNode, Object nodeToFind) {
|
|
||||||
if (classNode == null) {
|
if (classNode == null) {
|
||||||
return new DisassembleTuple("ClassNode is null! This is not a valid java class file!");
|
return "ClassNode is null! This is not a valid java class file!";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AtomicInteger lineFound = new AtomicInteger(-1);
|
HugeStrings hs = new HugeStrings();
|
||||||
StringContext ctx = new StringContext(16);
|
StringContext ctx = new StringContext(18);
|
||||||
ctx.next("// #Annotations:\n");
|
ctx.next("// #Annotations:\n");
|
||||||
ctx.next(doAnnotations(classNode.visibleAnnotations));
|
ctx.next(doAnnotations(classNode.visibleAnnotations, hs, ""));
|
||||||
ctx.next("// #Class v:" + classNode.version + "\n");
|
ctx.next("// #Class v:" + classNode.version + "\n");
|
||||||
if (classNode.signature != null)
|
if (classNode.signature != null)
|
||||||
ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(classNode.signature) + "\n");
|
ctx.next("// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, classNode.signature) + "\n");
|
||||||
if (classNode.outerMethod != null)
|
if (classNode.outerMethod != null)
|
||||||
ctx.next("// #OuterMethod: " + (classNode.outerMethod == null ? "null"
|
ctx.next(
|
||||||
: (UnicodeUtils.escapeWithSpaces(classNode.outerMethod) + " "
|
"// #OuterMethod: "
|
||||||
+ UnicodeUtils.escapeWithSpaces(classNode.outerMethodDesc)))
|
+ (classNode.outerMethod == null ? "null"
|
||||||
|
: (UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethod) + " "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, classNode.outerMethodDesc)))
|
||||||
+ "\n");
|
+ "\n");
|
||||||
if (classNode.outerClass != null)
|
if (classNode.outerClass != null)
|
||||||
ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(classNode.outerClass) + "\n");
|
ctx.next("// #OuterClass: " + UnicodeUtils.escapeWithSpaces(hs, classNode.outerClass) + "\n");
|
||||||
ctx.next("// #InnerClasses:\n");
|
ctx.next("// #InnerClasses:\n");
|
||||||
if (classNode.innerClasses != null) {
|
if (classNode.innerClasses != null) {
|
||||||
String ics = "";
|
String ics = "";
|
||||||
for (InnerClassNode icn : classNode.innerClasses) {
|
for (InnerClassNode icn : classNode.innerClasses) {
|
||||||
ics += "// " + UnicodeUtils.escapeWithSpaces(icn.name) + " "
|
ics += "// " + UnicodeUtils.escapeWithSpaces(hs, icn.name) + " "
|
||||||
+ UnicodeUtils.escapeWithSpaces(icn.outerName) + " "
|
+ UnicodeUtils.escapeWithSpaces(hs, icn.outerName) + " "
|
||||||
+ UnicodeUtils.escapeWithSpaces(icn.innerName)
|
+ UnicodeUtils.escapeWithSpaces(hs, icn.innerName)
|
||||||
+ (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n";
|
+ (icn.access == 0 ? "" : " " + ClassUtil.getAccessFlagsFull(icn.access).trim()) + "\n";
|
||||||
}
|
}
|
||||||
ctx.next(ics);
|
ctx.next(ics);
|
||||||
}
|
}
|
||||||
ctx.next(ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(classNode.name)
|
ctx.next(ClassUtil.getAccessFlagsClass(classNode.access) + UnicodeUtils.escapeWithSpaces(hs, classNode.name)
|
||||||
+ " ");
|
+ " ");
|
||||||
ctx.next("extends " + UnicodeUtils.escapeWithSpaces(classNode.superName) + " ");
|
ctx.next("extends " + UnicodeUtils.escapeWithSpaces(hs, classNode.superName) + " ");
|
||||||
if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) {
|
if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) {
|
||||||
String interfaceStr = "";
|
String interfaceStr = "";
|
||||||
for (String interfc : classNode.interfaces) {
|
for (String interfc : classNode.interfaces) {
|
||||||
if (interfaceStr.isEmpty()) {
|
if (interfaceStr.isEmpty()) {
|
||||||
interfaceStr += UnicodeUtils.escapeWithSpaces(interfc);
|
interfaceStr += UnicodeUtils.escapeWithSpaces(hs, interfc);
|
||||||
} else {
|
} else {
|
||||||
interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(interfc);
|
interfaceStr += ", " + UnicodeUtils.escapeWithSpaces(hs, interfc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!interfaceStr.isEmpty())
|
if (!interfaceStr.isEmpty())
|
||||||
ctx.next("implements " + interfaceStr + " ");
|
ctx.next("implements " + interfaceStr + " ");
|
||||||
}
|
}
|
||||||
ctx.next("{\n// #SourceFile: "
|
ctx.next("{\n// #SourceFile: "
|
||||||
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(classNode.sourceFile))
|
+ (classNode.sourceFile == null ? "null" : UnicodeUtils.escape(hs, classNode.sourceFile)) + "\n");
|
||||||
+ "\n\n// #Fields\n");
|
int hugeIdx = ctx.next("");
|
||||||
ctx.next(doFields(classNode.fields, nodeToFind, lineFound));
|
ctx.next("\n// #Fields\n");
|
||||||
|
ctx.next(doFields(classNode.fields, hs));
|
||||||
ctx.next("\n// #Methods\n");
|
ctx.next("\n// #Methods\n");
|
||||||
ctx.next(doMethods(classNode.methods, classNode.name, nodeToFind, lineFound));
|
ctx.next(doMethods(classNode.methods, hs));
|
||||||
ctx.next("}\n");
|
ctx.next("}\n");
|
||||||
return new DisassembleTuple(ctx.finish(), lineFound.get());
|
|
||||||
|
if (!hs.isEmpty())
|
||||||
|
ctx.set(hugeIdx, hs.makeStringsList());
|
||||||
|
return ctx.finish();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return new DisassembleTuple("Class couldn't be decompiled:\n" + e.getClass().getName() + ": "
|
return "Class couldn't be decompiled:\n" + e.getClass().getName() + ": " + e.getMessage() + "\n"
|
||||||
+ e.getMessage() + "\n"
|
|
||||||
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
|
+ Arrays.toString(e.getStackTrace()).replace(", ", "\n\tat ").replace("[", "\tat ").replace("]", "")
|
||||||
+ "\n");
|
+ "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String doAnnotations(List<AnnotationNode> annotations) {
|
private static String doAnnotations(List<AnnotationNode> annotations, HugeStrings hs, String linePrefix) {
|
||||||
if (annotations == null)
|
if (annotations == null)
|
||||||
return "";
|
return "";
|
||||||
StringContext ctx = new StringContext(annotations.size());
|
StringContext ctx = new StringContext(annotations.size());
|
||||||
for (AnnotationNode annotationNode : annotations) {
|
for (AnnotationNode annotationNode : annotations) {
|
||||||
String s = "@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc);
|
String s = linePrefix + "@" + UnicodeUtils.escapeWithSpaces(hs, annotationNode.desc);
|
||||||
if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
|
if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
|
||||||
s += " (";
|
s += " (";
|
||||||
boolean valBefore = true;
|
boolean valBefore = true;
|
||||||
@@ -153,16 +169,16 @@ public class Disassembler {
|
|||||||
s += o + " = [";
|
s += o + " = [";
|
||||||
valBefore = false;
|
valBefore = false;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
if (o instanceof String[]) {
|
if (o instanceof String[]) {
|
||||||
String[] arr = (String[]) o;
|
String[] arr = (String[]) o;
|
||||||
boolean w8ing = false;
|
boolean w8ing = false;
|
||||||
for (String rofl : arr) {
|
for (String rofl : arr) {
|
||||||
if (!w8ing) {
|
if (!w8ing) {
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
|
||||||
w8ing = true;
|
w8ing = true;
|
||||||
} else {
|
} else {
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "]";
|
s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += ", ";
|
s += ", ";
|
||||||
@@ -175,27 +191,26 @@ public class Disassembler {
|
|||||||
boolean w8ing = false;
|
boolean w8ing = false;
|
||||||
for (String rofl : arr) {
|
for (String rofl : arr) {
|
||||||
if (!w8ing) {
|
if (!w8ing) {
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
s += UnicodeUtils.escapeWithSpaces(hs, rofl) + "/";
|
||||||
w8ing = true;
|
w8ing = true;
|
||||||
} else {
|
} else {
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl);
|
s += UnicodeUtils.escapeWithSpaces(hs, rofl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\"";
|
s += "\"" + UnicodeUtils.escape(hs, String.valueOf(obj)) + "\"";
|
||||||
}
|
}
|
||||||
s += ", ";
|
s += ", ";
|
||||||
}
|
}
|
||||||
s = s.substring(0, s.length() - 2);
|
s = s.substring(0, s.length() - 2);
|
||||||
s += " }]";
|
s += " }], ";
|
||||||
} else if (o instanceof String) {
|
} else if (o instanceof String) {
|
||||||
s += "\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"], ";
|
s += "\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\"], ";
|
||||||
} else {
|
} else {
|
||||||
s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
|
s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
|
||||||
}
|
}
|
||||||
valBefore = true;
|
valBefore = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (s.endsWith(", "))
|
if (s.endsWith(", "))
|
||||||
s = s.substring(0, s.length() - 2);
|
s = s.substring(0, s.length() - 2);
|
||||||
s += ")";
|
s += ")";
|
||||||
@@ -206,93 +221,35 @@ public class Disassembler {
|
|||||||
return ctx.finish();
|
return ctx.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String doMethods(List<MethodNode> methods, String className, Object nodeToFind,
|
private static String doMethods(List<MethodNode> methods, HugeStrings hs)
|
||||||
AtomicInteger lineFound) throws InterruptedException, ExecutionException {
|
throws InterruptedException, ExecutionException {
|
||||||
|
boolean multithreaded = Main.INSTANCE.mntmMultithreaded.isSelected();
|
||||||
Future<String>[] futures = new Future[methods.size()];
|
Future<String>[] futures = new Future[methods.size()];
|
||||||
for (int i = 0; i < futures.length; i++) {
|
for (int i = 0; i < futures.length; i++) {
|
||||||
MethodNode mn = methods.get(i);
|
MethodNode mn = methods.get(i);
|
||||||
futures[i] = exec.submit(new Callable<String>() {
|
Callable<String> callable = new Callable<String>() {
|
||||||
@Override
|
@Override
|
||||||
public String call() throws Exception {
|
public String call() throws Exception {
|
||||||
String ms = "";
|
String ms = "";
|
||||||
try {
|
try {
|
||||||
ms += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n";
|
ms += "\t// #Max: l:" + mn.maxLocals + " s:" + mn.maxStack + "\n";
|
||||||
if (mn.signature != null)
|
if (mn.signature != null)
|
||||||
ms += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(mn.signature) + "\n";
|
ms += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, mn.signature) + "\n";
|
||||||
String[] dis = disassembleMethod(className, mn);
|
String[] dis = disassembleMethod(mn, hs);
|
||||||
ms += dis[2];
|
ms += dis[2];
|
||||||
ms += dis[1];
|
ms += dis[1];
|
||||||
if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty()) {
|
if (mn.visibleAnnotations != null && !mn.visibleAnnotations.isEmpty())
|
||||||
for (AnnotationNode annotationNode : mn.visibleAnnotations) {
|
ms += doAnnotations(mn.visibleAnnotations, hs, "\t");
|
||||||
ms += "\t@" + annotationNode.desc;
|
ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access)
|
||||||
if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
|
+ UnicodeUtils.escapeWithSpaces(hs, mn.name) + " "
|
||||||
ms += " (";
|
+ UnicodeUtils.escapeWithSpaces(hs, mn.desc) + " ";
|
||||||
boolean valBefore = true;
|
|
||||||
for (Object o : annotationNode.values) {
|
|
||||||
if (valBefore) {
|
|
||||||
ms += o + " = [";
|
|
||||||
valBefore = false;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (o instanceof String[]) {
|
|
||||||
String[] arr = (String[]) o;
|
|
||||||
boolean w8ing = false;
|
|
||||||
for (String rofl : arr) {
|
|
||||||
if (!w8ing) {
|
|
||||||
ms += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
|
||||||
w8ing = true;
|
|
||||||
} else {
|
|
||||||
ms += UnicodeUtils.escapeWithSpaces(rofl) + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ms += ", ";
|
|
||||||
} else if (o instanceof List) {
|
|
||||||
List list = (List) o;
|
|
||||||
ms += "{ ";
|
|
||||||
for (Object obj : list) {
|
|
||||||
if (obj instanceof String[]) {
|
|
||||||
String[] arr = (String[]) obj;
|
|
||||||
boolean w8ing = false;
|
|
||||||
for (String rofl : arr) {
|
|
||||||
if (!w8ing) {
|
|
||||||
ms += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
|
||||||
w8ing = true;
|
|
||||||
} else {
|
|
||||||
ms += UnicodeUtils.escapeWithSpaces(rofl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ms += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\"";
|
|
||||||
}
|
|
||||||
ms += ", ";
|
|
||||||
}
|
|
||||||
ms = ms.substring(0, ms.length() - 2);
|
|
||||||
ms += " }]";
|
|
||||||
} else {
|
|
||||||
ms += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
|
|
||||||
}
|
|
||||||
valBefore = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ms.endsWith(", "))
|
|
||||||
ms = ms.substring(0, ms.length() - 2);
|
|
||||||
ms += ")";
|
|
||||||
}
|
|
||||||
ms += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mn.equals(nodeToFind)) {
|
|
||||||
lineFound.set(ms.split("\\n").length);
|
|
||||||
}
|
|
||||||
ms += "\t" + ClassUtil.getAccessFlagsFull(mn.access) + UnicodeUtils.escapeWithSpaces(mn.name)
|
|
||||||
+ " " + UnicodeUtils.escapeWithSpaces(mn.desc) + " ";
|
|
||||||
if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
|
if (mn.exceptions != null && !mn.exceptions.isEmpty()) {
|
||||||
String exceptionStr = "";
|
String exceptionStr = "";
|
||||||
for (String exc : mn.exceptions) {
|
for (String exc : mn.exceptions) {
|
||||||
if (exceptionStr.isEmpty()) {
|
if (exceptionStr.isEmpty()) {
|
||||||
exceptionStr += UnicodeUtils.escapeWithSpaces(exc);
|
exceptionStr += UnicodeUtils.escapeWithSpaces(hs, exc);
|
||||||
} else {
|
} else {
|
||||||
exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(exc);
|
exceptionStr += ", " + UnicodeUtils.escapeWithSpaces(hs, exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!exceptionStr.isEmpty())
|
if (!exceptionStr.isEmpty())
|
||||||
@@ -309,10 +266,13 @@ public class Disassembler {
|
|||||||
}
|
}
|
||||||
return ms;
|
return ms;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
futures[i] = multithreaded ? exec.submit(callable) : new FutureTask<>(callable);
|
||||||
}
|
}
|
||||||
StringContext ctx = new StringContext(futures.length);
|
StringContext ctx = new StringContext(futures.length);
|
||||||
for (Future<String> f : futures) {
|
for (Future<String> f : futures) {
|
||||||
|
if (f instanceof FutureTask)
|
||||||
|
((FutureTask) f).run();
|
||||||
ctx.next(f.get());
|
ctx.next(f.get());
|
||||||
}
|
}
|
||||||
String s = ctx.finish();
|
String s = ctx.finish();
|
||||||
@@ -321,78 +281,18 @@ public class Disassembler {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String doFields(List<FieldNode> fields, Object nodeToFind, AtomicInteger lineFound) {
|
private static String doFields(List<FieldNode> fields, HugeStrings hs) {
|
||||||
StringContext ctx = new StringContext(fields.size());
|
StringContext ctx = new StringContext(fields.size());
|
||||||
for (FieldNode fn : fields) {
|
for (FieldNode fn : fields) {
|
||||||
String s = "";
|
String s = "";
|
||||||
if (fn.signature != null)
|
if (fn.signature != null)
|
||||||
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(fn.signature) + "\n";
|
s += "\t// #Signature: " + UnicodeUtils.escapeWithSpaces(hs, fn.signature) + "\n";
|
||||||
if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty()) {
|
if (fn.visibleAnnotations != null && !fn.visibleAnnotations.isEmpty())
|
||||||
for (AnnotationNode annotationNode : fn.visibleAnnotations) {
|
s += doAnnotations(fn.visibleAnnotations, hs, "\t");
|
||||||
s += "\t@" + UnicodeUtils.escapeWithSpaces(annotationNode.desc);
|
|
||||||
if (annotationNode.values != null && !annotationNode.values.isEmpty()) {
|
|
||||||
s += " (";
|
|
||||||
boolean valBefore = true;
|
|
||||||
for (Object o : annotationNode.values) {
|
|
||||||
if (valBefore) {
|
|
||||||
s += o + " = [";
|
|
||||||
valBefore = false;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (o instanceof String[]) {
|
|
||||||
String[] arr = (String[]) o;
|
|
||||||
boolean w8ing = false;
|
|
||||||
for (String rofl : arr) {
|
|
||||||
if (!w8ing) {
|
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
|
||||||
w8ing = true;
|
|
||||||
} else {
|
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s += ", ";
|
|
||||||
} else if (o instanceof List) {
|
|
||||||
List list = (List) o;
|
|
||||||
s += "{ ";
|
|
||||||
for (Object obj : list) {
|
|
||||||
if (obj instanceof String[]) {
|
|
||||||
String[] arr = (String[]) obj;
|
|
||||||
boolean w8ing = false;
|
|
||||||
for (String rofl : arr) {
|
|
||||||
if (!w8ing) {
|
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl) + "/";
|
|
||||||
w8ing = true;
|
|
||||||
} else {
|
|
||||||
s += UnicodeUtils.escapeWithSpaces(rofl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s += "\"" + UnicodeUtils.escape(String.valueOf(obj)) + "\"";
|
|
||||||
}
|
|
||||||
s += ", ";
|
|
||||||
}
|
|
||||||
s = s.substring(0, s.length() - 2);
|
|
||||||
s += " }]";
|
|
||||||
} else {
|
|
||||||
s += "(" + o.getClass().getName().replace(".", "/") + ") " + o + "], ";
|
|
||||||
}
|
|
||||||
valBefore = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s.endsWith(", "))
|
|
||||||
s = s.substring(0, s.length() - 2);
|
|
||||||
s += ")";
|
|
||||||
}
|
|
||||||
s += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fn.equals(nodeToFind)) {
|
|
||||||
lineFound.set(s.split("\\n").length);
|
|
||||||
}
|
|
||||||
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient")
|
s += "\t" + ClassUtil.getAccessFlagsFull(fn.access).replace("varargs", "transient")
|
||||||
+ UnicodeUtils.escapeWithSpaces(fn.desc) + " " + UnicodeUtils.escapeWithSpaces(fn.name);
|
+ UnicodeUtils.escapeWithSpaces(hs, fn.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, fn.name);
|
||||||
if (fn.value != null) {
|
if (fn.value != null) {
|
||||||
s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true);
|
s += " = " + ClassUtil.getDecompiledValue(fn.value, fn.desc, true, hs);
|
||||||
}
|
}
|
||||||
s += "\n";
|
s += "\n";
|
||||||
ctx.next(s);
|
ctx.next(s);
|
||||||
@@ -400,13 +300,22 @@ public class Disassembler {
|
|||||||
return ctx.finish();
|
return ctx.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] disassembleMethod(String className, MethodNode mn) {
|
private static String[] disassembleMethod(MethodNode mn, HugeStrings hs) {
|
||||||
HashMap<Label, Integer> labels = new HashMap<Label, Integer>();
|
HashMap<Label, Integer> labels = new HashMap<Label, Integer>();
|
||||||
String localVarTable;
|
String localVarTable;
|
||||||
String tryCatchTable;
|
String tryCatchTable;
|
||||||
for (AbstractInsnNode n : mn.instructions.toArray()) {
|
|
||||||
|
InsnList insnList = mn.instructions;
|
||||||
|
boolean deobfNumbers = Main.INSTANCE.mntmNumbers.isSelected();
|
||||||
|
|
||||||
|
ArrayList<Label> labelsReversed = deobfNumbers ? new ArrayList<>() : null;
|
||||||
|
|
||||||
|
for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
|
||||||
if (n instanceof LabelNode) {
|
if (n instanceof LabelNode) {
|
||||||
labels.put(((LabelNode) n).getLabel(), labels.size() + 1);
|
int id = labels.size() + 1;
|
||||||
|
if (deobfNumbers && labelsReversed != null)
|
||||||
|
labelsReversed.add(((LabelNode) n).getLabel());
|
||||||
|
labels.put(((LabelNode) n).getLabel(), id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mn.localVariables != null && !mn.localVariables.isEmpty()) {
|
if (mn.localVariables != null && !mn.localVariables.isEmpty()) {
|
||||||
@@ -414,10 +323,10 @@ public class Disassembler {
|
|||||||
StringContext ctx = new StringContext(list.size() + 1);
|
StringContext ctx = new StringContext(list.size() + 1);
|
||||||
ctx.next("\t// #LocalVars:\n");
|
ctx.next("\t// #LocalVars:\n");
|
||||||
for (LocalVariableNode lvn : list) {
|
for (LocalVariableNode lvn : list) {
|
||||||
ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(lvn.name) + ": "
|
ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, lvn.name) + ": "
|
||||||
+ UnicodeUtils.escapeWithSpaces(lvn.desc) + " i:" + lvn.index + " s:"
|
+ UnicodeUtils.escapeWithSpaces(hs, lvn.desc) + " i:" + lvn.index + " s:"
|
||||||
+ labels.get(lvn.start.getLabel()) + " e:" + labels.get(lvn.end.getLabel()) + " sig:"
|
+ labels.get(lvn.start.getLabel()) + " e:" + labels.get(lvn.end.getLabel()) + " sig:"
|
||||||
+ UnicodeUtils.escapeWithSpaces(lvn.signature) + "\n");
|
+ UnicodeUtils.escapeWithSpaces(hs, lvn.signature) + "\n");
|
||||||
}
|
}
|
||||||
localVarTable = ctx.finish();
|
localVarTable = ctx.finish();
|
||||||
} else
|
} else
|
||||||
@@ -427,208 +336,125 @@ public class Disassembler {
|
|||||||
StringContext ctx = new StringContext(list.size() + 1);
|
StringContext ctx = new StringContext(list.size() + 1);
|
||||||
ctx.next("\t// #TryCatch:\n");
|
ctx.next("\t// #TryCatch:\n");
|
||||||
for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) {
|
for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) {
|
||||||
ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(tcbn.type) + " s:" + labels.get(tcbn.start.getLabel())
|
ctx.next("\t// " + UnicodeUtils.escapeWithSpaces(hs, tcbn.type) + " s:"
|
||||||
+ " e:" + labels.get(tcbn.end.getLabel()) + " h:" + labels.get(tcbn.handler.getLabel()) + "\n");
|
+ labels.get(tcbn.start.getLabel()) + " e:" + labels.get(tcbn.end.getLabel()) + " h:"
|
||||||
|
+ labels.get(tcbn.handler.getLabel()) + "\n");
|
||||||
}
|
}
|
||||||
tryCatchTable = ctx.finish();
|
tryCatchTable = ctx.finish();
|
||||||
} else
|
} else
|
||||||
tryCatchTable = "";
|
tryCatchTable = "";
|
||||||
AbstractInsnNode[] insns = mn.instructions.toArray();
|
|
||||||
StringContext ctx = new StringContext(insns.length);
|
if (deobfNumbers) {
|
||||||
for (AbstractInsnNode n : insns) {
|
StackBasedCalculator calc = new StackBasedCalculator(insnList);
|
||||||
ctx.next(disassembleInstruction(n, labels));
|
calc.run();
|
||||||
|
insnList = calc.get();
|
||||||
|
int i = 0;
|
||||||
|
for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
|
||||||
|
if (n instanceof LabelNode && labelsReversed != null) {
|
||||||
|
((LabelNode) n).setLabel(labelsReversed.get(i++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringContext ctx = new StringContext(insnList.size());
|
||||||
|
for (AbstractInsnNode n = insnList.getFirst(); n != null; n = n.getNext()) {
|
||||||
|
ctx.next(disassembleInstruction(n, labels, hs));
|
||||||
}
|
}
|
||||||
return new String[] { ctx.finish(), localVarTable, tryCatchTable };
|
return new String[] { ctx.finish(), localVarTable, tryCatchTable };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final HashMap<Class, InstructionInterface> iiMap = new HashMap<>();
|
public static String disassembleInstruction(AbstractInsnNode n, HashMap<Label, Integer> labels, HugeStrings hs) {
|
||||||
|
switch (n.getType()) {
|
||||||
static {
|
case INSN: {
|
||||||
iiMap.put(FieldInsnNode.class, (n, labels) -> {
|
|
||||||
FieldInsnNode node = (FieldInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/"
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(LabelNode.class, (n, labels) -> {
|
|
||||||
LabelNode node = (LabelNode) n;
|
|
||||||
return "\t\t// label " + labels.get(node.getLabel()) + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(FrameNode.class, (n, labels) -> {
|
|
||||||
FrameNode node = (FrameNode) n;
|
|
||||||
String type = "";
|
|
||||||
switch (node.type) {
|
|
||||||
case Opcodes.F_NEW:
|
|
||||||
type = "NEW";
|
|
||||||
break;
|
|
||||||
case Opcodes.F_FULL:
|
|
||||||
type = "FULL";
|
|
||||||
break;
|
|
||||||
case Opcodes.F_APPEND:
|
|
||||||
type = "APPEND";
|
|
||||||
break;
|
|
||||||
case Opcodes.F_CHOP:
|
|
||||||
type = "CHOP";
|
|
||||||
break;
|
|
||||||
case Opcodes.F_SAME:
|
|
||||||
type = "SAME";
|
|
||||||
break;
|
|
||||||
case Opcodes.F_SAME1:
|
|
||||||
type = "SAME1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
String s = "\t\t// frame " + type + " l:";
|
|
||||||
ArrayList<String> arr = new ArrayList<>();
|
|
||||||
if (node.local != null) {
|
|
||||||
for (Object o : node.local) {
|
|
||||||
if (o == null) {
|
|
||||||
arr.add(null);
|
|
||||||
} else {
|
|
||||||
if (o instanceof String) {
|
|
||||||
arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"");
|
|
||||||
} else if (o instanceof LabelNode) {
|
|
||||||
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
|
|
||||||
} else if (o instanceof Integer) {
|
|
||||||
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
|
|
||||||
if (frameType != null)
|
|
||||||
arr.add(frameType);
|
|
||||||
else
|
|
||||||
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
|
||||||
} else {
|
|
||||||
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s += arr.toString();
|
|
||||||
} else {
|
|
||||||
s += "null";
|
|
||||||
}
|
|
||||||
arr.clear();
|
|
||||||
s += " s:";
|
|
||||||
if (node.stack != null) {
|
|
||||||
for (Object o : node.stack) {
|
|
||||||
if (o == null) {
|
|
||||||
arr.add(null);
|
|
||||||
} else {
|
|
||||||
if (o instanceof String) {
|
|
||||||
arr.add("\"" + UnicodeUtils.escapeWithSpaces((String) o) + "\"");
|
|
||||||
} else if (o instanceof LabelNode) {
|
|
||||||
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
|
|
||||||
} else if (o instanceof Integer) {
|
|
||||||
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
|
|
||||||
if (frameType != null)
|
|
||||||
arr.add(frameType);
|
|
||||||
else
|
|
||||||
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
|
||||||
} else {
|
|
||||||
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s += arr.toString();
|
|
||||||
} else {
|
|
||||||
s += "null";
|
|
||||||
}
|
|
||||||
s += "\n";
|
|
||||||
return s;
|
|
||||||
});
|
|
||||||
iiMap.put(LineNumberNode.class, (n, labels) -> {
|
|
||||||
LineNumberNode node = (LineNumberNode) n;
|
|
||||||
return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(InvokeDynamicInsnNode.class, (n, labels) -> {
|
|
||||||
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
|
|
||||||
String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.bsm.getName()) + "\n\t\t\t\towner: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.bsm.getOwner()) + "\n\t\t\t\tdesc: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.bsm.getDesc()) + "\n\t\t\t\tisInterface: "
|
|
||||||
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(node.bsm.getTag())
|
|
||||||
+ "\n\t\t\t]\n\t\t\targs: [\n";
|
|
||||||
for (Object l : node.bsmArgs) {
|
|
||||||
if (l instanceof Type) {
|
|
||||||
Type type = (Type) l;
|
|
||||||
int valueBegin = type.valueBegin;
|
|
||||||
int valueEnd = type.valueEnd;
|
|
||||||
String buf = type.valueBuffer;
|
|
||||||
// Reflection
|
|
||||||
s += "\t\t\t\tType: [\n\t\t\t\t\ttype: " + ClassUtil.getClassNameFromType(type)
|
|
||||||
+ "\n\t\t\t\t\tstart: " + valueBegin + "\n\t\t\t\t\tend: " + valueEnd + "\n\t\t\t\t\tbuf: "
|
|
||||||
+ ClassUtil.getDecompiledValue(buf, "");
|
|
||||||
s += "\n\t\t\t\t]\n";
|
|
||||||
} else if (l instanceof Handle) {
|
|
||||||
Handle h = (Handle) l;
|
|
||||||
s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(h.getName()).replace("/", "\\u002F") + "\n\t\t\t\t\towner: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(h.getOwner()) + "\n\t\t\t\t\tdesc: "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(h.getDesc()) + "\n\t\t\t\t\tisInterface: " + h.isInterface()
|
|
||||||
+ "\n\t\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(h.getTag());
|
|
||||||
s += "\n\t\t\t\t]\n";
|
|
||||||
} else {
|
|
||||||
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "") + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s += "\t\t\t]\n\t\t]\n";
|
|
||||||
return s;
|
|
||||||
});
|
|
||||||
iiMap.put(MethodInsnNode.class, (n, labels) -> {
|
|
||||||
MethodInsnNode node = (MethodInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + UnicodeUtils.escapeWithSpaces(node.owner) + "/"
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.name).replace("/", "\\u002F") + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(TypeInsnNode.class, (n, labels) -> {
|
|
||||||
TypeInsnNode node = (TypeInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.desc) + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(MultiANewArrayInsnNode.class, (n, labels) -> {
|
|
||||||
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
|
||||||
+ UnicodeUtils.escapeWithSpaces(node.desc) + " " + node.dims + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(LdcInsnNode.class, (n, labels) -> {
|
|
||||||
LdcInsnNode node = (LdcInsnNode) n;
|
|
||||||
if (node.cst instanceof Type) {
|
|
||||||
Type type = (Type) node.cst;
|
|
||||||
int valueBegin = type.valueBegin;
|
|
||||||
int valueEnd = type.valueEnd;
|
|
||||||
String buf = type.valueBuffer;
|
|
||||||
// Reflection
|
|
||||||
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type: [\n\t\t\ttype: "
|
|
||||||
+ ClassUtil.getClassNameFromType(type) + "\n\t\t\tstart: " + valueBegin + "\n\t\t\tend: "
|
|
||||||
+ valueEnd + "\n\t\t\tbuf: " + ClassUtil.getDecompiledValue(buf, "");
|
|
||||||
s += "\n\t\t]\n";
|
|
||||||
return s;
|
|
||||||
} else {
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
|
||||||
+ ClassUtil.getDecompiledValue(node.cst, "") + "\n";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
iiMap.put(VarInsnNode.class, (n, labels) -> {
|
|
||||||
VarInsnNode node = (VarInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
|
|
||||||
});
|
|
||||||
iiMap.put(InsnNode.class, (n, labels) -> {
|
|
||||||
InsnNode node = (InsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + "\n";
|
||||||
});
|
}
|
||||||
iiMap.put(IntInsnNode.class, (n, labels) -> {
|
case INT_INSN: {
|
||||||
IntInsnNode node = (IntInsnNode) n;
|
IntInsnNode node = (IntInsnNode) n;
|
||||||
if (n.getOpcode() == Opcodes.NEWARRAY) {
|
if (n.getOpcode() == Opcodes.NEWARRAY) {
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
|
||||||
+ ClassUtil.getArrayTypeByID(node.operand) + "\n";
|
+ ClassUtil.getArrayTypeByID(node.operand) + "\n";
|
||||||
} else {
|
}
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.operand + "\n";
|
||||||
}
|
}
|
||||||
});
|
case VAR_INSN: {
|
||||||
iiMap.put(JumpInsnNode.class, (n, labels) -> {
|
VarInsnNode node = (VarInsnNode) n;
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + "\n";
|
||||||
|
}
|
||||||
|
case TYPE_INSN: {
|
||||||
|
TypeInsnNode node = (TypeInsnNode) n;
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n";
|
||||||
|
}
|
||||||
|
case FIELD_INSN: {
|
||||||
|
FieldInsnNode node = (FieldInsnNode) n;
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner)
|
||||||
|
+ "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n";
|
||||||
|
}
|
||||||
|
case METHOD_INSN: {
|
||||||
|
MethodInsnNode node = (MethodInsnNode) n;
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + UnicodeUtils.escapeWithSpaces(hs, node.owner)
|
||||||
|
+ "/" + UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n";
|
||||||
|
}
|
||||||
|
case INVOKE_DYNAMIC_INSN: {
|
||||||
|
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
|
||||||
|
String s = "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " [\n\t\t\tname: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.name).replace("/", "\\u002F") + "\n\t\t\tdesc: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + "\n\t\t\tHandle: [\n\t\t\t\tname: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getName()) + "\n\t\t\t\towner: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getOwner()) + "\n\t\t\t\tdesc: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.bsm.getDesc()) + "\n\t\t\t\tisInterface: "
|
||||||
|
+ node.bsm.isInterface() + "\n\t\t\t\ttag: " + OpcodesReverse.reverseHandleOpcode(node.bsm.getTag())
|
||||||
|
+ "\n\t\t\t]\n\t\t\targs: [\n";
|
||||||
|
for (Object l : node.bsmArgs) {
|
||||||
|
if (l instanceof Type) {
|
||||||
|
s += "\t\t\t\tType " + ClassUtil.getDecompiledValue(((Type) l).getDescriptor(), "", hs) + "\n";
|
||||||
|
} else if (l instanceof Handle) {
|
||||||
|
Handle h = (Handle) l;
|
||||||
|
s += "\t\t\t\tHandle: [\n\t\t\t\t\tname: "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, h.getName()).replace("/", "\\u002F")
|
||||||
|
+ "\n\t\t\t\t\towner: " + UnicodeUtils.escapeWithSpaces(hs, h.getOwner())
|
||||||
|
+ "\n\t\t\t\t\tdesc: " + UnicodeUtils.escapeWithSpaces(hs, h.getDesc())
|
||||||
|
+ "\n\t\t\t\t\tisInterface: " + h.isInterface() + "\n\t\t\t\t\ttag: "
|
||||||
|
+ OpcodesReverse.reverseHandleOpcode(h.getTag());
|
||||||
|
s += "\n\t\t\t\t]\n";
|
||||||
|
} else {
|
||||||
|
s += "\t\t\t\t" + ClassUtil.getDecompiledValue(l, "", hs) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += "\t\t\t]\n\t\t]\n";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
case JUMP_INSN: {
|
||||||
JumpInsnNode node = (JumpInsnNode) n;
|
JumpInsnNode node = (JumpInsnNode) n;
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel())
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + labels.get(node.label.getLabel())
|
||||||
+ "\n";
|
+ "\n";
|
||||||
});
|
}
|
||||||
iiMap.put(TableSwitchInsnNode.class, (n, labels) -> {
|
case LABEL: {
|
||||||
|
LabelNode node = (LabelNode) n;
|
||||||
|
return "\t\t// label " + labels.get(node.getLabel()) + "\n";
|
||||||
|
}
|
||||||
|
case LDC_INSN: {
|
||||||
|
LdcInsnNode node = (LdcInsnNode) n;
|
||||||
|
if (node.cst instanceof Type) {
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " Type "
|
||||||
|
+ ClassUtil.getDecompiledValue(((Type) node.cst).getDescriptor(), "", hs) + "\n";
|
||||||
|
}
|
||||||
|
String decomp = ClassUtil.getDecompiledValue(node.cst, "", hs);
|
||||||
|
if (node.cst instanceof String) {
|
||||||
|
if (decomp.startsWith("\"#") && decomp.endsWith("\""))
|
||||||
|
decomp = decomp.substring(1, decomp.length() - 1);
|
||||||
|
else if (decomp.startsWith("\"\\u0023"))
|
||||||
|
decomp = "\"#" + decomp.substring(7);
|
||||||
|
}
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " " + decomp + "\n";
|
||||||
|
}
|
||||||
|
case IINC_INSN: {
|
||||||
|
IincInsnNode node = (IincInsnNode) n;
|
||||||
|
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
|
||||||
|
}
|
||||||
|
case TABLESWITCH_INSN: {
|
||||||
TableSwitchInsnNode node = (TableSwitchInsnNode) n;
|
TableSwitchInsnNode node = (TableSwitchInsnNode) n;
|
||||||
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tmin: " + node.min
|
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tmin: " + node.min
|
||||||
+ "\n\t\t\tmax: " + node.max + "\n\t\t\tdefault: " + labels.get(node.dflt.getLabel())
|
+ "\n\t\t\tmax: " + node.max + "\n\t\t\tdefault: " + labels.get(node.dflt.getLabel())
|
||||||
@@ -638,8 +464,8 @@ public class Disassembler {
|
|||||||
}
|
}
|
||||||
s += "\t\t\t]\n\t\t]\n";
|
s += "\t\t\t]\n\t\t]\n";
|
||||||
return s;
|
return s;
|
||||||
});
|
}
|
||||||
iiMap.put(LookupSwitchInsnNode.class, (n, labels) -> {
|
case LOOKUPSWITCH_INSN: {
|
||||||
LookupSwitchInsnNode node = (LookupSwitchInsnNode) n;
|
LookupSwitchInsnNode node = (LookupSwitchInsnNode) n;
|
||||||
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: "
|
String s = "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " [\n\t\t\tdefault: "
|
||||||
+ labels.get(node.dflt.getLabel()) + "\n\t\t\tkeys: [\n";
|
+ labels.get(node.dflt.getLabel()) + "\n\t\t\tkeys: [\n";
|
||||||
@@ -652,24 +478,69 @@ public class Disassembler {
|
|||||||
}
|
}
|
||||||
s += "\t\t\t]\n\t\t]\n";
|
s += "\t\t\t]\n\t\t]\n";
|
||||||
return s;
|
return s;
|
||||||
});
|
|
||||||
iiMap.put(IincInsnNode.class, (n, labels) -> {
|
|
||||||
IincInsnNode node = (IincInsnNode) n;
|
|
||||||
return "\t\t" + OpcodesReverse.reverseOpcode(n.getOpcode()) + " " + node.var + " " + node.incr + "\n";
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
case MULTIANEWARRAY_INSN: {
|
||||||
static interface InstructionInterface {
|
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
|
||||||
String apply(AbstractInsnNode n, HashMap<Label, Integer> labels);
|
return "\t\t" + OpcodesReverse.reverseOpcode(node.getOpcode()) + " "
|
||||||
|
+ UnicodeUtils.escapeWithSpaces(hs, node.desc) + " " + node.dims + "\n";
|
||||||
}
|
}
|
||||||
|
case FRAME: {
|
||||||
public static String disassembleInstruction(AbstractInsnNode n, HashMap<Label, Integer> labels) {
|
FrameNode node = (FrameNode) n;
|
||||||
InstructionInterface ii = iiMap.get(n.getClass());
|
String out = "";
|
||||||
if (ii != null)
|
switch (node.type) {
|
||||||
return ii.apply(n, labels);
|
case Opcodes.F_SAME:
|
||||||
else
|
out = "SAME";
|
||||||
|
break;
|
||||||
|
case Opcodes.F_SAME1:
|
||||||
|
out = "SAME1 " + getFrameArray(hs, node.stack, labels);
|
||||||
|
break;
|
||||||
|
case Opcodes.F_CHOP:
|
||||||
|
out = "CHOP " + Integer.toString(node.local.size());
|
||||||
|
break;
|
||||||
|
case Opcodes.F_APPEND:
|
||||||
|
out = "APPEND " + getFrameArray(hs, node.local, labels);
|
||||||
|
break;
|
||||||
|
case Opcodes.F_FULL:
|
||||||
|
out = "FULL " + getFrameArray(hs, node.local, labels) + " " + getFrameArray(hs, node.stack, labels);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "\t\t// frame " + out + "\n";
|
||||||
|
}
|
||||||
|
case LINE: {
|
||||||
|
LineNumberNode node = (LineNumberNode) n;
|
||||||
|
return "\t\t// line " + node.line + " " + labels.get(node.start.getLabel()) + "\n";
|
||||||
|
}
|
||||||
|
default: {
|
||||||
return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
|
return "\t\tNOT HANDLED! " + OpcodesReverse.reverseOpcode(n.getOpcode()) + " "
|
||||||
+ n.getClass().getSimpleName() + "\n";
|
+ n.getClass().getSimpleName() + "\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFrameArray(HugeStrings hs, List<Object> list, HashMap<Label, Integer> labels) {
|
||||||
|
ArrayList<String> arr = new ArrayList<>();
|
||||||
|
if (list != null) {
|
||||||
|
for (Object o : list) {
|
||||||
|
if (o == null) {
|
||||||
|
arr.add(null);
|
||||||
|
} else {
|
||||||
|
if (o instanceof String) {
|
||||||
|
arr.add("\"" + UnicodeUtils.escapeWithSpaces(hs, (String) o) + "\"");
|
||||||
|
} else if (o instanceof LabelNode) {
|
||||||
|
arr.add("(label) " + labels.get(((LabelNode) o).getLabel()));
|
||||||
|
} else if (o instanceof Integer) {
|
||||||
|
String frameType = ClassUtil.getFrameTypeByID(((Integer) o).intValue());
|
||||||
|
if (frameType != null)
|
||||||
|
arr.add(frameType);
|
||||||
|
else
|
||||||
|
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
||||||
|
} else {
|
||||||
|
arr.add("(" + o.getClass().getName().replace(".", "/") + ") " + o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.toString();
|
||||||
|
}
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package me.ByteEdit.edit;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
|
|
||||||
|
public class HugeStrings {
|
||||||
|
|
||||||
|
public static int THRESHOLD = 1000;
|
||||||
|
private final HashMap<String, HugeData> map = new HashMap<>();
|
||||||
|
|
||||||
|
public String onString(String s) {
|
||||||
|
synchronized (map) {
|
||||||
|
HugeData i = map.get(s);
|
||||||
|
if (i == null)
|
||||||
|
map.put(s, i = new HugeData(map.size(), UnicodeUtils.escape(this, s, true)));
|
||||||
|
return "#" + Integer.toString(i.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String makeStringsList() {
|
||||||
|
StringContext ctx = new StringContext(map.size());
|
||||||
|
List<HugeData> list = new ArrayList<>(map.values());
|
||||||
|
list.sort((o1, o2) -> Integer.compare(o1.id, o2.id));
|
||||||
|
for (HugeData hd : list) {
|
||||||
|
StringBuilder sb = new StringBuilder(20 + hd.escaped.length());
|
||||||
|
sb.append('#');
|
||||||
|
sb.append(Integer.toString(hd.id));
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(hd.escaped);
|
||||||
|
sb.append('\n');
|
||||||
|
ctx.next(sb.toString());
|
||||||
|
}
|
||||||
|
return ctx.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HugeData {
|
||||||
|
int id;
|
||||||
|
String escaped;
|
||||||
|
|
||||||
|
public HugeData(int id, String escaped) {
|
||||||
|
this.id = id;
|
||||||
|
this.escaped = escaped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package me.ByteEdit.edit;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class HugeStringsRev {
|
||||||
|
|
||||||
|
private final HashMap<Integer, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
public void add(int i, String s) {
|
||||||
|
map.put(Integer.valueOf(i), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get(int i) {
|
||||||
|
String s = map.get(Integer.valueOf(i));
|
||||||
|
if (s == null)
|
||||||
|
s = "#" + Integer.toString(i);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package me.ByteEdit.edit;
|
|
||||||
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
|
|
||||||
public class OptionBox extends JFrame {
|
|
||||||
|
|
||||||
private JPanel contentPane;
|
|
||||||
public JCheckBox chckbxComputeFrames;
|
|
||||||
public JCheckBox chckbxComputeMax;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the application.
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
EventQueue.invokeLater(new Runnable() {
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
OptionBox frame = new OptionBox();
|
|
||||||
frame.setVisible(true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the frame.
|
|
||||||
*/
|
|
||||||
public OptionBox() {
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
setResizable(false);
|
|
||||||
setTitle("Options");
|
|
||||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
|
||||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 150),
|
|
||||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 100), 300, 200);
|
|
||||||
contentPane = new JPanel();
|
|
||||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
|
||||||
setContentPane(contentPane);
|
|
||||||
contentPane.setLayout(null);
|
|
||||||
chckbxComputeFrames = new JCheckBox("Compute Frames");
|
|
||||||
chckbxComputeFrames.setBounds(6, 7, 138, 23);
|
|
||||||
contentPane.add(chckbxComputeFrames);
|
|
||||||
chckbxComputeMax = new JCheckBox("Compute Max");
|
|
||||||
chckbxComputeMax.setBounds(6, 33, 138, 23);
|
|
||||||
contentPane.add(chckbxComputeMax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
package me.ByteEdit.edit;
|
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.KeyStroke;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
|
|
||||||
import me.ByteEdit.main.Main;
|
|
||||||
|
|
||||||
public class SearchBox extends JFrame {
|
|
||||||
|
|
||||||
public JPanel contentPane;
|
|
||||||
public JTextField txtFind;
|
|
||||||
public JTextField txtReplace;
|
|
||||||
public JCheckBox chckbxCaseSensitive;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the frame.
|
|
||||||
*/
|
|
||||||
public SearchBox() {
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
setResizable(false);
|
|
||||||
setTitle("Find/Replace");
|
|
||||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
|
||||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 128),
|
|
||||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 181), 256, 262);
|
|
||||||
contentPane = new JPanel();
|
|
||||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
|
||||||
setContentPane(contentPane);
|
|
||||||
contentPane.setLayout(null);
|
|
||||||
JLabel lblFind = new JLabel("Find:");
|
|
||||||
lblFind.setBounds(10, 25, 71, 14);
|
|
||||||
contentPane.add(lblFind);
|
|
||||||
txtFind = new JTextField();
|
|
||||||
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
|
||||||
txtFind.registerKeyboardAction(new ActionListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
}, enter, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
||||||
txtFind.setBounds(91, 22, 149, 20);
|
|
||||||
contentPane.add(txtFind);
|
|
||||||
txtFind.setColumns(10);
|
|
||||||
JLabel lblReplaceWith = new JLabel("Replace with:");
|
|
||||||
lblReplaceWith.setBounds(10, 53, 71, 14);
|
|
||||||
contentPane.add(lblReplaceWith);
|
|
||||||
txtReplace = new JTextField();
|
|
||||||
txtReplace.setColumns(10);
|
|
||||||
txtReplace.setBounds(91, 50, 149, 20);
|
|
||||||
contentPane.add(txtReplace);
|
|
||||||
chckbxCaseSensitive = new JCheckBox("Case sensitive");
|
|
||||||
chckbxCaseSensitive.setBounds(10, 103, 230, 23);
|
|
||||||
contentPane.add(chckbxCaseSensitive);
|
|
||||||
JButton btnFind = new JButton("Find");
|
|
||||||
btnFind.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnFind.setBounds(10, 150, 110, 23);
|
|
||||||
contentPane.add(btnFind);
|
|
||||||
JButton btnReplacefind = new JButton("Replace/Find");
|
|
||||||
btnReplacefind.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
replaceFind();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnReplacefind.setBounds(130, 150, 110, 23);
|
|
||||||
contentPane.add(btnReplacefind);
|
|
||||||
JButton btnReplace = new JButton("Replace");
|
|
||||||
btnReplace.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
replace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnReplace.setBounds(10, 184, 110, 23);
|
|
||||||
contentPane.add(btnReplace);
|
|
||||||
JButton btnReplaceAll = new JButton("Replace All");
|
|
||||||
btnReplaceAll.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
replaceAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnReplaceAll.setBounds(130, 184, 110, 23);
|
|
||||||
contentPane.add(btnReplaceAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void find() {
|
|
||||||
int startPos = Main.txtByteEditView.getCaretPosition();
|
|
||||||
String toFind = txtFind.getText();
|
|
||||||
String txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText().substring(startPos)
|
|
||||||
: Main.txtByteEditView.getText().substring(startPos).toLowerCase();
|
|
||||||
int index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
|
||||||
if (index == -1) {
|
|
||||||
txt = chckbxCaseSensitive.isSelected() ? Main.txtByteEditView.getText() : Main.txtByteEditView.getText().toLowerCase();
|
|
||||||
index = txt.indexOf(chckbxCaseSensitive.isSelected() ? toFind : toFind.toLowerCase());
|
|
||||||
startPos = 0;
|
|
||||||
if (index == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Main.txtByteEditView.select(startPos + index, startPos + index + toFind.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replaceFind() {
|
|
||||||
replace();
|
|
||||||
find();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replace() {
|
|
||||||
String txt = Main.txtByteEditView.getText();
|
|
||||||
int startPos = Main.txtByteEditView.getSelectionStart();
|
|
||||||
Main.txtByteEditView.replaceSelection(txtReplace.getText());
|
|
||||||
Main.txtByteEditView.select(startPos, startPos + txtReplace.getText().length());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replaceAll() {
|
|
||||||
String toFind = txtFind.getText();
|
|
||||||
String toReplace = txtReplace.getText();
|
|
||||||
String txt = Main.txtByteEditView.getText();
|
|
||||||
int prev = Main.txtByteEditView.getCaretPosition();
|
|
||||||
if (chckbxCaseSensitive.isSelected()) {
|
|
||||||
Main.txtByteEditView.replaceRange(txt.replace(toFind, toReplace), 0, txt.length());
|
|
||||||
} else {
|
|
||||||
Main.txtByteEditView.replaceRange(txt.replaceAll("(?i)" + Pattern.quote(toFind), toReplace), 0, txt.length());
|
|
||||||
}
|
|
||||||
Main.txtByteEditView.setCaretPosition(prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,689 @@
|
|||||||
|
package me.ByteEdit.edit;
|
||||||
|
|
||||||
|
import java.util.EmptyStackException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.InsnNode;
|
||||||
|
import org.objectweb.asm.tree.IntInsnNode;
|
||||||
|
import org.objectweb.asm.tree.LabelNode;
|
||||||
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
|
|
||||||
|
public class StackBasedCalculator implements Opcodes, Runnable {
|
||||||
|
|
||||||
|
private final InsnList insns;
|
||||||
|
private final Stack<Number> stack = new Stack<>();
|
||||||
|
private AbstractInsnNode start;
|
||||||
|
private int startIdx = -1;
|
||||||
|
private boolean isAtEnd = false;
|
||||||
|
|
||||||
|
public StackBasedCalculator(InsnList insns) {
|
||||||
|
this.insns = new InsnList();
|
||||||
|
|
||||||
|
HashMap<LabelNode, LabelNode> labelMap = new HashMap<>();
|
||||||
|
for (AbstractInsnNode node = insns.getFirst(); node != null; node = node.getNext()) {
|
||||||
|
if (node.getType() == AbstractInsnNode.LABEL) {
|
||||||
|
labelMap.put((LabelNode) node, new LabelNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AbstractInsnNode node = insns.getFirst(); node != null; node = node.getNext()) {
|
||||||
|
this.insns.add(node.clone(labelMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsnList get() {
|
||||||
|
return insns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!isAtEnd) {
|
||||||
|
out: {
|
||||||
|
AbstractInsnNode[] arr = insns.toArray();
|
||||||
|
for (int i = startIdx == -1 ? 0 : startIdx; i < arr.length; i++) {
|
||||||
|
if (!handle(arr[i]))
|
||||||
|
break out;
|
||||||
|
}
|
||||||
|
isAtEnd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handle(AbstractInsnNode node) {
|
||||||
|
try {
|
||||||
|
switch (node.getOpcode()) {
|
||||||
|
case ICONST_0:
|
||||||
|
stack.push(Integer.valueOf(0));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_1:
|
||||||
|
stack.push(Integer.valueOf(1));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_2:
|
||||||
|
stack.push(Integer.valueOf(2));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_3:
|
||||||
|
stack.push(Integer.valueOf(3));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_4:
|
||||||
|
stack.push(Integer.valueOf(4));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_5:
|
||||||
|
stack.push(Integer.valueOf(5));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case ICONST_M1:
|
||||||
|
stack.push(Integer.valueOf(-1));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case DCONST_0:
|
||||||
|
stack.push(Double.valueOf(0));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case DCONST_1:
|
||||||
|
stack.push(Double.valueOf(1));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case FCONST_0:
|
||||||
|
stack.push(Float.valueOf(0));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case FCONST_1:
|
||||||
|
stack.push(Float.valueOf(1));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case FCONST_2:
|
||||||
|
stack.push(Float.valueOf(2));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case LCONST_0:
|
||||||
|
stack.push(Long.valueOf(0));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case LCONST_1:
|
||||||
|
stack.push(Long.valueOf(1));
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case BIPUSH:
|
||||||
|
case SIPUSH:
|
||||||
|
stack.push(((IntInsnNode) node).operand);
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
break;
|
||||||
|
case D2F:
|
||||||
|
stack.push(((Double) stack.pop()).floatValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case D2I:
|
||||||
|
stack.push(((Double) stack.pop()).intValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case D2L:
|
||||||
|
stack.push(((Double) stack.pop()).longValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case F2D:
|
||||||
|
stack.push(((Float) stack.pop()).doubleValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case F2I:
|
||||||
|
stack.push(((Float) stack.pop()).intValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case F2L:
|
||||||
|
stack.push(((Float) stack.pop()).longValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case L2D:
|
||||||
|
stack.push(((Long) stack.pop()).doubleValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case L2F:
|
||||||
|
stack.push(((Long) stack.pop()).floatValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case L2I:
|
||||||
|
stack.push(((Long) stack.pop()).intValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case I2B:
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
case I2C:
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
case I2D:
|
||||||
|
stack.push(((Integer) stack.pop()).doubleValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case I2F:
|
||||||
|
stack.push(((Integer) stack.pop()).floatValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case I2L:
|
||||||
|
stack.push(((Integer) stack.pop()).longValue());
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case I2S:
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
case NOP:
|
||||||
|
break;
|
||||||
|
case LDC:
|
||||||
|
LdcInsnNode ldc = (LdcInsnNode) node;
|
||||||
|
if (ldc.cst instanceof Number) {
|
||||||
|
stack.push((Number) ldc.cst);
|
||||||
|
if (start == null)
|
||||||
|
start = node;
|
||||||
|
} else {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// long
|
||||||
|
case LADD: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom + top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LSUB: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom - top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LMUL: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom * top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LDIV: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom / top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LREM: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom % top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LNEG: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(-top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LAND: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom & top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LOR: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom | top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LXOR: {
|
||||||
|
long top = ((Long) stack.pop()).longValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom ^ top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LSHR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom >> top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LSHL: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom << top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case LUSHR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
long bottom = ((Long) stack.pop()).longValue();
|
||||||
|
stack.push(bottom >>> top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// int
|
||||||
|
case IADD: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom + top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case ISUB: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom - top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IMUL: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom * top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IDIV: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom / top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IREM: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom % top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case INEG: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(-top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IAND: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom & top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IOR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom | top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IXOR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom ^ top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case ISHR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom >> top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case ISHL: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom << top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case IUSHR: {
|
||||||
|
int top = ((Integer) stack.pop()).intValue();
|
||||||
|
int bottom = ((Integer) stack.pop()).intValue();
|
||||||
|
stack.push(bottom >>> top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// double
|
||||||
|
case DADD: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
double bottom = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(bottom + top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DSUB: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
double bottom = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(bottom - top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DMUL: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
double bottom = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(bottom * top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DDIV: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
double bottom = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(bottom / top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DREM: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
double bottom = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(bottom % top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DNEG: {
|
||||||
|
double top = ((Double) stack.pop()).doubleValue();
|
||||||
|
stack.push(-top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// float
|
||||||
|
case FADD: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
float bottom = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(bottom + top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case FSUB: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
float bottom = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(bottom - top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case FMUL: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
float bottom = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(bottom * top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case FDIV: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
float bottom = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(bottom / top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case FREM: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
float bottom = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(bottom % top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case FNEG: {
|
||||||
|
float top = ((Float) stack.pop()).floatValue();
|
||||||
|
stack.push(-top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// dup
|
||||||
|
case DUP: {
|
||||||
|
Number num = stack.pop();
|
||||||
|
if (num instanceof Double || num instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
stack.push(num);
|
||||||
|
stack.push(num);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DUP_X1: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long || top instanceof Double
|
||||||
|
|| top instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
stack.push(top);
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DUP_X2: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = stack.pop();
|
||||||
|
if (top instanceof Double || top instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Number bottom2 = null;
|
||||||
|
if (!(bottom instanceof Double || bottom instanceof Long)) {
|
||||||
|
bottom2 = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack.push(top);
|
||||||
|
if (bottom2 != null)
|
||||||
|
stack.push(bottom2);
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DUP2: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = null;
|
||||||
|
if (!(top instanceof Double || top instanceof Long)) {
|
||||||
|
bottom = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DUP2_X1: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = null;
|
||||||
|
if (!(top instanceof Double || top instanceof Long)) {
|
||||||
|
bottom = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number bottom2 = stack.pop();
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
stack.push(bottom2);
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case DUP2_X2: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = null;
|
||||||
|
if (!(top instanceof Double || top instanceof Long)) {
|
||||||
|
bottom = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number top2 = stack.pop();
|
||||||
|
Number bottom2 = null;
|
||||||
|
if (!(top2 instanceof Double || top2 instanceof Long)) {
|
||||||
|
bottom2 = stack.pop();
|
||||||
|
if (bottom2 instanceof Double || bottom2 instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
if (bottom2 != null)
|
||||||
|
stack.push(bottom2);
|
||||||
|
stack.push(top2);
|
||||||
|
if (bottom != null)
|
||||||
|
stack.push(bottom);
|
||||||
|
stack.push(top);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// stack
|
||||||
|
case POP:
|
||||||
|
stack.pop();
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case POP2:
|
||||||
|
stack.pop();
|
||||||
|
stack.pop();
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
case SWAP: {
|
||||||
|
Number top = stack.pop();
|
||||||
|
Number bottom = stack.pop();
|
||||||
|
if (bottom instanceof Double || bottom instanceof Long || top instanceof Double
|
||||||
|
|| top instanceof Long) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
stack.push(top);
|
||||||
|
stack.push(bottom);
|
||||||
|
change(node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (ClassCastException | EmptyStackException ex) {
|
||||||
|
error(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void error(AbstractInsnNode node) {
|
||||||
|
change(node.getPrevious());
|
||||||
|
stack.clear();
|
||||||
|
start = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void change(AbstractInsnNode node) {
|
||||||
|
if (start == null)
|
||||||
|
return;
|
||||||
|
int idx = insns.indexOf(start);
|
||||||
|
startIdx = idx;
|
||||||
|
int idx2 = insns.indexOf(node);
|
||||||
|
if (idx != idx2) {
|
||||||
|
for (int i = 0; i <= idx2 - idx; i++) {
|
||||||
|
insns.remove(insns.get(idx));
|
||||||
|
}
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
addNode(idx, stack.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack.clear();
|
||||||
|
start = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addNode(int idx, Number n) {
|
||||||
|
if (n instanceof Double) {
|
||||||
|
double val = n.doubleValue();
|
||||||
|
if (val == 0.0)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(DCONST_0));
|
||||||
|
else if (val == 1.0)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(DCONST_1));
|
||||||
|
else
|
||||||
|
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
|
||||||
|
} else if (n instanceof Float) {
|
||||||
|
float val = n.floatValue();
|
||||||
|
if (val == 0.0f)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_0));
|
||||||
|
else if (val == 1.0f)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_1));
|
||||||
|
else if (val == 2.0f)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(FCONST_2));
|
||||||
|
else
|
||||||
|
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
|
||||||
|
} else if (n instanceof Long) {
|
||||||
|
long val = n.longValue();
|
||||||
|
if (val == 0l)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(LCONST_0));
|
||||||
|
else if (val == 1l)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(LCONST_1));
|
||||||
|
else
|
||||||
|
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
|
||||||
|
} else if (n instanceof Integer) {
|
||||||
|
int val = n.intValue();
|
||||||
|
if (val == 0)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_0));
|
||||||
|
else if (val == 1)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_1));
|
||||||
|
else if (val == 2)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_2));
|
||||||
|
else if (val == 3)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_3));
|
||||||
|
else if (val == 4)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_4));
|
||||||
|
else if (val == 5)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_5));
|
||||||
|
else if (val == -1)
|
||||||
|
insns.insertBefore(insns.get(idx), new InsnNode(ICONST_M1));
|
||||||
|
else if (val == (byte) val)
|
||||||
|
insns.insertBefore(insns.get(idx), new IntInsnNode(BIPUSH, (byte) val));
|
||||||
|
else if (val == (short) val)
|
||||||
|
insns.insertBefore(insns.get(idx), new IntInsnNode(SIPUSH, (short) val));
|
||||||
|
else
|
||||||
|
insns.insertBefore(insns.get(idx), new LdcInsnNode(val));
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unexpected number: " + n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,8 +16,16 @@ public class StringContext {
|
|||||||
arrs = new String[amt];
|
arrs = new String[amt];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next(String s) {
|
public int next(String s) {
|
||||||
|
int i = idx;
|
||||||
len += (arrs[idx++] = s).length();
|
len += (arrs[idx++] = s).length();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int i, String s) {
|
||||||
|
if (arrs[i] != null)
|
||||||
|
len -= arrs[i].length();
|
||||||
|
len += (arrs[i] = s).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String finish() {
|
public String finish() {
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
package me.ByteEdit.edit;
|
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
import javax.swing.DefaultListModel;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
|
|
||||||
import me.ByteEdit.main.Main;
|
|
||||||
|
|
||||||
public class TypeOpenBox extends JFrame {
|
|
||||||
|
|
||||||
public JPanel contentPane;
|
|
||||||
public JTextField txtSearch;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the frame.
|
|
||||||
*/
|
|
||||||
public TypeOpenBox() {
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
setResizable(false);
|
|
||||||
setTitle("Open Type");
|
|
||||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
|
||||||
setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 200),
|
|
||||||
(int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 140), 400, 280);
|
|
||||||
contentPane = new JPanel();
|
|
||||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
|
||||||
setContentPane(contentPane);
|
|
||||||
contentPane.setLayout(null);
|
|
||||||
|
|
||||||
DefaultListModel<String> model = new DefaultListModel<>();
|
|
||||||
JList<String> list = new JList(model);
|
|
||||||
list.addListSelectionListener(new ListSelectionListener() {
|
|
||||||
|
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
|
||||||
String val = list.getSelectedValue();
|
|
||||||
if (val != null && !val.equals(Main.currentNodeName)) {
|
|
||||||
Main.selectFile(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
txtSearch = new JTextField();
|
|
||||||
txtSearch.addActionListener(new ActionListener() {
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
if (model.size() == 1) {
|
|
||||||
list.setSelectedIndex(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtSearch.getDocument().addDocumentListener(new DocumentListener() {
|
|
||||||
|
|
||||||
public void changedUpdate(DocumentEvent e) {
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeUpdate(DocumentEvent e) {
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void insertUpdate(DocumentEvent e) {
|
|
||||||
updateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateList() {
|
|
||||||
model.clear();
|
|
||||||
if (txtSearch.getText().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String search = txtSearch.getText().toLowerCase();
|
|
||||||
if (search.contains("/")) {
|
|
||||||
for (String s : Main.classNodes.keySet()) {
|
|
||||||
String className = s.substring(0, s.length() - 6);
|
|
||||||
if (!className.contains("$") && className.toLowerCase().startsWith(search)) {
|
|
||||||
model.addElement(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (String s : Main.classNodes.keySet()) {
|
|
||||||
String[] split = s.split("/");
|
|
||||||
String className = split[split.length - 1];
|
|
||||||
className = className.substring(0, className.length() - 6);
|
|
||||||
if (!className.contains("$") && className.toLowerCase().startsWith(search)) {
|
|
||||||
model.addElement(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
txtSearch.setBounds(10, 11, 374, 20);
|
|
||||||
contentPane.add(txtSearch);
|
|
||||||
txtSearch.setColumns(10);
|
|
||||||
|
|
||||||
JScrollPane scrollPane = new JScrollPane();
|
|
||||||
scrollPane.setBounds(10, 46, 374, 194);
|
|
||||||
contentPane.add(scrollPane);
|
|
||||||
|
|
||||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
scrollPane.setViewportView(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
|
public class ArchiveTreeModel extends DefaultTreeModel {
|
||||||
|
|
||||||
|
public final ArrayList<String> paths = new ArrayList<>();
|
||||||
|
private final HashMap<String, ClassNode> classNodes;
|
||||||
|
private final HashMap<String, byte[]> otherFiles;
|
||||||
|
private final ZipFile jar;
|
||||||
|
|
||||||
|
public boolean newCreated = false;
|
||||||
|
|
||||||
|
public ArchiveTreeModel(HashMap<String, ClassNode> classNodes, HashMap<String, byte[]> otherFiles) {
|
||||||
|
super(new ByteEditTreeNode("New"));
|
||||||
|
this.newCreated = true;
|
||||||
|
this.jar = null;
|
||||||
|
this.classNodes = classNodes;
|
||||||
|
this.otherFiles = otherFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchiveTreeModel(ZipFile jar, HashMap<String, ClassNode> classNodes, HashMap<String, byte[]> otherFiles) {
|
||||||
|
super(new ByteEditTreeNode(jar.getName().split(File.separator.equals("\\") ? "\\\\"
|
||||||
|
: File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length
|
||||||
|
- 1]));
|
||||||
|
this.newCreated = false;
|
||||||
|
this.jar = jar;
|
||||||
|
this.classNodes = classNodes;
|
||||||
|
this.otherFiles = otherFiles;
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
classNodes.clear();
|
||||||
|
otherFiles.clear();
|
||||||
|
Enumeration<? extends ZipEntry> enumeration = jar.entries();
|
||||||
|
while (enumeration.hasMoreElements()) {
|
||||||
|
ZipEntry next = enumeration.nextElement();
|
||||||
|
byte[] data = toByteArray(jar.getInputStream(next));
|
||||||
|
if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
|
||||||
|
&& (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) {
|
||||||
|
try {
|
||||||
|
ClassReader reader = new ClassReader(data);
|
||||||
|
ClassNode node = new ClassNode();
|
||||||
|
reader.accept(node, 0);
|
||||||
|
classNodes.put(node.name, node);
|
||||||
|
|
||||||
|
if ((next.getName().contains("/")
|
||||||
|
? (!Main.patternSlash
|
||||||
|
.split(next.getName())[Main.patternSlash.split(next.getName()).length - 1]
|
||||||
|
.contains("$"))
|
||||||
|
: (!next.getName().contains("$")))
|
||||||
|
|| (next.getName().startsWith("$") || next.getName().contains("$$")
|
||||||
|
|| next.getName().endsWith("$"))) {
|
||||||
|
paths.add(node.name + ".class");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
otherFiles.put(next.getName(), data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
otherFiles.put(next.getName(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jar.close();
|
||||||
|
refresh();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
classNodes.clear();
|
||||||
|
otherFiles.clear();
|
||||||
|
e.printStackTrace();
|
||||||
|
Main.showError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getSlashCount(String s) {
|
||||||
|
int count = 0;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '/')
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
setRoot(new ByteEditTreeNode(((ByteEditTreeNode) getRoot()).toString()));
|
||||||
|
Collections.sort(paths, String.CASE_INSENSITIVE_ORDER);
|
||||||
|
Collections.sort(paths, new Comparator<String>() {
|
||||||
|
public int compare(String s1, String s2) {
|
||||||
|
return getSlashCount(s2) - getSlashCount(s1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Windows-like sorting (like file explorer)
|
||||||
|
List<String> tmp = new ArrayList<>(paths);
|
||||||
|
|
||||||
|
List<String> folders = tmp.stream().filter(s -> {
|
||||||
|
int c = countSlashes(s, 50);
|
||||||
|
return c > 0 && c < 50;
|
||||||
|
}).map(s -> {
|
||||||
|
int idx = s.lastIndexOf('/');
|
||||||
|
if (idx == s.length() - 1)
|
||||||
|
idx = s.lastIndexOf('/', idx - 1);
|
||||||
|
if (idx == -1)
|
||||||
|
return s;
|
||||||
|
return s.substring(0, idx);
|
||||||
|
}).distinct().sorted(new Comparator<String>() {
|
||||||
|
@Override
|
||||||
|
public int compare(String s, String s2) {
|
||||||
|
// From String#compareToIgnoreCase(String)
|
||||||
|
int n = s.length();
|
||||||
|
int n2 = s2.length();
|
||||||
|
int n3 = Math.min(n, n2);
|
||||||
|
for (int i = 0; i < n3; ++i) {
|
||||||
|
char c;
|
||||||
|
char c2 = s.charAt(i);
|
||||||
|
if (c2 == (c = s2.charAt(i)) || (c2 = Character.toUpperCase(c2)) == (c = Character.toUpperCase(c))
|
||||||
|
|| (c2 = Character.toLowerCase(c2)) == (c = Character.toLowerCase(c)))
|
||||||
|
continue;
|
||||||
|
return c2 - c;
|
||||||
|
}
|
||||||
|
// Other way around
|
||||||
|
return n2 - n;
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
tmp.removeAll(folders);
|
||||||
|
tmp.addAll(0, folders);
|
||||||
|
|
||||||
|
for (String s : tmp) {
|
||||||
|
String[] elements = Main.patternSlash.split(s, 50);
|
||||||
|
if (elements.length >= 50) {
|
||||||
|
((ByteEditTreeNode) getRoot()).add(new ByteEditTreeNode(s, s));
|
||||||
|
} else {
|
||||||
|
ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot();
|
||||||
|
for (int i = 0; i < elements.length; i++) {
|
||||||
|
String token = elements[i];
|
||||||
|
ByteEditTreeNode nextNode = findNode(currentNode, token);
|
||||||
|
if (nextNode == null) {
|
||||||
|
nextNode = new ByteEditTreeNode(token, s);
|
||||||
|
currentNode.add(nextNode);
|
||||||
|
}
|
||||||
|
currentNode = nextNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) {
|
||||||
|
Enumeration<?> e = parent.children();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
ByteEditTreeNode element = (ByteEditTreeNode) e.nextElement();
|
||||||
|
if (element.getUserObject().equals(name)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countSlashes(String s, int max) {
|
||||||
|
int count = 0;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '/') {
|
||||||
|
count++;
|
||||||
|
if (count == max)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] toByteArray(final InputStream input) throws IOException {
|
||||||
|
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
while ((read = input.read(buffer)) != -1) {
|
||||||
|
output.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return output.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.event.TreeExpansionEvent;
|
||||||
|
import javax.swing.event.TreeExpansionListener;
|
||||||
|
import javax.swing.tree.TreeNode;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
|
public class FurtherExpandingTreeExpansionListener implements TreeExpansionListener {
|
||||||
|
|
||||||
|
private final JTree tree;
|
||||||
|
|
||||||
|
public FurtherExpandingTreeExpansionListener(JTree tree) {
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void treeExpanded(TreeExpansionEvent event) {
|
||||||
|
TreePath treePath = event.getPath();
|
||||||
|
Object expandedTreePathObject = treePath.getLastPathComponent();
|
||||||
|
if (!(expandedTreePathObject instanceof TreeNode))
|
||||||
|
return;
|
||||||
|
TreeNode expandedTreeNode = (TreeNode) expandedTreePathObject;
|
||||||
|
if (expandedTreeNode.getChildCount() == 1) {
|
||||||
|
TreeNode descendantTreeNode = expandedTreeNode.getChildAt(0);
|
||||||
|
if (descendantTreeNode.isLeaf())
|
||||||
|
return;
|
||||||
|
TreePath nextTreePath = treePath.pathByAddingChild(descendantTreeNode);
|
||||||
|
tree.expandPath(nextTreePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void treeCollapsed(TreeExpansionEvent event) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||||
|
import org.fife.ui.rtextarea.RTextArea;
|
||||||
|
import org.fife.ui.rtextarea.ToolTipSupplier;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.Assembler;
|
||||||
|
|
||||||
|
public class HugeStringsToolTips implements ToolTipSupplier {
|
||||||
|
|
||||||
|
private final RSyntaxTextArea txtByteEditView;
|
||||||
|
|
||||||
|
public HugeStringsToolTips(RSyntaxTextArea txtByteEditView) {
|
||||||
|
this.txtByteEditView = txtByteEditView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToolTipText(RTextArea textArea, MouseEvent e) {
|
||||||
|
int idx = textArea.viewToModel(e.getPoint());
|
||||||
|
if (idx < 0)
|
||||||
|
return null;
|
||||||
|
int subIdx = Math.max(idx - 15, 0);
|
||||||
|
int subLen = Math.min(30, textArea.getDocument().getLength() - subIdx);
|
||||||
|
if (subLen <= 0)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
String cut = textArea.getText(subIdx, subLen);
|
||||||
|
int hashIdx = -1;
|
||||||
|
for (int off = idx - subIdx; off >= 0; off--) {
|
||||||
|
if (cut.charAt(off) == '#') {
|
||||||
|
hashIdx = off;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hashIdx < 0) {
|
||||||
|
for (int off = idx - subIdx; off < cut.length(); off++) {
|
||||||
|
if (cut.charAt(off) == '#') {
|
||||||
|
hashIdx = off;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hashIdx < 0)
|
||||||
|
return null;
|
||||||
|
if (hashIdx >= 5 && cut.substring(hashIdx - 5, hashIdx).equals("ldc \"")) // ldc "#..."
|
||||||
|
return null;
|
||||||
|
int numLen = 1;
|
||||||
|
for (int i = hashIdx + 1; i < cut.length(); i++) {
|
||||||
|
if (!(cut.charAt(i) - '0' >= 0 && cut.charAt(i) - '0' <= 9)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
numLen++;
|
||||||
|
}
|
||||||
|
if (numLen < 2 || hashIdx > idx - subIdx || idx - subIdx - numLen >= hashIdx)
|
||||||
|
return null;
|
||||||
|
String hashNum = cut.substring(hashIdx, hashIdx + numLen);
|
||||||
|
|
||||||
|
String txt = txtByteEditView.getText();
|
||||||
|
int len = 0;
|
||||||
|
for (String asm : txt.split("\\/\\/ #Annotations:\n")) {
|
||||||
|
len += 19; // "\\/\\/ #Annotations:\n".length()
|
||||||
|
if (asm.isEmpty())
|
||||||
|
continue;
|
||||||
|
if (idx >= len && idx < len + asm.length()) {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new StringReader(asm))) {
|
||||||
|
String s;
|
||||||
|
while (!(s = reader.readLine()).startsWith("// #SourceFile: ")) {
|
||||||
|
}
|
||||||
|
while (!(s = reader.readLine()).equals("// #Fields")) {
|
||||||
|
if (s.startsWith("#")) {
|
||||||
|
String[] split = Assembler.SPACE.split(s, 2);
|
||||||
|
if (hashNum.equals(split[0].substring(0, split[0].length() - 1))) {
|
||||||
|
String toolTip = split[1];
|
||||||
|
if (toolTip.length() > 500)
|
||||||
|
toolTip = toolTip.substring(0, 500) + "...";
|
||||||
|
return toolTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e1) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += asm.length();
|
||||||
|
}
|
||||||
|
} catch (Exception e1) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+232
-426
@@ -1,5 +1,6 @@
|
|||||||
package me.ByteEdit.main;
|
package me.ByteEdit.main;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
@@ -15,28 +16,29 @@ import java.awt.dnd.DropTargetEvent;
|
|||||||
import java.awt.dnd.DropTargetListener;
|
import java.awt.dnd.DropTargetListener;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.awt.event.ItemListener;
|
||||||
import java.awt.event.KeyAdapter;
|
import java.awt.event.KeyAdapter;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.jar.JarOutputStream;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.DefaultComboBoxModel;
|
||||||
|
import javax.swing.JCheckBoxMenuItem;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
@@ -46,21 +48,16 @@ import javax.swing.JMenuBar;
|
|||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JRadioButtonMenuItem;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSplitPane;
|
import javax.swing.JSplitPane;
|
||||||
import javax.swing.JTree;
|
import javax.swing.JTree;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.event.TreeExpansionEvent;
|
|
||||||
import javax.swing.event.TreeExpansionListener;
|
|
||||||
import javax.swing.event.TreeSelectionEvent;
|
|
||||||
import javax.swing.event.TreeSelectionListener;
|
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
import javax.swing.text.BadLocationException;
|
import javax.swing.text.BadLocationException;
|
||||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
import javax.swing.tree.TreeNode;
|
|
||||||
import javax.swing.tree.TreePath;
|
|
||||||
import javax.swing.tree.TreeSelectionModel;
|
import javax.swing.tree.TreeSelectionModel;
|
||||||
|
|
||||||
import org.fife.ui.autocomplete.AutoCompletion;
|
import org.fife.ui.autocomplete.AutoCompletion;
|
||||||
@@ -73,23 +70,21 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
|||||||
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
|
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
|
||||||
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
|
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
|
||||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import me.ByteEdit.boxes.CompilationBox;
|
import me.ByteEdit.boxes.CompilationBox;
|
||||||
import me.ByteEdit.boxes.GlobalSearchBox;
|
import me.ByteEdit.boxes.GlobalSearchBox;
|
||||||
import me.ByteEdit.boxes.OptionBox;
|
|
||||||
import me.ByteEdit.boxes.RenameBox;
|
import me.ByteEdit.boxes.RenameBox;
|
||||||
import me.ByteEdit.boxes.SearchBox;
|
import me.ByteEdit.boxes.SearchBox;
|
||||||
import me.ByteEdit.boxes.ThemeBox;
|
import me.ByteEdit.boxes.ThemeBox;
|
||||||
import me.ByteEdit.boxes.TypeOpenBox;
|
import me.ByteEdit.boxes.TypeOpenBox;
|
||||||
import me.ByteEdit.boxes.UnicodeBox;
|
import me.ByteEdit.boxes.UnicodeBox;
|
||||||
|
import me.ByteEdit.decompiler.EnumDecompiler;
|
||||||
|
import me.ByteEdit.decompiler.SingleThreadedExecutor;
|
||||||
import me.ByteEdit.edit.Assembler;
|
import me.ByteEdit.edit.Assembler;
|
||||||
import me.ByteEdit.edit.Disassembler;
|
import me.ByteEdit.edit.HugeStrings;
|
||||||
import me.ByteEdit.edit.Disassembler.DisassembleTuple;
|
|
||||||
import me.ByteEdit.utils.ClassUtil;
|
import me.ByteEdit.utils.ClassUtil;
|
||||||
import me.ByteEdit.utils.OpcodesReverse;
|
import me.ByteEdit.utils.OpcodesReverse;
|
||||||
import me.ByteEdit.utils.UnicodeUtils;
|
import me.ByteEdit.utils.UnicodeUtils;
|
||||||
@@ -97,17 +92,23 @@ import me.ByteEdit.utils.UnicodeUtils;
|
|||||||
public class Main extends JFrame {
|
public class Main extends JFrame {
|
||||||
|
|
||||||
public static Main INSTANCE;
|
public static Main INSTANCE;
|
||||||
|
|
||||||
|
public static final Pattern patternSlash = Pattern.compile("/");
|
||||||
|
private static final Pattern patternRenameableField = Pattern
|
||||||
|
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
||||||
|
private static final Pattern patternRenameableMethod = Pattern
|
||||||
|
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?([^ ]+) (\\((?:\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;))*\\)[^ ]+) .*\\{");
|
||||||
|
|
||||||
private JPanel contentPane;
|
private JPanel contentPane;
|
||||||
private volatile boolean isChangingFile;
|
private volatile boolean isChangingFile;
|
||||||
public static File jarFile;
|
public static File jarFile;
|
||||||
public static HashMap<String, byte[]> OTHER_FILES = new HashMap<>();
|
public static final HashMap<String, ClassNode> classNodes = new HashMap<>();
|
||||||
public static HashMap<String, ClassNode> classNodes = new HashMap<>();
|
public static final HashMap<String, byte[]> otherFiles = new HashMap<>();
|
||||||
public static String currentNodeName;
|
public static String currentNodeName;
|
||||||
public static RSyntaxTextArea txtByteEditView;
|
public static RSyntaxTextArea txtByteEditView;
|
||||||
public static GlobalSearchBox globalSearchBox;
|
public static GlobalSearchBox globalSearchBox;
|
||||||
public static SearchBox searchBox;
|
public static SearchBox searchBox;
|
||||||
public static TypeOpenBox typeOpenBox;
|
public static TypeOpenBox typeOpenBox;
|
||||||
public static OptionBox optionBox;
|
|
||||||
public static UnicodeBox unicodeBox;
|
public static UnicodeBox unicodeBox;
|
||||||
public static RenameBox renameBox;
|
public static RenameBox renameBox;
|
||||||
public static CompilationBox compilationBox;
|
public static CompilationBox compilationBox;
|
||||||
@@ -116,15 +117,42 @@ public class Main extends JFrame {
|
|||||||
public static RTextScrollPane scrollPane_ByteEdit;
|
public static RTextScrollPane scrollPane_ByteEdit;
|
||||||
public static File saveFolder;
|
public static File saveFolder;
|
||||||
|
|
||||||
|
private JMenuBar menuBar;
|
||||||
|
private JMenu mnFile;
|
||||||
|
private JMenuItem mntmOpenJar;
|
||||||
|
private JMenuItem mntmSaveBytecode;
|
||||||
|
private JMenuItem mntmSaveJar;
|
||||||
|
private JMenu mnWindow;
|
||||||
|
private JMenuItem mntmThemes;
|
||||||
|
private JMenuItem mntmSearchMembers;
|
||||||
|
private JMenuItem mntmSearch;
|
||||||
|
private JMenuItem mntmOpenType;
|
||||||
|
private JMenuItem mntmUnicode;
|
||||||
|
private JMenuItem mntmCompiler;
|
||||||
|
private JMenu mnSearch;
|
||||||
|
private JMenu mnOptions;
|
||||||
|
private JCheckBoxMenuItem mntmComputeFrames;
|
||||||
|
private JCheckBoxMenuItem mntmComputeMax;
|
||||||
|
private JMenu mnStringLimit;
|
||||||
|
private JRadioButtonMenuItem rdbtnmntm0;
|
||||||
|
private JMenuItem rdbtnmntm100;
|
||||||
|
private JMenuItem rdbtnmntm1000;
|
||||||
|
private JMenuItem rdbtnmntm500;
|
||||||
|
private JMenuItem rdbtnmntm5000;
|
||||||
|
private JMenuItem rdbtnmntm10000;
|
||||||
|
public JCheckBoxMenuItem mntmMultithreaded;
|
||||||
|
private JMenu mnDeobfuscation;
|
||||||
|
public JCheckBoxMenuItem mntmNumbers;
|
||||||
|
|
||||||
public static final Object treeLock = new Object();
|
public static final Object treeLock = new Object();
|
||||||
|
|
||||||
|
public static EnumDecompiler decompiler = EnumDecompiler.BYTEEDIT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
EventQueue.invokeLater(new Runnable() {
|
EventQueue.invokeLater(() -> {
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
Main frame = new Main();
|
Main frame = new Main();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
@@ -132,15 +160,13 @@ public class Main extends JFrame {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a simple provider that adds some Java-related completions.
|
* Create a simple provider that adds some Java-related completions.
|
||||||
*/
|
*/
|
||||||
private CompletionProvider createCompletionProvider() {
|
private static CompletionProvider createCompletionProvider() {
|
||||||
DefaultCompletionProvider provider = new DefaultCompletionProvider();
|
DefaultCompletionProvider provider = new DefaultCompletionProvider();
|
||||||
for (int i = 0; i < 200; i++) {
|
for (int i = 0; i < 200; i++) {
|
||||||
String s = OpcodesReverse.reverseOpcode(i);
|
String s = OpcodesReverse.reverseOpcode(i);
|
||||||
@@ -196,7 +222,17 @@ public class Main extends JFrame {
|
|||||||
"// #Max: l:0 s:0\n\t// #TryCatch:\n\t// #LocalVars:\n\tpublic static method ()V {\n\t\treturn\n\t}",
|
"// #Max: l:0 s:0\n\t// #TryCatch:\n\t// #LocalVars:\n\tpublic static method ()V {\n\t\treturn\n\t}",
|
||||||
null, "<html><b><u>method</u></b><br>Creates an example method</html>"));
|
null, "<html><b><u>method</u></b><br>Creates an example method</html>"));
|
||||||
provider.addCompletion(new ShorthandCompletion(provider, "frame", "frame FULL l:[] s:[]", null,
|
provider.addCompletion(new ShorthandCompletion(provider, "frame", "frame FULL l:[] s:[]", null,
|
||||||
"<html><b><u>frame</u></b><br>Creates a stack map frame</html>"));
|
"<html><b><u>frame</u></b><br>Creates a stack map frame<br><br><b>Possible frames:</b><br><ul><li><code>SAME: same locals, empty stack</code></li><li><code>SAME1: same locals, stack has 1 entry</code></li><li><code>CHOP: same locals - k, empty stack</code></li><li><code>APPEND: same locals + k, empty stack</code></li><li><code>FULL: define locals, define stack</code></li></ul></html>"));
|
||||||
|
provider.addCompletion(new BasicCompletion(provider, "SAME", null,
|
||||||
|
"<html><b><u>Frames:</u></b><br><code>SAME</code><br><br><u>Locals:</u> same as previous<br><u>Stack:</u> empty</html>"));
|
||||||
|
provider.addCompletion(new BasicCompletion(provider, "SAME1", null,
|
||||||
|
"<html><b><u>Frames:</u></b><br><code>SAME1 [(type)]</code><br><br><u>Locals:</u> same as previous<br><u>Stack:</u> 1 entry</html>"));
|
||||||
|
provider.addCompletion(new BasicCompletion(provider, "CHOP", null,
|
||||||
|
"<html><b><u>Frames:</u></b><br><code>CHOP (int:k)</code><br><br><u>Locals:</u> removes the top <i>k</i> elements<br><u>Stack:</u> empty</html>"));
|
||||||
|
provider.addCompletion(new BasicCompletion(provider, "APPEND", null,
|
||||||
|
"<html><b><u>Frames:</u></b><br><code>APPEND [(type), (type), ...]</code><br><br><u>Locals:</u> adds the elements to the top<br><u>Stack:</u> empty</html>"));
|
||||||
|
provider.addCompletion(new BasicCompletion(provider, "FULL", null,
|
||||||
|
"<html><b><u>Frames:</u></b><br><code>FULL [(type), (type), ...] [(type), (type), ...]</code><br><i>first locals, then stack</i><br><br><u>Locals:</u> sets the elements<br><u>Stack:</u> sets the elements</html>"));
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +245,6 @@ public class Main extends JFrame {
|
|||||||
globalSearchBox = new GlobalSearchBox();
|
globalSearchBox = new GlobalSearchBox();
|
||||||
searchBox = new SearchBox();
|
searchBox = new SearchBox();
|
||||||
typeOpenBox = new TypeOpenBox();
|
typeOpenBox = new TypeOpenBox();
|
||||||
optionBox = new OptionBox();
|
|
||||||
unicodeBox = new UnicodeBox();
|
unicodeBox = new UnicodeBox();
|
||||||
renameBox = new RenameBox();
|
renameBox = new RenameBox();
|
||||||
compilationBox = new CompilationBox();
|
compilationBox = new CompilationBox();
|
||||||
@@ -217,7 +252,6 @@ public class Main extends JFrame {
|
|||||||
ThemeManager.registerFrames(globalSearchBox);
|
ThemeManager.registerFrames(globalSearchBox);
|
||||||
ThemeManager.registerFrames(searchBox);
|
ThemeManager.registerFrames(searchBox);
|
||||||
ThemeManager.registerFrames(typeOpenBox);
|
ThemeManager.registerFrames(typeOpenBox);
|
||||||
ThemeManager.registerFrames(optionBox);
|
|
||||||
ThemeManager.registerFrames(unicodeBox);
|
ThemeManager.registerFrames(unicodeBox);
|
||||||
ThemeManager.registerFrames(renameBox);
|
ThemeManager.registerFrames(renameBox);
|
||||||
ThemeManager.registerFrames(compilationBox);
|
ThemeManager.registerFrames(compilationBox);
|
||||||
@@ -254,7 +288,6 @@ public class Main extends JFrame {
|
|||||||
if (action == 0) {
|
if (action == 0) {
|
||||||
final File file = fileChooser.getSelectedFile();
|
final File file = fileChooser.getSelectedFile();
|
||||||
saveFolder = file.getParentFile();
|
saveFolder = file.getParentFile();
|
||||||
boolean shouldSave = false;
|
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
jarFile = file;
|
jarFile = file;
|
||||||
@@ -268,8 +301,9 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile), classNodes,
|
||||||
EventQueue.invokeLater(new Runnable() {
|
otherFiles);
|
||||||
|
EventQueue.invokeAndWait(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
tree.setModel(model);
|
tree.setModel(model);
|
||||||
@@ -278,7 +312,6 @@ public class Main extends JFrame {
|
|||||||
globalSearchBox.setVisible(false);
|
globalSearchBox.setVisible(false);
|
||||||
searchBox.setVisible(false);
|
searchBox.setVisible(false);
|
||||||
typeOpenBox.setVisible(false);
|
typeOpenBox.setVisible(false);
|
||||||
optionBox.setVisible(false);
|
|
||||||
unicodeBox.setVisible(false);
|
unicodeBox.setVisible(false);
|
||||||
renameBox.setVisible(false);
|
renameBox.setVisible(false);
|
||||||
compilationBox.setVisible(false);
|
compilationBox.setVisible(false);
|
||||||
@@ -287,7 +320,7 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,6 +369,62 @@ public class Main extends JFrame {
|
|||||||
mntmCompiler = new JMenuItem("Compiler");
|
mntmCompiler = new JMenuItem("Compiler");
|
||||||
mntmCompiler.addActionListener(e -> compilationBox.setVisible(true));
|
mntmCompiler.addActionListener(e -> compilationBox.setVisible(true));
|
||||||
mnWindow.add(mntmCompiler);
|
mnWindow.add(mntmCompiler);
|
||||||
|
|
||||||
|
mnOptions = new JMenu("Options");
|
||||||
|
menuBar.add(mnOptions);
|
||||||
|
|
||||||
|
mntmComputeFrames = new JCheckBoxMenuItem("Compute Frames");
|
||||||
|
mnOptions.add(mntmComputeFrames);
|
||||||
|
|
||||||
|
mntmComputeMax = new JCheckBoxMenuItem("Compute Max");
|
||||||
|
mnOptions.add(mntmComputeMax);
|
||||||
|
|
||||||
|
mntmMultithreaded = new JCheckBoxMenuItem("Multithreaded");
|
||||||
|
mntmMultithreaded.setSelected(true);
|
||||||
|
mnOptions.add(mntmMultithreaded);
|
||||||
|
|
||||||
|
mnStringLimit = new JMenu("Huge String Limit");
|
||||||
|
mnOptions.add(mnStringLimit);
|
||||||
|
|
||||||
|
rdbtnmntm0 = new JRadioButtonMenuItem("0");
|
||||||
|
rdbtnmntm0.addActionListener(e -> HugeStrings.THRESHOLD = 0);
|
||||||
|
mnStringLimit.add(rdbtnmntm0);
|
||||||
|
|
||||||
|
rdbtnmntm100 = new JRadioButtonMenuItem("100");
|
||||||
|
rdbtnmntm100.addActionListener(e -> HugeStrings.THRESHOLD = 100);
|
||||||
|
mnStringLimit.add(rdbtnmntm100);
|
||||||
|
|
||||||
|
rdbtnmntm500 = new JRadioButtonMenuItem("500");
|
||||||
|
rdbtnmntm500.addActionListener(e -> HugeStrings.THRESHOLD = 500);
|
||||||
|
mnStringLimit.add(rdbtnmntm500);
|
||||||
|
|
||||||
|
rdbtnmntm1000 = new JRadioButtonMenuItem("1000");
|
||||||
|
rdbtnmntm1000.addActionListener(e -> HugeStrings.THRESHOLD = 1000);
|
||||||
|
rdbtnmntm1000.setSelected(true);
|
||||||
|
mnStringLimit.add(rdbtnmntm1000);
|
||||||
|
|
||||||
|
rdbtnmntm5000 = new JRadioButtonMenuItem("5000");
|
||||||
|
rdbtnmntm5000.addActionListener(e -> HugeStrings.THRESHOLD = 5000);
|
||||||
|
mnStringLimit.add(rdbtnmntm5000);
|
||||||
|
|
||||||
|
rdbtnmntm10000 = new JRadioButtonMenuItem("10000");
|
||||||
|
rdbtnmntm10000.addActionListener(e -> HugeStrings.THRESHOLD = 10000);
|
||||||
|
mnStringLimit.add(rdbtnmntm10000);
|
||||||
|
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
group.add(rdbtnmntm0);
|
||||||
|
group.add(rdbtnmntm100);
|
||||||
|
group.add(rdbtnmntm500);
|
||||||
|
group.add(rdbtnmntm1000);
|
||||||
|
group.add(rdbtnmntm5000);
|
||||||
|
group.add(rdbtnmntm10000);
|
||||||
|
|
||||||
|
mnDeobfuscation = new JMenu("Deobfuscation");
|
||||||
|
menuBar.add(mnDeobfuscation);
|
||||||
|
|
||||||
|
mntmNumbers = new JCheckBoxMenuItem("Numbers");
|
||||||
|
mnDeobfuscation.add(mntmNumbers);
|
||||||
|
|
||||||
contentPane = new JPanel();
|
contentPane = new JPanel();
|
||||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
setContentPane(contentPane);
|
setContentPane(contentPane);
|
||||||
@@ -352,9 +441,8 @@ public class Main extends JFrame {
|
|||||||
new CurlyFoldParser(false, true));
|
new CurlyFoldParser(false, true));
|
||||||
tree = new JTree(new DefaultTreeModel(null));
|
tree = new JTree(new DefaultTreeModel(null));
|
||||||
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener());
|
tree.addTreeExpansionListener(new FurtherExpandingTreeExpansionListener(tree));
|
||||||
tree.addKeyListener(new KeyAdapter() {
|
tree.addKeyListener(new KeyAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
if (e.getKeyCode() == 116 && jarFile != null) { // F5
|
if (e.getKeyCode() == 116 && jarFile != null) { // F5
|
||||||
@@ -368,8 +456,9 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile), classNodes,
|
||||||
EventQueue.invokeLater(new Runnable() {
|
otherFiles);
|
||||||
|
EventQueue.invokeAndWait(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
tree.setModel(model);
|
tree.setModel(model);
|
||||||
@@ -378,7 +467,7 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,19 +483,19 @@ public class Main extends JFrame {
|
|||||||
String s = ((ByteEditTreeNode) tree.getSelectionPath().getLastPathComponent()).path;
|
String s = ((ByteEditTreeNode) tree.getSelectionPath().getLastPathComponent()).path;
|
||||||
if (JOptionPane.showConfirmDialog(INSTANCE, "Do you want to delete\n\"" + s + "\"?", "Delete",
|
if (JOptionPane.showConfirmDialog(INSTANCE, "Do you want to delete\n\"" + s + "\"?", "Delete",
|
||||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||||
String substr = s.substring(0, s.length() - 6);
|
s = s.substring(0, s.length() - 6);
|
||||||
ArrayList<String> toRemove = new ArrayList<>();
|
ArrayList<String> toRemove = new ArrayList<>();
|
||||||
for (String key : Main.classNodes.keySet()) {
|
for (String key : Main.classNodes.keySet()) {
|
||||||
if (key.contains("$")) {
|
if (key.contains("$")) {
|
||||||
String[] split = key.split("\\$");
|
String[] split = key.split("\\$");
|
||||||
if (split[0].equals(substr)) {
|
if (split[0].equals(s)) {
|
||||||
toRemove.add(key);
|
toRemove.add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArchiveTreeModel model = (ArchiveTreeModel) tree.getModel();
|
ArchiveTreeModel model = (ArchiveTreeModel) tree.getModel();
|
||||||
classNodes.remove(s);
|
classNodes.remove(s);
|
||||||
model.paths.remove(s);
|
model.paths.remove(s + ".class");
|
||||||
for (String rem : toRemove) {
|
for (String rem : toRemove) {
|
||||||
classNodes.remove(rem);
|
classNodes.remove(rem);
|
||||||
}
|
}
|
||||||
@@ -423,16 +512,8 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
scrollPane.setViewportView(tree);
|
scrollPane.setViewportView(tree);
|
||||||
tree.addTreeSelectionListener(new TreeSelectionListener() {
|
tree.addTreeSelectionListener(e -> SingleThreadedExecutor
|
||||||
|
.submit(() -> selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path)));
|
||||||
public void valueChanged(TreeSelectionEvent e) {
|
|
||||||
synchronized (treeLock) {
|
|
||||||
if (!isChangingFile) {
|
|
||||||
selectFile(((ByteEditTreeNode) e.getPath().getLastPathComponent()).path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
new DropTarget(tree, new DropTargetListener() {
|
new DropTarget(tree, new DropTargetListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -448,7 +529,7 @@ public class Main extends JFrame {
|
|||||||
for (int i = 0; i < flavors.length; i++) {
|
for (int i = 0; i < flavors.length; i++) {
|
||||||
if (flavors[i].isFlavorJavaFileListType()) {
|
if (flavors[i].isFlavorJavaFileListType()) {
|
||||||
dtde.acceptDrop(dtde.getDropAction());
|
dtde.acceptDrop(dtde.getDropAction());
|
||||||
java.util.List<File> files = (java.util.List<File>) tr.getTransferData(flavors[i]);
|
List<File> files = (List<File>) tr.getTransferData(flavors[i]);
|
||||||
final File file = files.get(0);
|
final File file = files.get(0);
|
||||||
if (file.getName().endsWith(".jar")) {
|
if (file.getName().endsWith(".jar")) {
|
||||||
jarFile = file;
|
jarFile = file;
|
||||||
@@ -462,8 +543,9 @@ public class Main extends JFrame {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
ArchiveTreeModel model = new ArchiveTreeModel(new JarFile(jarFile));
|
ArchiveTreeModel model = new ArchiveTreeModel(new ZipFile(jarFile),
|
||||||
EventQueue.invokeLater(new Runnable() {
|
classNodes, otherFiles);
|
||||||
|
EventQueue.invokeAndWait(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
tree.setModel(model);
|
tree.setModel(model);
|
||||||
@@ -472,7 +554,6 @@ public class Main extends JFrame {
|
|||||||
globalSearchBox.setVisible(false);
|
globalSearchBox.setVisible(false);
|
||||||
searchBox.setVisible(false);
|
searchBox.setVisible(false);
|
||||||
typeOpenBox.setVisible(false);
|
typeOpenBox.setVisible(false);
|
||||||
optionBox.setVisible(false);
|
|
||||||
unicodeBox.setVisible(false);
|
unicodeBox.setVisible(false);
|
||||||
renameBox.setVisible(false);
|
renameBox.setVisible(false);
|
||||||
compilationBox.setVisible(false);
|
compilationBox.setVisible(false);
|
||||||
@@ -481,7 +562,7 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,30 +601,12 @@ public class Main extends JFrame {
|
|||||||
txtByteEditView = new RSyntaxTextArea();
|
txtByteEditView = new RSyntaxTextArea();
|
||||||
ac.install(txtByteEditView);
|
ac.install(txtByteEditView);
|
||||||
txtByteEditView.setCodeFoldingEnabled(true);
|
txtByteEditView.setCodeFoldingEnabled(true);
|
||||||
|
txtByteEditView.setToolTipSupplier(new HugeStringsToolTips(txtByteEditView));
|
||||||
txtByteEditView.addKeyListener(new KeyAdapter() {
|
txtByteEditView.addKeyListener(new KeyAdapter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
if (e.getKeyCode() == 116 && currentNodeName != null) { // F5
|
||||||
try {
|
SingleThreadedExecutor.submit(Main::decompileCurrentNode);
|
||||||
ClassNode classNode = classNodes.get(currentNodeName);
|
|
||||||
int prev = txtByteEditView.getCaretPosition();
|
|
||||||
String dis = Disassembler.disassemble(classNode);
|
|
||||||
String substr = currentNodeName.substring(0, currentNodeName.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
|
||||||
if (key.contains("$")) {
|
|
||||||
String[] split = key.split("\\$");
|
|
||||||
if (split[0].equals(substr)) {
|
|
||||||
dis += "\n" + Disassembler.disassemble(classNodes.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txtByteEditView.setText(dis);
|
|
||||||
if (dis.length() > prev)
|
|
||||||
txtByteEditView.setCaretPosition(prev);
|
|
||||||
} catch (Exception e2) {
|
|
||||||
e2.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -551,7 +614,6 @@ public class Main extends JFrame {
|
|||||||
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlT = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_DOWN_MASK);
|
||||||
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlS = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK);
|
||||||
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlG = KeyStroke.getKeyStroke(KeyEvent.VK_G, KeyEvent.CTRL_DOWN_MASK);
|
||||||
KeyStroke ctrlO = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK);
|
|
||||||
KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlU = KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK);
|
||||||
KeyStroke ctrlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlR = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK);
|
||||||
KeyStroke ctrlE = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK);
|
KeyStroke ctrlE = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK);
|
||||||
@@ -574,8 +636,6 @@ public class Main extends JFrame {
|
|||||||
typeOpenBox.txtSearch.requestFocusInWindow();
|
typeOpenBox.txtSearch.requestFocusInWindow();
|
||||||
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
|
typeOpenBox.txtSearch.select(0, typeOpenBox.txtSearch.getText().length());
|
||||||
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
}, ctrlT, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
txtByteEditView.registerKeyboardAction(e -> optionBox.setVisible(true), ctrlO,
|
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
||||||
txtByteEditView.registerKeyboardAction(e -> unicodeBox.setVisible(true), ctrlU,
|
txtByteEditView.registerKeyboardAction(e -> unicodeBox.setVisible(true), ctrlU,
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
txtByteEditView.registerKeyboardAction(e -> compilationBox.setVisible(true), ctrlE,
|
txtByteEditView.registerKeyboardAction(e -> compilationBox.setVisible(true), ctrlE,
|
||||||
@@ -583,114 +643,63 @@ public class Main extends JFrame {
|
|||||||
// specific
|
// specific
|
||||||
tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
|
tree.registerKeyboardAction(e -> save(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
|
txtByteEditView.registerKeyboardAction(e -> saveCurrentClassNode(), ctrlS, JComponent.WHEN_FOCUSED);
|
||||||
txtByteEditView.registerKeyboardAction(e -> {
|
txtByteEditView.registerKeyboardAction(e -> renameSelected(), ctrlR, JComponent.WHEN_FOCUSED);
|
||||||
try {
|
|
||||||
goToSelected();
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}, ctrlG, JComponent.WHEN_FOCUSED);
|
|
||||||
txtByteEditView.registerKeyboardAction(e -> {
|
|
||||||
try {
|
|
||||||
renameSelected();
|
|
||||||
} catch (BadLocationException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}, ctrlR, JComponent.WHEN_FOCUSED);
|
|
||||||
txtByteEditView.setEditable(true);
|
txtByteEditView.setEditable(true);
|
||||||
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
txtByteEditView.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA_DISASSEMBLE);
|
||||||
txtByteEditView.setCodeFoldingEnabled(true);
|
txtByteEditView.setCodeFoldingEnabled(true);
|
||||||
scrollPane_ByteEdit = new RTextScrollPane();
|
scrollPane_ByteEdit = new RTextScrollPane();
|
||||||
ThemeManager.registerTextArea(txtByteEditView);
|
ThemeManager.registerTextArea(txtByteEditView);
|
||||||
|
|
||||||
splitPane.setRightComponent(scrollPane_ByteEdit);
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
|
panel.add(scrollPane_ByteEdit, BorderLayout.CENTER);
|
||||||
|
final JComboBox<String> decompilerMode = new JComboBox<>();
|
||||||
|
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||||
|
Stream.of(EnumDecompiler.values()).forEach(model::addElement);
|
||||||
|
decompilerMode.setModel(model);
|
||||||
|
decompilerMode.addItemListener(new ItemListener() {
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
EnumDecompiler selected = (EnumDecompiler) e.getItem();
|
||||||
|
SingleThreadedExecutor.submit(() -> {
|
||||||
|
decompiler = selected;
|
||||||
|
decompileCurrentNode();
|
||||||
|
try {
|
||||||
|
EventQueue.invokeAndWait(() -> {
|
||||||
|
synchronized (treeLock) {
|
||||||
|
txtByteEditView.setCaretPosition(0);
|
||||||
|
try {
|
||||||
|
txtByteEditView.setSyntaxEditingStyle(decompiler.getSyntaxStyle());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
}
|
||||||
|
txtByteEditView.setEditable(decompiler.isEditable());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
panel.add(decompilerMode, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
splitPane.setRightComponent(panel);
|
||||||
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
scrollPane_ByteEdit.setViewportView(txtByteEditView);
|
||||||
scrollPane_ByteEdit.setLineNumbersEnabled(true);
|
scrollPane_ByteEdit.setLineNumbersEnabled(true);
|
||||||
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
scrollPane_ByteEdit.setFoldIndicatorEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Pattern jumpableInstructionPattern = Pattern.compile("^\t\t(?!//|\t+).+ .+");
|
public void renameSelected() {
|
||||||
|
try {
|
||||||
public void goToSelected() throws BadLocationException {
|
|
||||||
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
||||||
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
||||||
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
||||||
if (!jumpableInstructionPattern.matcher(line).matches()) {
|
Matcher m = patternRenameableField.matcher(line);
|
||||||
return;
|
|
||||||
}
|
|
||||||
line = line.substring(2);
|
|
||||||
if (line.startsWith("invoke")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String desc = UnicodeUtils.unescape(split[1]);
|
|
||||||
String target = split[2];
|
|
||||||
int index = target.lastIndexOf("/");
|
|
||||||
String className = UnicodeUtils.unescape(target.substring(0, index));
|
|
||||||
String methodName = UnicodeUtils.unescape(target.substring(index + 1));
|
|
||||||
ClassNode classNode = classNodes.get(getFullName(className));
|
|
||||||
if (classNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (MethodNode mn : classNode.methods) {
|
|
||||||
if (mn.name.equals(methodName) && mn.desc.equals(desc)) {
|
|
||||||
while (classNode.outerClass != null) {
|
|
||||||
classNode = classNodes.get(getFullName(classNode.outerClass));
|
|
||||||
}
|
|
||||||
int lineFound = selectFileWithSearch(getFullName(classNode.name), mn);
|
|
||||||
if (lineFound != -1) {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (line.startsWith("new ")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String className = UnicodeUtils.unescape(split[1]);
|
|
||||||
ClassNode classNode = classNodes.get(getFullName(className));
|
|
||||||
if (classNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectFile(getFullName(className));
|
|
||||||
} else if (line.startsWith("getstatic ") || line.startsWith("putstatic ") || line.startsWith("getfield ")
|
|
||||||
|| line.startsWith("putfield ")) {
|
|
||||||
String[] split = line.split(" ");
|
|
||||||
String desc = UnicodeUtils.unescape(split[1]);
|
|
||||||
String target = split[2];
|
|
||||||
int index = target.lastIndexOf("/");
|
|
||||||
String className = UnicodeUtils.unescape(target.substring(0, index));
|
|
||||||
String fieldName = UnicodeUtils.unescape(target.substring(index + 1));
|
|
||||||
ClassNode classNode = classNodes.get(getFullName(className));
|
|
||||||
if (classNode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (FieldNode fn : classNode.fields) {
|
|
||||||
if (fn.name.equals(fieldName) && fn.desc.equals(desc)) {
|
|
||||||
while (classNode.outerClass != null) {
|
|
||||||
classNode = classNodes.get(getFullName(classNode.outerClass));
|
|
||||||
}
|
|
||||||
int lineFound = selectFileWithSearch(getFullName(classNode.name), fn);
|
|
||||||
if (lineFound != -1) {
|
|
||||||
Main.txtByteEditView.setCaretPosition(Main.txtByteEditView.getLineStartOffset(lineFound));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Pattern renameableFieldPattern = Pattern
|
|
||||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?(\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;)) ([^ ]+) ?.*");
|
|
||||||
private final Pattern renameableMethodPattern = Pattern
|
|
||||||
.compile("^\t(?:[a-z]+ |0x[0-9a-fA-F]+ )*?([^ ]+) (\\((?:\\[*(?:V|Z|C|B|S|I|F|J|D|L.+?;))*\\)[^ ]+) .*\\{");
|
|
||||||
|
|
||||||
public void renameSelected() throws BadLocationException {
|
|
||||||
int lineStart = txtByteEditView.getLineStartOffsetOfCurrentLine();
|
|
||||||
int lineEnd = txtByteEditView.getLineEndOffsetOfCurrentLine() - 1;
|
|
||||||
String line = txtByteEditView.getText(lineStart, lineEnd - lineStart);
|
|
||||||
Matcher m = renameableFieldPattern.matcher(line);
|
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
setRenameInfo(m, lineEnd);
|
setRenameInfo(m, lineEnd);
|
||||||
} else {
|
} else {
|
||||||
m = renameableMethodPattern.matcher(line);
|
m = patternRenameableMethod.matcher(line);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
if (ClassUtil.isObjectClassMethod(m.group(1), m.group(2), false)) {
|
if (ClassUtil.isObjectClassMethod(m.group(1), m.group(2), false)) {
|
||||||
JOptionPane.showMessageDialog(null, "This method can not be renamed!", "Error!",
|
JOptionPane.showMessageDialog(null, "This method can not be renamed!", "Error!",
|
||||||
@@ -700,6 +709,9 @@ public class Main extends JFrame {
|
|||||||
setRenameInfo(m, lineEnd);
|
setRenameInfo(m, lineEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (BadLocationException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRenameInfo(Matcher m, int lineEnd) throws BadLocationException {
|
public void setRenameInfo(Matcher m, int lineEnd) throws BadLocationException {
|
||||||
@@ -721,10 +733,12 @@ public class Main extends JFrame {
|
|||||||
if (s.contains(" extends "))
|
if (s.contains(" extends "))
|
||||||
s = s.substring(0, s.lastIndexOf(" extends "));
|
s = s.substring(0, s.lastIndexOf(" extends "));
|
||||||
String[] split = s.split(" ");
|
String[] split = s.split(" ");
|
||||||
String className = UnicodeUtils.unescape(split[split.length - 1]);
|
String className = UnicodeUtils.unescape(null, split[split.length - 1], true);
|
||||||
renameBox.className = className;
|
renameBox.className = className;
|
||||||
String name = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(2) : m.group(1));
|
String name = UnicodeUtils.unescape(null, m.pattern() == patternRenameableField ? m.group(2) : m.group(1),
|
||||||
String desc = UnicodeUtils.unescape(m.pattern() == renameableFieldPattern ? m.group(1) : m.group(2));
|
true);
|
||||||
|
String desc = UnicodeUtils.unescape(null, m.pattern() == patternRenameableField ? m.group(1) : m.group(2),
|
||||||
|
true);
|
||||||
renameBox.name = name;
|
renameBox.name = name;
|
||||||
renameBox.desc = desc;
|
renameBox.desc = desc;
|
||||||
renameBox.txtName.setText(name);
|
renameBox.txtName.setText(name);
|
||||||
@@ -734,7 +748,7 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveCurrentClassNode() {
|
private static void saveCurrentClassNode() {
|
||||||
String txt = txtByteEditView.getText();
|
String txt = txtByteEditView.getText();
|
||||||
for (String s : txt.split("\\/\\/ #Annotations:\n")) {
|
for (String s : txt.split("\\/\\/ #Annotations:\n")) {
|
||||||
if (s.isEmpty())
|
if (s.isEmpty())
|
||||||
@@ -743,15 +757,15 @@ public class Main extends JFrame {
|
|||||||
if (node == null) {
|
if (node == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (classNodes.replace(getFullName(node.name), node) == null) {
|
if (classNodes.replace(node.name, node) == null) {
|
||||||
classNodes.put(getFullName(node.name), node);
|
classNodes.put(node.name, node);
|
||||||
ArchiveTreeModel model;
|
ArchiveTreeModel model;
|
||||||
if (tree.getModel().getClass().equals(DefaultTreeModel.class)) {
|
if (tree.getModel().getClass().equals(DefaultTreeModel.class)) {
|
||||||
tree.setModel(model = new ArchiveTreeModel());
|
tree.setModel(model = new ArchiveTreeModel(classNodes, otherFiles));
|
||||||
} else {
|
} else {
|
||||||
model = (ArchiveTreeModel) tree.getModel();
|
model = (ArchiveTreeModel) tree.getModel();
|
||||||
}
|
}
|
||||||
String name = getFullName(node.name);
|
String name = node.name + ".class";
|
||||||
if (name.contains("/") ? (!name.split("/")[name.split("/").length - 1].contains("$"))
|
if (name.contains("/") ? (!name.split("/")[name.split("/").length - 1].contains("$"))
|
||||||
: (!name.contains("$"))) {
|
: (!name.contains("$"))) {
|
||||||
model.paths.add(name);
|
model.paths.add(name);
|
||||||
@@ -764,41 +778,34 @@ public class Main extends JFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int selectFileWithSearch(String s, Object nodeToFind) {
|
public static void decompileCurrentNode() {
|
||||||
if (s != null && s.endsWith(".class")) {
|
if (currentNodeName == null)
|
||||||
currentNodeName = s;
|
return;
|
||||||
int lineFound = -1;
|
try {
|
||||||
ClassNode classNode = classNodes.get(s);
|
EnumDecompiler decompiler = Main.decompiler;
|
||||||
if (classNode == null)
|
String current = currentNodeName;
|
||||||
return -1;
|
ClassNode classNode = classNodes.get(current);
|
||||||
String dis = "";
|
int prev = txtByteEditView.getCaretPosition();
|
||||||
DisassembleTuple tuple = Disassembler.disassemble(classNode, nodeToFind);
|
String dis = decompiler.getDecompiler().decompile(classNode, Main.classNodes);
|
||||||
if (tuple.getLine() != -1) {
|
EventQueue.invokeAndWait(() -> {
|
||||||
lineFound = dis.split("\\n").length + tuple.getLine() - 1;
|
synchronized (treeLock) {
|
||||||
}
|
|
||||||
dis += tuple.getDisassembly();
|
|
||||||
String substr = s.substring(0, s.length() - 6);
|
|
||||||
for (String key : Main.classNodes.keySet()) {
|
|
||||||
if (key.contains("$")) {
|
|
||||||
String[] split = key.split("\\$");
|
|
||||||
if (split[0].equals(substr)) {
|
|
||||||
tuple = Disassembler.disassemble(classNodes.get(key), nodeToFind);
|
|
||||||
if (tuple.getLine() != -1) {
|
|
||||||
lineFound = dis.split("\\n").length + tuple.getLine() + 1;
|
|
||||||
}
|
|
||||||
dis += "\n" + tuple.getDisassembly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txtByteEditView.setText(dis);
|
txtByteEditView.setText(dis);
|
||||||
txtByteEditView.setCaretPosition(0);
|
if (dis.length() > prev)
|
||||||
return lineFound;
|
txtByteEditView.setCaretPosition(prev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e2) {
|
||||||
|
e2.printStackTrace();
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int selectFile(String s) {
|
public static void selectFile(String s) {
|
||||||
return selectFileWithSearch(s, null);
|
if (s != null && s.endsWith(".class")) {
|
||||||
|
s = s.substring(0, s.length() - 6);
|
||||||
|
currentNodeName = s;
|
||||||
|
decompileCurrentNode();
|
||||||
|
txtByteEditView.setCaretPosition(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
@@ -824,7 +831,6 @@ public class Main extends JFrame {
|
|||||||
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
|
int dialogResult = JOptionPane.showConfirmDialog(null, "This file already exists! Overwrite it?",
|
||||||
"Warning", JOptionPane.YES_NO_OPTION);
|
"Warning", JOptionPane.YES_NO_OPTION);
|
||||||
if (dialogResult == JOptionPane.YES_OPTION) {
|
if (dialogResult == JOptionPane.YES_OPTION) {
|
||||||
save(file, classNodes.values());
|
|
||||||
shouldSave = true;
|
shouldSave = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -847,14 +853,16 @@ public class Main extends JFrame {
|
|||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
synchronized (treeLock) {
|
||||||
save(file, classNodes.values());
|
save(file, classNodes.values());
|
||||||
EventQueue.invokeLater(new Runnable() {
|
try {
|
||||||
|
EventQueue.invokeAndWait(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (treeLock) {
|
|
||||||
isChangingFile = false;
|
isChangingFile = false;
|
||||||
Main.this.setTitle("ByteEdit");
|
Main.this.setTitle("ByteEdit");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
@@ -868,7 +876,7 @@ public class Main extends JFrame {
|
|||||||
|
|
||||||
public void save(File jar, Collection<ClassNode> classes) {
|
public void save(File jar, Collection<ClassNode> classes) {
|
||||||
try {
|
try {
|
||||||
final JarOutputStream output = new JarOutputStream(new FileOutputStream(jar));
|
final ZipOutputStream output = new ZipOutputStream(new FileOutputStream(jar));
|
||||||
if (tree.getModel().getClass().equals(DefaultTreeModel.class)
|
if (tree.getModel().getClass().equals(DefaultTreeModel.class)
|
||||||
|| ((ArchiveTreeModel) tree.getModel()).newCreated) {
|
|| ((ArchiveTreeModel) tree.getModel()).newCreated) {
|
||||||
int acc = ClassUtil.ACC_PUBLIC | ClassUtil.ACC_STATIC;
|
int acc = ClassUtil.ACC_PUBLIC | ClassUtil.ACC_STATIC;
|
||||||
@@ -887,28 +895,28 @@ public class Main extends JFrame {
|
|||||||
if (name != null && !name.isEmpty()) {
|
if (name != null && !name.isEmpty()) {
|
||||||
String val = "Manifest-Version: 1.0\n" + "Class-Path: .\n" + "Main-Class: " + name.replace('/', '.')
|
String val = "Manifest-Version: 1.0\n" + "Class-Path: .\n" + "Main-Class: " + name.replace('/', '.')
|
||||||
+ "\n\n";
|
+ "\n\n";
|
||||||
OTHER_FILES.put("META-INF/MANIFEST.MF", val.getBytes());
|
otherFiles.put("META-INF/MANIFEST.MF", val.getBytes());
|
||||||
}
|
}
|
||||||
if (tree.getModel() instanceof ArchiveTreeModel)
|
if (tree.getModel() instanceof ArchiveTreeModel)
|
||||||
((ArchiveTreeModel) tree.getModel()).newCreated = false;
|
((ArchiveTreeModel) tree.getModel()).newCreated = false;
|
||||||
}
|
}
|
||||||
for (Entry<String, byte[]> entry : OTHER_FILES.entrySet()) {
|
for (Entry<String, byte[]> entry : otherFiles.entrySet()) {
|
||||||
JarEntry ent = new JarEntry(entry.getKey());
|
ZipEntry ent = new ZipEntry(entry.getKey());
|
||||||
output.putNextEntry(ent);
|
output.putNextEntry(ent);
|
||||||
output.write(entry.getValue());
|
output.write(entry.getValue());
|
||||||
output.closeEntry();
|
output.closeEntry();
|
||||||
}
|
}
|
||||||
int computeFlags = 0;
|
int computeFlags = 0;
|
||||||
if (optionBox.chckbxComputeFrames.isSelected()) {
|
if (mntmComputeFrames.isSelected()) {
|
||||||
computeFlags |= ClassWriter.COMPUTE_FRAMES;
|
computeFlags |= ClassWriter.COMPUTE_FRAMES;
|
||||||
}
|
}
|
||||||
if (optionBox.chckbxComputeMax.isSelected()) {
|
if (mntmComputeMax.isSelected()) {
|
||||||
computeFlags |= ClassWriter.COMPUTE_MAXS;
|
computeFlags |= ClassWriter.COMPUTE_MAXS;
|
||||||
}
|
}
|
||||||
for (ClassNode node : classes) {
|
for (ClassNode node : classes) {
|
||||||
ClassWriter writer = new ClassWriter(computeFlags);
|
ClassWriter writer = new ClassWriter(computeFlags);
|
||||||
node.accept(writer);
|
node.accept(writer);
|
||||||
output.putNextEntry(new JarEntry(getFullName(node.name)));
|
output.putNextEntry(new ZipEntry(node.name + ".class"));
|
||||||
output.write(writer.toByteArray());
|
output.write(writer.toByteArray());
|
||||||
output.closeEntry();
|
output.closeEntry();
|
||||||
}
|
}
|
||||||
@@ -934,206 +942,4 @@ public class Main extends JFrame {
|
|||||||
public static void showError(String s) {
|
public static void showError(String s) {
|
||||||
JOptionPane.showMessageDialog(INSTANCE, s, "Error!", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(INSTANCE, s, "Error!", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getFullName(String s) {
|
|
||||||
return s + ".class";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern SLASH = Pattern.compile("/");
|
|
||||||
private JMenuBar menuBar;
|
|
||||||
private JMenu mnFile;
|
|
||||||
private JMenuItem mntmOpenJar;
|
|
||||||
private JMenuItem mntmSaveBytecode;
|
|
||||||
private JMenuItem mntmSaveJar;
|
|
||||||
private JMenu mnWindow;
|
|
||||||
private JMenuItem mntmThemes;
|
|
||||||
private JMenuItem mntmSearchMembers;
|
|
||||||
private JMenuItem mntmSearch;
|
|
||||||
private JMenuItem mntmOpenType;
|
|
||||||
private JMenuItem mntmUnicode;
|
|
||||||
private JMenuItem mntmCompiler;
|
|
||||||
private JMenu mnSearch;
|
|
||||||
|
|
||||||
class ArchiveTreeModel extends DefaultTreeModel {
|
|
||||||
|
|
||||||
public ArrayList<String> paths = new ArrayList<>();
|
|
||||||
public boolean newCreated = false;
|
|
||||||
|
|
||||||
public ArchiveTreeModel() {
|
|
||||||
super(new ByteEditTreeNode("New"));
|
|
||||||
newCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArchiveTreeModel(JarFile jar) {
|
|
||||||
super(new ByteEditTreeNode(jar.getName().split(File.separator.equals("\\") ? "\\\\"
|
|
||||||
: File.separator)[jar.getName().split(File.separator.equals("\\") ? "\\\\" : File.separator).length
|
|
||||||
- 1]));
|
|
||||||
try {
|
|
||||||
classNodes.clear();
|
|
||||||
OTHER_FILES.clear();
|
|
||||||
Enumeration<JarEntry> enumeration = jar.entries();
|
|
||||||
while (enumeration.hasMoreElements()) {
|
|
||||||
JarEntry next = enumeration.nextElement();
|
|
||||||
byte[] data = toByteArray(jar.getInputStream(next));
|
|
||||||
if (next.getSize() != 0 && !next.getName().startsWith("META-INF")
|
|
||||||
&& (next.getName().endsWith(".class") || next.getName().endsWith(".class/"))) {
|
|
||||||
try {
|
|
||||||
ClassReader reader = new ClassReader(data);
|
|
||||||
ClassNode node = new ClassNode();
|
|
||||||
reader.accept(node, 0);
|
|
||||||
classNodes.put(getFullName(node.name), node);
|
|
||||||
|
|
||||||
if ((next.getName().contains("/")
|
|
||||||
? (!SLASH.split(next.getName())[SLASH.split(next.getName()).length - 1]
|
|
||||||
.contains("$"))
|
|
||||||
: (!next.getName().contains("$")))
|
|
||||||
|| (next.getName().startsWith("$") || next.getName().contains("$$")
|
|
||||||
|| next.getName().endsWith("$"))) {
|
|
||||||
paths.add(getFullName(node.name));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
OTHER_FILES.put(next.getName(), data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
OTHER_FILES.put(next.getName(), data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jar.close();
|
|
||||||
refresh();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
classNodes.clear();
|
|
||||||
OTHER_FILES.clear();
|
|
||||||
e.printStackTrace();
|
|
||||||
showError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSlashCount(String s) {
|
|
||||||
int count = 0;
|
|
||||||
for (char c : s.toCharArray()) {
|
|
||||||
if (c == '/')
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refresh() {
|
|
||||||
setRoot(new ByteEditTreeNode(((ByteEditTreeNode) getRoot()).toString()));
|
|
||||||
Collections.sort(paths, String.CASE_INSENSITIVE_ORDER);
|
|
||||||
Collections.sort(paths, new Comparator<String>() {
|
|
||||||
public int compare(String s1, String s2) {
|
|
||||||
return getSlashCount(s2) - getSlashCount(s1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Windows-like sorting (like file explorer)
|
|
||||||
List<String> tmp = new ArrayList<>(paths);
|
|
||||||
|
|
||||||
List<String> folders = tmp.stream().filter(s -> {
|
|
||||||
int c = countSlashes(s, 50);
|
|
||||||
return c > 0 && c < 50;
|
|
||||||
}).map(s -> {
|
|
||||||
int idx = s.lastIndexOf('/');
|
|
||||||
if (idx == s.length() - 1)
|
|
||||||
idx = s.lastIndexOf('/', idx - 1);
|
|
||||||
if (idx == -1)
|
|
||||||
return s;
|
|
||||||
return s.substring(0, idx);
|
|
||||||
}).distinct().sorted(new Comparator<String>() {
|
|
||||||
@Override
|
|
||||||
public int compare(String s, String s2) {
|
|
||||||
// From String#compareToIgnoreCase(String)
|
|
||||||
int n = s.length();
|
|
||||||
int n2 = s2.length();
|
|
||||||
int n3 = Math.min(n, n2);
|
|
||||||
for (int i = 0; i < n3; ++i) {
|
|
||||||
char c;
|
|
||||||
char c2 = s.charAt(i);
|
|
||||||
if (c2 == (c = s2.charAt(i))
|
|
||||||
|| (c2 = Character.toUpperCase(c2)) == (c = Character.toUpperCase(c))
|
|
||||||
|| (c2 = Character.toLowerCase(c2)) == (c = Character.toLowerCase(c)))
|
|
||||||
continue;
|
|
||||||
return c2 - c;
|
|
||||||
}
|
|
||||||
// Other way around
|
|
||||||
return n2 - n;
|
|
||||||
}
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
|
|
||||||
tmp.removeAll(folders);
|
|
||||||
tmp.addAll(0, folders);
|
|
||||||
|
|
||||||
for (String s : tmp) {
|
|
||||||
String[] elements = SLASH.split(s, 50);
|
|
||||||
if (elements.length >= 50) {
|
|
||||||
((ByteEditTreeNode) getRoot()).add(new ByteEditTreeNode(s, s));
|
|
||||||
} else {
|
|
||||||
ByteEditTreeNode currentNode = (ByteEditTreeNode) getRoot();
|
|
||||||
for (int i = 0; i < elements.length; i++) {
|
|
||||||
String token = elements[i];
|
|
||||||
ByteEditTreeNode nextNode = findNode(currentNode, token);
|
|
||||||
if (nextNode == null) {
|
|
||||||
nextNode = new ByteEditTreeNode(token, s);
|
|
||||||
currentNode.add(nextNode);
|
|
||||||
}
|
|
||||||
currentNode = nextNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ByteEditTreeNode findNode(ByteEditTreeNode parent, String name) {
|
|
||||||
Enumeration<?> e = parent.children();
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
ByteEditTreeNode element = (ByteEditTreeNode) e.nextElement();
|
|
||||||
if (element.getUserObject().equals(name)) {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int countSlashes(String s, int max) {
|
|
||||||
int count = 0;
|
|
||||||
for (char c : s.toCharArray()) {
|
|
||||||
if (c == '/') {
|
|
||||||
count++;
|
|
||||||
if (count == max)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FurtherExpandingTreeExpansionListener implements TreeExpansionListener {
|
|
||||||
public void treeExpanded(TreeExpansionEvent event) {
|
|
||||||
TreePath treePath = event.getPath();
|
|
||||||
Object expandedTreePathObject = treePath.getLastPathComponent();
|
|
||||||
if (!(expandedTreePathObject instanceof TreeNode))
|
|
||||||
return;
|
|
||||||
TreeNode expandedTreeNode = (TreeNode) expandedTreePathObject;
|
|
||||||
if (expandedTreeNode.getChildCount() == 1) {
|
|
||||||
TreeNode descendantTreeNode = expandedTreeNode.getChildAt(0);
|
|
||||||
if (descendantTreeNode.isLeaf())
|
|
||||||
return;
|
|
||||||
TreePath nextTreePath = treePath.pathByAddingChild(descendantTreeNode);
|
|
||||||
tree.expandPath(nextTreePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void treeCollapsed(TreeExpansionEvent event) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] toByteArray(final InputStream input) throws IOException {
|
|
||||||
try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int read;
|
|
||||||
while ((read = input.read(buffer)) != -1) {
|
|
||||||
output.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
return output.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ import java.util.HashSet;
|
|||||||
|
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.HugeStrings;
|
||||||
|
|
||||||
public class ClassUtil {
|
public class ClassUtil {
|
||||||
|
|
||||||
public static final int ACC_PUBLIC = 0x0001;
|
public static final int ACC_PUBLIC = 0x0001;
|
||||||
@@ -318,12 +320,10 @@ public class ClassUtil {
|
|||||||
s += "enum ";
|
s += "enum ";
|
||||||
acc ^= ACC_ENUM;
|
acc ^= ACC_ENUM;
|
||||||
}
|
}
|
||||||
if (acc == access) {
|
if (acc == access)
|
||||||
return s;
|
return s;
|
||||||
} else {
|
|
||||||
return "0x" + Integer.toHexString(access) + " ";
|
return "0x" + Integer.toHexString(access) + " ";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return { JavaType, Import }
|
* @return { JavaType, Import }
|
||||||
@@ -525,28 +525,28 @@ public class ClassUtil {
|
|||||||
public static final HashMap<Class, DecompilationInterface> diMap = new HashMap<>();
|
public static final HashMap<Class, DecompilationInterface> diMap = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
diMap.put(String.class, (o, desc, escapeSpaces) -> "\""
|
diMap.put(String.class, (o, desc, escapeSpaces, hs) -> "\""
|
||||||
+ (escapeSpaces ? UnicodeUtils.escapeWithSpaces((String) o) : UnicodeUtils.escape((String) o)) + "\"");
|
+ (escapeSpaces ? UnicodeUtils.escapeWithSpaces(hs, (String) o) : UnicodeUtils.escape(hs, (String) o))
|
||||||
|
+ "\"");
|
||||||
diMap.put(Integer.class,
|
diMap.put(Integer.class,
|
||||||
(o, desc, escape) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString());
|
(o, desc, escape, hs) -> desc.equals("Z") ? (((int) o) == 0 ? "false" : "true") : o.toString());
|
||||||
diMap.put(Long.class, (o, desc, escape) -> o.toString() + "l");
|
diMap.put(Long.class, (o, desc, escape, hs) -> o.toString() + "l");
|
||||||
diMap.put(Float.class, (o, desc, escape) -> o.toString() + "f");
|
diMap.put(Float.class, (o, desc, escape, hs) -> o.toString() + "f");
|
||||||
}
|
}
|
||||||
|
|
||||||
static interface DecompilationInterface {
|
static interface DecompilationInterface {
|
||||||
String apply(Object o, String desc, boolean escape);
|
String apply(Object o, String desc, boolean escape, HugeStrings hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces) {
|
public static String getDecompiledValue(Object o, String desc, boolean escapeSpaces, HugeStrings hs) {
|
||||||
DecompilationInterface di = diMap.get(o.getClass());
|
DecompilationInterface di = diMap.get(o.getClass());
|
||||||
if (di != null)
|
if (di != null)
|
||||||
return di.apply(o, desc, escapeSpaces);
|
return di.apply(o, desc, escapeSpaces, hs);
|
||||||
else
|
|
||||||
return o.toString();
|
return o.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDecompiledValue(Object o, String desc) {
|
public static String getDecompiledValue(Object o, String desc, HugeStrings hs) {
|
||||||
return getDecompiledValue(o, desc, false);
|
return getDecompiledValue(o, desc, false, hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getCastedValue(String o, String className) {
|
public static Object getCastedValue(String o, String className) {
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
package me.ByteEdit.utils;
|
package me.ByteEdit.utils;
|
||||||
|
|
||||||
|
import me.ByteEdit.edit.HugeStrings;
|
||||||
|
import me.ByteEdit.edit.HugeStringsRev;
|
||||||
|
|
||||||
public class UnicodeUtils {
|
public class UnicodeUtils {
|
||||||
|
|
||||||
public static String unescape(String s) {
|
public static String unescape(HugeStringsRev hsr, String s) {
|
||||||
|
return unescape(hsr, s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String unescape(HugeStringsRev hsr, String s, boolean force) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!force && !s.isEmpty() && s.charAt(0) == '#' && s.length() < 12) {
|
||||||
|
try {
|
||||||
|
int id = Integer.parseInt(s.substring(1));
|
||||||
|
return hsr.get(id);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
// Doesn't seem like a HugeString
|
||||||
|
}
|
||||||
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
char unicodeBuffer = 0;
|
char unicodeBuffer = 0;
|
||||||
int stage = 0;
|
int stage = 0;
|
||||||
@@ -69,19 +84,20 @@ public class UnicodeUtils {
|
|||||||
sb.append(c);
|
sb.append(c);
|
||||||
}
|
}
|
||||||
if (stage != 0) {
|
if (stage != 0) {
|
||||||
if (unicodeBuffer != 0) {
|
if (unicodeBuffer != 0)
|
||||||
throw new IllegalArgumentException("The unicode at the end is incomplete.");
|
throw new IllegalArgumentException("The unicode at the end is incomplete.");
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("'\\' at the end is invalid.");
|
throw new IllegalArgumentException("'\\' at the end is invalid.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String escapeWithSpaces(String s) {
|
public static String escapeWithSpaces(HugeStrings hs, String s) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (s.length() > HugeStrings.THRESHOLD) {
|
||||||
|
return hs.onString(s);
|
||||||
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
char[] arr = s.toCharArray();
|
char[] arr = s.toCharArray();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -92,6 +108,9 @@ public class UnicodeUtils {
|
|||||||
if (arr[0] == '/') {
|
if (arr[0] == '/') {
|
||||||
sb.append("\\u002F");
|
sb.append("\\u002F");
|
||||||
i++;
|
i++;
|
||||||
|
} else if (arr[0] == '#') {
|
||||||
|
sb.append("\\u0023");
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
if (arr[len - 1] == '/') {
|
if (arr[len - 1] == '/') {
|
||||||
addSlash = true;
|
addSlash = true;
|
||||||
@@ -158,12 +177,26 @@ public class UnicodeUtils {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String escape(String s) {
|
public static String escape(HugeStrings hs, String s) {
|
||||||
|
return escape(hs, s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String escape(HugeStrings hs, String s, boolean force) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
if (!force && s.length() > HugeStrings.THRESHOLD) {
|
||||||
for (char c : s.toCharArray()) {
|
return hs.onString(s);
|
||||||
|
}
|
||||||
|
char[] arr = s.toCharArray();
|
||||||
|
StringBuilder sb = new StringBuilder(arr.length);
|
||||||
|
int i = 0;
|
||||||
|
if (arr.length > 0 && arr[0] == '#') {
|
||||||
|
sb.append("\\u0023");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (; i < arr.length; i++) {
|
||||||
|
char c = arr[i];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'Ä':
|
case 'Ä':
|
||||||
case 'ä':
|
case 'ä':
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<baseFont size="12"/>
|
<baseFont size="12"/>
|
||||||
|
|
||||||
<!-- General editor colors. -->
|
<!-- General editor colors. -->
|
||||||
<background color="ffffff"/>
|
<background color="c0c0c0"/>
|
||||||
<caret color="000000"/>
|
<caret color="000000"/>
|
||||||
<selection bg="dddddd" fg="000000"/>
|
<selection bg="dddddd" fg="000000"/>
|
||||||
<currentLineHighlight color="dddddd" fade="false"/>
|
<currentLineHighlight color="dddddd" fade="false"/>
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
<baseFont size="12"/>
|
<baseFont size="12"/>
|
||||||
|
|
||||||
<!-- General editor colors. -->
|
<!-- General editor colors. -->
|
||||||
<background color="000000"/>
|
<background color="2f2f2f"/>
|
||||||
<caret color="eeeeee"/>
|
<caret color="eeeeee"/>
|
||||||
<selection bg="222222" fg="eeeeee"/>
|
<selection bg="555555" fg="eeeeee"/>
|
||||||
<currentLineHighlight color="222222" fade="false"/>
|
<currentLineHighlight color="111111" fade="false"/>
|
||||||
<marginLine fg="4f4b46"/>
|
<marginLine fg="4f4b46"/>
|
||||||
<markAllHighlight color="947e76"/> <!-- TODO: Fix me -->
|
<markAllHighlight color="947e76"/> <!-- TODO: Fix me -->
|
||||||
<markOccurrencesHighlight color="2b2b2b" border="false"/>
|
<markOccurrencesHighlight color="2b2b2b" border="false"/>
|
||||||
@@ -36,23 +36,23 @@
|
|||||||
<!-- Syntax tokens. -->
|
<!-- Syntax tokens. -->
|
||||||
<tokenStyles>
|
<tokenStyles>
|
||||||
<style token="IDENTIFIER" fg="eeeeee"/>
|
<style token="IDENTIFIER" fg="eeeeee"/>
|
||||||
<style token="RESERVED_WORD" fg="dd02d6" bold="true"/>
|
<style token="RESERVED_WORD" fg="cc6c1d" bold="true"/>
|
||||||
<style token="RESERVED_WORD_2" fg="dd02d6" bold="true"/>
|
<style token="RESERVED_WORD_2" fg="cc6c1d" bold="true"/>
|
||||||
<style token="ANNOTATION" fg="808080"/>
|
<style token="ANNOTATION" fg="808080"/>
|
||||||
<style token="COMMENT_DOCUMENTATION" fg="279627"/>
|
<style token="COMMENT_DOCUMENTATION" fg="279627"/>
|
||||||
<style token="COMMENT_EOL" fg="279627"/>
|
<style token="COMMENT_EOL" fg="279627"/>
|
||||||
<style token="COMMENT_MULTILINE" fg="279627"/>
|
<style token="COMMENT_MULTILINE" fg="279627"/>
|
||||||
<style token="COMMENT_KEYWORD" fg="806040" bold="true"/>
|
<style token="COMMENT_KEYWORD" fg="806040" bold="true"/>
|
||||||
<style token="COMMENT_MARKUP" fg="808060"/>
|
<style token="COMMENT_MARKUP" fg="808060"/>
|
||||||
<style token="DATA_TYPE" fg="dd02d6" bold="true"/>
|
<style token="DATA_TYPE" fg="cc6c1d"/>
|
||||||
<style token="FUNCTION" fg="eeeeee"/>
|
<style token="FUNCTION" fg="eeeeee"/>
|
||||||
<style token="LITERAL_BOOLEAN" fg="dd02d6" bold="true"/>
|
<style token="LITERAL_BOOLEAN" fg="cc6c1d"/>
|
||||||
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_DECIMAL_INT" fg="6897bb"/>
|
||||||
<style token="LITERAL_NUMBER_FLOAT" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_FLOAT" fg="6897bb"/>
|
||||||
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="eeeeee"/>
|
<style token="LITERAL_NUMBER_HEXADECIMAL" fg="6897bb"/>
|
||||||
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="00aeff"/>
|
<style token="LITERAL_STRING_DOUBLE_QUOTE" fg="17c6a3"/>
|
||||||
<style token="LITERAL_CHAR" fg="00aeff"/>
|
<style token="LITERAL_CHAR" fg="17c6a3"/>
|
||||||
<style token="LITERAL_BACKQUOTE" fg="00aeff"/>
|
<style token="LITERAL_BACKQUOTE" fg="17c6a3"/>
|
||||||
<style token="MARKUP_TAG_DELIMITER" fg="008080"/>
|
<style token="MARKUP_TAG_DELIMITER" fg="008080"/>
|
||||||
<style token="MARKUP_TAG_NAME" fg="3f7f7f"/>
|
<style token="MARKUP_TAG_NAME" fg="3f7f7f"/>
|
||||||
<style token="MARKUP_TAG_ATTRIBUTE" fg="7f007f"/>
|
<style token="MARKUP_TAG_ATTRIBUTE" fg="7f007f"/>
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ public class DocumentReader extends Reader {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param document
|
* @param document The document we're 'reading'.
|
||||||
* The document we're 'reading'.
|
|
||||||
*/
|
*/
|
||||||
public DocumentReader(Document document) {
|
public DocumentReader(Document document) {
|
||||||
position = 0;
|
position = 0;
|
||||||
@@ -55,14 +54,14 @@ public class DocumentReader extends Reader {
|
|||||||
* This currently does nothing...
|
* This currently does nothing...
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {}
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the present position in the stream. Subsequent calls to
|
* Marks the present position in the stream. Subsequent calls to
|
||||||
* <code>reset()</code> will reposition the stream to this point.
|
* <code>reset()</code> will reposition the stream to this point.
|
||||||
*
|
*
|
||||||
* @param readAheadLimit
|
* @param readAheadLimit Ignored.
|
||||||
* Ignored.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void mark(int readAheadLimit) {
|
public void mark(int readAheadLimit) {
|
||||||
@@ -70,8 +69,8 @@ public class DocumentReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells whether this reader supports the <code>mark</code> operation.
|
* Tells whether this reader supports the <code>mark</code> operation. This
|
||||||
* This always returns <code>true</code> for <code>DocumentReader</code>.
|
* always returns <code>true</code> for <code>DocumentReader</code>.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean markSupported() {
|
public boolean markSupported() {
|
||||||
@@ -98,11 +97,10 @@ public class DocumentReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read <code>array.length</code> characters from the beginning
|
* Read <code>array.length</code> characters from the beginning of the document
|
||||||
* of the document into <code>array</code>.
|
* into <code>array</code>.
|
||||||
*
|
*
|
||||||
* @param array
|
* @param array The array to read characters into.
|
||||||
* The array to read characters into.
|
|
||||||
* @return The number of characters read.
|
* @return The number of characters read.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -113,14 +111,11 @@ public class DocumentReader extends Reader {
|
|||||||
/**
|
/**
|
||||||
* Reads characters into a portion of an array.
|
* Reads characters into a portion of an array.
|
||||||
*
|
*
|
||||||
* @param cbuf
|
* @param cbuf The destination buffer.
|
||||||
* The destination buffer.
|
* @param off Offset at which to start storing characters.
|
||||||
* @param off
|
* @param len Maximum number of characters to read.
|
||||||
* Offset at which to start storing characters.
|
* @return The number of characters read, or <code>-1</code> if the end of the
|
||||||
* @param len
|
* stream (document) has been reached.
|
||||||
* Maximum number of characters to read.
|
|
||||||
* @return The number of characters read, or <code>-1</code> if the
|
|
||||||
* end of the stream (document) has been reached.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int read(char[] cbuf, int off, int len) {
|
public int read(char[] cbuf, int off, int len) {
|
||||||
@@ -147,12 +142,11 @@ public class DocumentReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells whether this reader is ready to be read without
|
* Tells whether this reader is ready to be read without blocking for input.
|
||||||
* blocking for input. <code>DocumentReader</code> will
|
* <code>DocumentReader</code> will always return true.
|
||||||
* always return true.
|
|
||||||
*
|
*
|
||||||
* @return <code>true</code> if the next read operation will
|
* @return <code>true</code> if the next read operation will return without
|
||||||
* return without blocking.
|
* blocking.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean ready() {
|
public boolean ready() {
|
||||||
@@ -160,9 +154,9 @@ public class DocumentReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the stream. If the stream has been marked, then attempt to
|
* Resets the stream. If the stream has been marked, then attempt to reposition
|
||||||
* reposition it at the mark. If the stream has not been marked, then
|
* it at the mark. If the stream has not been marked, then move it to the
|
||||||
* move it to the beginning of the document.
|
* beginning of the document.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
@@ -177,8 +171,7 @@ public class DocumentReader extends Reader {
|
|||||||
/**
|
/**
|
||||||
* Skips characters. This will not 'skip' past the end of the document.
|
* Skips characters. This will not 'skip' past the end of the document.
|
||||||
*
|
*
|
||||||
* @param n
|
* @param n The number of characters to skip.
|
||||||
* The number of characters to skip.
|
|
||||||
* @return The number of characters actually skipped.
|
* @return The number of characters actually skipped.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -193,12 +186,11 @@ public class DocumentReader extends Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move to the specified position in the document. If <code>pos</code>
|
* Move to the specified position in the document. If <code>pos</code> is
|
||||||
* is greater than the document's length, the stream's position is moved
|
* greater than the document's length, the stream's position is moved to the end
|
||||||
* to the end of the document.
|
* of the document.
|
||||||
*
|
*
|
||||||
* @param pos
|
* @param pos The position in the document to move to.
|
||||||
* The position in the document to move to.
|
|
||||||
*/
|
*/
|
||||||
public void seek(long pos) {
|
public void seek(long pos) {
|
||||||
position = Math.min(pos, document.getLength());
|
position = Math.min(pos, document.getLength());
|
||||||
|
|||||||
@@ -30,10 +30,9 @@ import java.io.Writer;
|
|||||||
public class UnicodeWriter extends Writer {
|
public class UnicodeWriter extends Writer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this system property evaluates to "<code>false</code>", ignoring
|
* If this system property evaluates to "<code>false</code>", ignoring case,
|
||||||
* case, files written out as UTF-8 will not have a BOM written for them.
|
* files written out as UTF-8 will not have a BOM written for them. Otherwise
|
||||||
* Otherwise (even if the property is not set), UTF-8 files will have a
|
* (even if the property is not set), UTF-8 files will have a BOM written.
|
||||||
* BOM written.
|
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_WRITE_UTF8_BOM = "UnicodeWriter.writeUtf8BOM";
|
public static final String PROPERTY_WRITE_UTF8_BOM = "UnicodeWriter.writeUtf8BOM";
|
||||||
/**
|
/**
|
||||||
@@ -47,30 +46,24 @@ public class UnicodeWriter extends Writer {
|
|||||||
private static final byte[] UTF32BE_BOM = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF };
|
private static final byte[] UTF32BE_BOM = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility constructor since the vast majority of the time, this
|
* This is a utility constructor since the vast majority of the time, this class
|
||||||
* class will be used to write Unicode files.
|
* will be used to write Unicode files.
|
||||||
*
|
*
|
||||||
* @param fileName
|
* @param fileName The file to which to write the Unicode output.
|
||||||
* The file to which to write the Unicode output.
|
* @param encoding The encoding to use.
|
||||||
* @param encoding
|
* @throws IOException If an IO exception occurs.
|
||||||
* The encoding to use.
|
|
||||||
* @throws IOException
|
|
||||||
* If an IO exception occurs.
|
|
||||||
*/
|
*/
|
||||||
public UnicodeWriter(String fileName, String encoding) throws IOException {
|
public UnicodeWriter(String fileName, String encoding) throws IOException {
|
||||||
this(new FileOutputStream(fileName), encoding);
|
this(new FileOutputStream(fileName), encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a utility constructor since the vast majority of the time, this
|
* This is a utility constructor since the vast majority of the time, this class
|
||||||
* class will be used to write Unicode files.
|
* will be used to write Unicode files.
|
||||||
*
|
*
|
||||||
* @param file
|
* @param file The file to which to write the Unicode output.
|
||||||
* The file to which to write the Unicode output.
|
* @param encoding The encoding to use.
|
||||||
* @param encoding
|
* @throws IOException If an IO exception occurs.
|
||||||
* The encoding to use.
|
|
||||||
* @throws IOException
|
|
||||||
* If an IO exception occurs.
|
|
||||||
*/
|
*/
|
||||||
public UnicodeWriter(File file, String encoding) throws IOException {
|
public UnicodeWriter(File file, String encoding) throws IOException {
|
||||||
this(new FileOutputStream(file), encoding);
|
this(new FileOutputStream(file), encoding);
|
||||||
@@ -79,12 +72,9 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Creates a new writer.
|
* Creates a new writer.
|
||||||
*
|
*
|
||||||
* @param out
|
* @param out The output stream to write.
|
||||||
* The output stream to write.
|
* @param encoding The encoding to use.
|
||||||
* @param encoding
|
* @throws IOException If an IO exception occurs.
|
||||||
* The encoding to use.
|
|
||||||
* @throws IOException
|
|
||||||
* If an IO exception occurs.
|
|
||||||
*/
|
*/
|
||||||
public UnicodeWriter(OutputStream out, String encoding) throws IOException {
|
public UnicodeWriter(OutputStream out, String encoding) throws IOException {
|
||||||
init(out, encoding);
|
init(out, encoding);
|
||||||
@@ -93,8 +83,7 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Closes this writer.
|
* Closes this writer.
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException If an IO exception occurs.
|
||||||
* If an IO exception occurs.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
@@ -104,8 +93,7 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Flushes the stream.
|
* Flushes the stream.
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException If an IO exception occurs.
|
||||||
* If an IO exception occurs.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
@@ -139,15 +127,12 @@ public class UnicodeWriter extends Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the internal output stream and writes the BOM if the
|
* Initializes the internal output stream and writes the BOM if the specified
|
||||||
* specified encoding is a Unicode encoding.
|
* encoding is a Unicode encoding.
|
||||||
*
|
*
|
||||||
* @param out
|
* @param out The output stream we are writing.
|
||||||
* The output stream we are writing.
|
* @param encoding The encoding in which to write.
|
||||||
* @param encoding
|
* @throws IOException If an I/O error occurs while writing a BOM.
|
||||||
* The encoding in which to write.
|
|
||||||
* @throws IOException
|
|
||||||
* If an I/O error occurs while writing a BOM.
|
|
||||||
*/
|
*/
|
||||||
private void init(OutputStream out, String encoding) throws IOException {
|
private void init(OutputStream out, String encoding) throws IOException {
|
||||||
internalOut = new OutputStreamWriter(out, encoding);
|
internalOut = new OutputStreamWriter(out, encoding);
|
||||||
@@ -173,8 +158,7 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Sets whether UTF-8 files should have a BOM written in them.
|
* Sets whether UTF-8 files should have a BOM written in them.
|
||||||
*
|
*
|
||||||
* @param write
|
* @param write Whether to write a BOM.
|
||||||
* Whether to write a BOM.
|
|
||||||
* @see #getWriteUtf8BOM()
|
* @see #getWriteUtf8BOM()
|
||||||
* @see UnicodeWriter
|
* @see UnicodeWriter
|
||||||
*/
|
*/
|
||||||
@@ -185,14 +169,10 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Writes a portion of an array of characters.
|
* Writes a portion of an array of characters.
|
||||||
*
|
*
|
||||||
* @param cbuf
|
* @param cbuf The buffer of characters.
|
||||||
* The buffer of characters.
|
* @param off The offset from which to start writing characters.
|
||||||
* @param off
|
* @param len The number of characters to write.
|
||||||
* The offset from which to start writing characters.
|
* @throws IOException If an I/O error occurs.
|
||||||
* @param len
|
|
||||||
* The number of characters to write.
|
|
||||||
* @throws IOException
|
|
||||||
* If an I/O error occurs.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||||
@@ -202,10 +182,8 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Writes a single character.
|
* Writes a single character.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c An integer specifying the character to write.
|
||||||
* An integer specifying the character to write.
|
* @throws IOException If an IO error occurs.
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(int c) throws IOException {
|
public void write(int c) throws IOException {
|
||||||
@@ -215,14 +193,10 @@ public class UnicodeWriter extends Writer {
|
|||||||
/**
|
/**
|
||||||
* Writes a portion of a string.
|
* Writes a portion of a string.
|
||||||
*
|
*
|
||||||
* @param str
|
* @param str The string from which to write.
|
||||||
* The string from which to write.
|
* @param off The offset from which to start writing characters.
|
||||||
* @param off
|
* @param len The number of characters to write.
|
||||||
* The offset from which to start writing characters.
|
* @throws IOException If an IO error occurs.
|
||||||
* @param len
|
|
||||||
* The number of characters to write.
|
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void write(String str, int off, int len) throws IOException {
|
public void write(String str, int off, int len) throws IOException {
|
||||||
|
|||||||
@@ -55,24 +55,18 @@ public abstract class RPrintUtilities {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the position closest to, but before, position
|
* Returns the position closest to, but before, position
|
||||||
* <code>maxCharsPerLine</code> in
|
* <code>maxCharsPerLine</code> in <code>line</code> of one of the chars in
|
||||||
* <code>line</code> of one of the chars in <code>breakChars</code>, or
|
* <code>breakChars</code>, or simply returns <code>maxCharsPerLine-1</code> if
|
||||||
* simply returns
|
* none of the <code>breakChars</code> comes before that position. This position
|
||||||
* <code>maxCharsPerLine-1</code> if none of the <code>breakChars</code>
|
* represents the logical line break for this <code>java.lang.String</code> if
|
||||||
* comes before
|
* it is being printed in a monospaced font when lines can only be
|
||||||
* that position. This position represents the logical line break for this
|
* <code>maxCharsPerLine</code> characters long.
|
||||||
* <code>java.lang.String</code>
|
|
||||||
* if it is being printed in a monospaced font when lines can only be
|
|
||||||
* <code>maxCharsPerLine</code>
|
|
||||||
* characters long.
|
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The text being printed.
|
||||||
* The text being printed.
|
* @param maxCharsPerLine Only up-to this many characters from <code>line</code>
|
||||||
* @param maxCharsPerLine
|
* can be printed on one line.
|
||||||
* Only up-to this many characters from
|
* @return The logical position at which to stop printing <code>line</code> to
|
||||||
* <code>line</code> can be printed on one line.
|
* simulate word wrap.
|
||||||
* @return The logical position at which to stop printing <code>line</code>
|
|
||||||
* to simulate word wrap.
|
|
||||||
*/
|
*/
|
||||||
private static int getLineBreakPoint(String line, final int maxCharsPerLine) {
|
private static int getLineBreakPoint(String line, final int maxCharsPerLine) {
|
||||||
int breakPoint = -1;
|
int breakPoint = -1;
|
||||||
@@ -87,27 +81,20 @@ public abstract class RPrintUtilities {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a <code>Document</code> using a monospaced font, and does no word
|
* Prints a <code>Document</code> using a monospaced font, and does no word
|
||||||
* wrapping (ie,
|
* wrapping (ie, words will wrap mid-word to the next line). This method is
|
||||||
* words will wrap mid-word to the next line). This method is expected to be
|
* expected to be called from Printable 'print(Graphics g)' functions.
|
||||||
* called from
|
|
||||||
* Printable 'print(Graphics g)' functions.
|
|
||||||
*
|
*
|
||||||
* @param g
|
* @param g The graphics context to write to.
|
||||||
* The graphics context to write to.
|
* @param doc The <code>javax.swing.text.Document</code> to print.
|
||||||
* @param doc
|
* @param fontSize the point size to use for the monospaced font.
|
||||||
* The <code>javax.swing.text.Document</code> to print.
|
* @param pageIndex The page number to print.
|
||||||
* @param fontSize
|
* @param pageFormat The format to print the page with.
|
||||||
* the point size to use for the monospaced font.
|
* @param tabSize The number of spaces to expand tabs to.
|
||||||
* @param pageIndex
|
|
||||||
* The page number to print.
|
|
||||||
* @param pageFormat
|
|
||||||
* The format to print the page with.
|
|
||||||
* @param tabSize
|
|
||||||
* The number of spaces to expand tabs to.
|
|
||||||
*
|
*
|
||||||
* @see #printDocumentMonospacedWordWrap
|
* @see #printDocumentMonospacedWordWrap
|
||||||
*/
|
*/
|
||||||
public static int printDocumentMonospaced(Graphics g, Document doc, int fontSize, int pageIndex, PageFormat pageFormat, int tabSize) {
|
public static int printDocumentMonospaced(Graphics g, Document doc, int fontSize, int pageIndex,
|
||||||
|
PageFormat pageFormat, int tabSize) {
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
|
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
|
||||||
// Initialize our static variables (these are used by our tab expander
|
// Initialize our static variables (these are used by our tab expander
|
||||||
@@ -204,27 +191,21 @@ public abstract class RPrintUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a <code>Document</code> using a monospaced font, word wrapping on
|
* Prints a <code>Document</code> using a monospaced font, word wrapping on the
|
||||||
* the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
|
* characters ' ', '\t', '\n', ',', '.', and ';'. This method is expected to be
|
||||||
* expected to be called from Printable 'print(Graphics g)' functions.
|
* called from Printable 'print(Graphics g)' functions.
|
||||||
*
|
*
|
||||||
* @param g
|
* @param g The graphics context to write to.
|
||||||
* The graphics context to write to.
|
* @param doc The <code>javax.swing.text.Document</code> to print.
|
||||||
* @param doc
|
* @param fontSize the point size to use for the monospaced font.
|
||||||
* The <code>javax.swing.text.Document</code> to print.
|
* @param pageIndex The page number to print.
|
||||||
* @param fontSize
|
* @param pageFormat The format to print the page with.
|
||||||
* the point size to use for the monospaced font.
|
* @param tabSize The number of spaces to expand tabs to.
|
||||||
* @param pageIndex
|
|
||||||
* The page number to print.
|
|
||||||
* @param pageFormat
|
|
||||||
* The format to print the page with.
|
|
||||||
* @param tabSize
|
|
||||||
* The number of spaces to expand tabs to.
|
|
||||||
*
|
*
|
||||||
* @see #printDocumentMonospaced
|
* @see #printDocumentMonospaced
|
||||||
*/
|
*/
|
||||||
public static int printDocumentMonospacedWordWrap(Graphics g, Document doc, int fontSize, int pageIndex, PageFormat pageFormat,
|
public static int printDocumentMonospacedWordWrap(Graphics g, Document doc, int fontSize, int pageIndex,
|
||||||
int tabSize) {
|
PageFormat pageFormat, int tabSize) {
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
|
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
|
||||||
// Initialize our static variables (these are used by our tab expander
|
// Initialize our static variables (these are used by our tab expander
|
||||||
@@ -322,28 +303,22 @@ public abstract class RPrintUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a <code>Document</code> using the specified font, word wrapping
|
* Prints a <code>Document</code> using the specified font, word wrapping on the
|
||||||
* on the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
|
* characters ' ', '\t', '\n', ',', '.', and ';'. This method is expected to be
|
||||||
* expected to be called from Printable 'print(Graphics g)' functions.
|
* called from Printable 'print(Graphics g)' functions.
|
||||||
*
|
*
|
||||||
* @param g
|
* @param g The graphics context to write to.
|
||||||
* The graphics context to write to.
|
* @param textComponent The <code>javax.swing.text.JTextComponent</code> whose
|
||||||
* @param textComponent
|
* text you're printing.
|
||||||
* The <code>javax.swing.text.JTextComponent</code>
|
* @param font The font to use for printing. If <code>null</code>, then
|
||||||
* whose text you're printing.
|
|
||||||
* @param font
|
|
||||||
* The font to use for printing. If <code>null</code>, then
|
|
||||||
* <code>textComponent</code>'s font is used.
|
* <code>textComponent</code>'s font is used.
|
||||||
* @param pageIndex
|
* @param pageIndex The page number to print.
|
||||||
* The page number to print.
|
* @param pageFormat The format to print the page with.
|
||||||
* @param pageFormat
|
* @param tabSize The number of spaces to convert tabs to.
|
||||||
* The format to print the page with.
|
|
||||||
* @param tabSize
|
|
||||||
* The number of spaces to convert tabs to.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static int printDocumentWordWrap(Graphics g, JTextComponent textComponent, Font font, int pageIndex, PageFormat pageFormat,
|
public static int printDocumentWordWrap(Graphics g, JTextComponent textComponent, Font font, int pageIndex,
|
||||||
int tabSize) {
|
PageFormat pageFormat, int tabSize) {
|
||||||
// Initialize our graphics object.
|
// Initialize our graphics object.
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
g.setFont(font != null ? font : textComponent.getFont());
|
g.setFont(font != null ? font : textComponent.getFont());
|
||||||
@@ -389,7 +364,8 @@ public abstract class RPrintUtilities {
|
|||||||
// we'd start after the part
|
// we'd start after the part
|
||||||
// that has already been printed).
|
// that has already been printed).
|
||||||
try {
|
try {
|
||||||
doc.getText(currentLineStart + startingOffset, currentLineEnd - (currentLineStart + startingOffset), currentLineSeg);
|
doc.getText(currentLineStart + startingOffset, currentLineEnd - (currentLineStart + startingOffset),
|
||||||
|
currentLineSeg);
|
||||||
} catch (BadLocationException ble) {
|
} catch (BadLocationException ble) {
|
||||||
System.err.println("BadLocationException in print (where there shouldn't be one!): " + ble);
|
System.err.println("BadLocationException in print (where there shouldn't be one!): " + ble);
|
||||||
return Printable.NO_SUCH_PAGE;
|
return Printable.NO_SUCH_PAGE;
|
||||||
@@ -452,7 +428,8 @@ public abstract class RPrintUtilities {
|
|||||||
System.err.println(ble);
|
System.err.println(ble);
|
||||||
return Printable.NO_SUCH_PAGE;
|
return Printable.NO_SUCH_PAGE;
|
||||||
}
|
}
|
||||||
currentLineLengthInPixels = Utilities.getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
|
currentLineLengthInPixels = Utilities.getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander,
|
||||||
|
0);
|
||||||
} while (currentLineLengthInPixels <= lineLengthInPixels);
|
} while (currentLineLengthInPixels <= lineLengthInPixels);
|
||||||
currentPos--;
|
currentPos--;
|
||||||
}
|
}
|
||||||
@@ -460,8 +437,8 @@ public abstract class RPrintUtilities {
|
|||||||
doc.getText((currentLineStart + startingOffset), currentPos, currentLineSeg);
|
doc.getText((currentLineStart + startingOffset), currentPos, currentLineSeg);
|
||||||
} catch (BadLocationException ble) {
|
} catch (BadLocationException ble) {
|
||||||
System.err.println("BadLocationException in print (a):");
|
System.err.println("BadLocationException in print (a):");
|
||||||
System.err.println("==> currentLineStart: " + currentLineStart + "; startingOffset: " + startingOffset
|
System.err.println("==> currentLineStart: " + currentLineStart + "; startingOffset: "
|
||||||
+ "; currentPos: " + currentPos);
|
+ startingOffset + "; currentPos: " + currentPos);
|
||||||
System.err.println("==> Range: " + (currentLineStart + startingOffset) + " - "
|
System.err.println("==> Range: " + (currentLineStart + startingOffset) + " - "
|
||||||
+ (currentLineStart + startingOffset + currentPos));
|
+ (currentLineStart + startingOffset + currentPos));
|
||||||
ble.printStackTrace();
|
ble.printStackTrace();
|
||||||
@@ -495,8 +472,7 @@ public abstract class RPrintUtilities {
|
|||||||
/**
|
/**
|
||||||
* Removes any spaces or tabs from the end of the segment.
|
* Removes any spaces or tabs from the end of the segment.
|
||||||
*
|
*
|
||||||
* @param segment
|
* @param segment The segment from which to remove tailing whitespace.
|
||||||
* The segment from which to remove tailing whitespace.
|
|
||||||
* @return <code>segment</code> with trailing whitespace removed.
|
* @return <code>segment</code> with trailing whitespace removed.
|
||||||
*/
|
*/
|
||||||
private static Segment removeEndingWhitespace(Segment segment) {
|
private static Segment removeEndingWhitespace(Segment segment) {
|
||||||
@@ -512,12 +488,13 @@ public abstract class RPrintUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tab expander for the document currently being printed with the
|
* A tab expander for the document currently being printed with the font being
|
||||||
* font being used for the printing.
|
* used for the printing.
|
||||||
*/
|
*/
|
||||||
private static class RPrintTabExpander implements TabExpander {
|
private static class RPrintTabExpander implements TabExpander {
|
||||||
|
|
||||||
RPrintTabExpander() {}
|
RPrintTabExpander() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float nextTabStop(float x, int tabOffset) {
|
public float nextTabStop(float x, int tabOffset) {
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ import javax.swing.text.JTextComponent;
|
|||||||
* lexicographically (ignoring case).
|
* lexicographically (ignoring case).
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This implementation assumes the input text and replacement text are the
|
* This implementation assumes the input text and replacement text are the same
|
||||||
* same value. It also returns the input text from its {@link #toString()}
|
* value. It also returns the input text from its {@link #toString()} method
|
||||||
* method (which is what <code>DefaultListCellRenderer</code> uses to render
|
* (which is what <code>DefaultListCellRenderer</code> uses to render objects).
|
||||||
* objects). Subclasses that wish to override any of this behavior can simply
|
* Subclasses that wish to override any of this behavior can simply override the
|
||||||
* override the corresponding method(s) needed to do so.
|
* corresponding method(s) needed to do so.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -38,17 +38,16 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
private Icon icon;
|
private Icon icon;
|
||||||
/**
|
/**
|
||||||
* The relevance of this completion. Completion instances with higher
|
* The relevance of this completion. Completion instances with higher
|
||||||
* "relevance" values are inserted higher into the list of possible
|
* "relevance" values are inserted higher into the list of possible completions
|
||||||
* completions than those with lower values. Completion instances with
|
* than those with lower values. Completion instances with equal relevance
|
||||||
* equal relevance values are sorted alphabetically.
|
* values are sorted alphabetically.
|
||||||
*/
|
*/
|
||||||
private int relevance;
|
private int relevance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider that created this completion.
|
||||||
* The provider that created this completion.
|
|
||||||
*/
|
*/
|
||||||
protected AbstractCompletion(CompletionProvider provider) {
|
protected AbstractCompletion(CompletionProvider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
@@ -57,10 +56,8 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider that created this completion.
|
||||||
* The provider that created this completion.
|
* @param icon The icon for this completion.
|
||||||
* @param icon
|
|
||||||
* The icon for this completion.
|
|
||||||
*/
|
*/
|
||||||
protected AbstractCompletion(CompletionProvider provider, Icon icon) {
|
protected AbstractCompletion(CompletionProvider provider, Icon icon) {
|
||||||
this(provider);
|
this(provider);
|
||||||
@@ -97,8 +94,8 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text the user has to (start) typing for this completion
|
* Returns the text the user has to (start) typing for this completion to be
|
||||||
* to be offered. The default implementation simply returns
|
* offered. The default implementation simply returns
|
||||||
* {@link #getReplacementText()}.
|
* {@link #getReplacementText()}.
|
||||||
*
|
*
|
||||||
* @return The text the user has to (start) typing for this completion.
|
* @return The text the user has to (start) typing for this completion.
|
||||||
@@ -126,8 +123,8 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation returns <code>null</code>. Subclasses
|
* The default implementation returns <code>null</code>. Subclasses can override
|
||||||
* can override this method.
|
* this method.
|
||||||
*
|
*
|
||||||
* @return The tool tip text.
|
* @return The tool tip text.
|
||||||
*/
|
*/
|
||||||
@@ -139,8 +136,7 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
/**
|
/**
|
||||||
* Sets the icon to use for this completion.
|
* Sets the icon to use for this completion.
|
||||||
*
|
*
|
||||||
* @param icon
|
* @param icon The icon to use.
|
||||||
* The icon to use.
|
|
||||||
* @see #getIcon()
|
* @see #getIcon()
|
||||||
*/
|
*/
|
||||||
public void setIcon(Icon icon) {
|
public void setIcon(Icon icon) {
|
||||||
@@ -150,8 +146,7 @@ public abstract class AbstractCompletion implements Completion {
|
|||||||
/**
|
/**
|
||||||
* Sets the relevance of this completion.
|
* Sets the relevance of this completion.
|
||||||
*
|
*
|
||||||
* @param relevance
|
* @param relevance The new relevance of this completion.
|
||||||
* The new relevance of this completion.
|
|
||||||
* @see #getRelevance()
|
* @see #getRelevance()
|
||||||
*/
|
*/
|
||||||
public void setRelevance(int relevance) {
|
public void setRelevance(int relevance) {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ import javax.swing.event.HyperlinkListener;
|
|||||||
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The optional "description" window that describes the currently selected
|
* The optional "description" window that describes the currently selected item
|
||||||
* item in the auto-completion window.
|
* in the auto-completion window.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -89,9 +89,8 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
private int historyPos;
|
private int historyPos;
|
||||||
/**
|
/**
|
||||||
* Provides a slight delay between asking to set a description and actually
|
* Provides a slight delay between asking to set a description and actually
|
||||||
* displaying it, so that if the user is scrolling quickly through
|
* displaying it, so that if the user is scrolling quickly through completions,
|
||||||
* completions, those with slow-to-calculate summaries won't bog down the
|
* those with slow-to-calculate summaries won't bog down the scrolling.
|
||||||
* scrolling.
|
|
||||||
*/
|
*/
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
/**
|
/**
|
||||||
@@ -103,10 +102,9 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
*/
|
*/
|
||||||
private ResourceBundle bundle;
|
private ResourceBundle bundle;
|
||||||
/**
|
/**
|
||||||
* The amount of time to wait after the user changes the selected
|
* The amount of time to wait after the user changes the selected completion to
|
||||||
* completion to refresh the description. This delay is in place to help
|
* refresh the description. This delay is in place to help performance for
|
||||||
* performance for {@link Completion}s that may be slow to compute their
|
* {@link Completion}s that may be slow to compute their summary text.
|
||||||
* summary text.
|
|
||||||
*/
|
*/
|
||||||
private static final int INITIAL_TIMER_DELAY = 120;
|
private static final int INITIAL_TIMER_DELAY = 120;
|
||||||
/**
|
/**
|
||||||
@@ -117,10 +115,8 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param owner
|
* @param owner The parent window.
|
||||||
* The parent window.
|
* @param ac The parent auto-completion.
|
||||||
* @param ac
|
|
||||||
* The parent auto-completion.
|
|
||||||
*/
|
*/
|
||||||
public AutoCompleteDescWindow(Window owner, AutoCompletion ac) {
|
public AutoCompleteDescWindow(Window owner, AutoCompletion ac) {
|
||||||
super(owner);
|
super(owner);
|
||||||
@@ -183,8 +179,7 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Sets the currently displayed description and updates the history.
|
* Sets the currently displayed description and updates the history.
|
||||||
*
|
*
|
||||||
* @param historyItem
|
* @param historyItem The item to add to the history.
|
||||||
* The item to add to the history.
|
|
||||||
*/
|
*/
|
||||||
private void addToHistory(HistoryEntry historyItem) {
|
private void addToHistory(HistoryEntry historyItem) {
|
||||||
history.add(++historyPos, historyItem);
|
history.add(++historyPos, historyItem);
|
||||||
@@ -214,8 +209,8 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies from the description text area, if it is visible and there is
|
* Copies from the description text area, if it is visible and there is a
|
||||||
* a selection.
|
* selection.
|
||||||
*
|
*
|
||||||
* @return Whether a copy occurred.
|
* @return Whether a copy occurred.
|
||||||
*/
|
*/
|
||||||
@@ -230,8 +225,7 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Returns the localized message for the specified key.
|
* Returns the localized message for the specified key.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key The key.
|
||||||
* The key.
|
|
||||||
* @return The localized message.
|
* @return The localized message.
|
||||||
*/
|
*/
|
||||||
private String getString(String key) {
|
private String getString(String key) {
|
||||||
@@ -244,8 +238,7 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Called when a hyperlink is clicked.
|
* Called when a hyperlink is clicked.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||||
@@ -261,7 +254,8 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
URL newUrl = redirector.possiblyRedirect(url);
|
URL newUrl = redirector.possiblyRedirect(url);
|
||||||
if (newUrl != null && newUrl != url) {
|
if (newUrl != null && newUrl != url) {
|
||||||
url = newUrl;
|
url = newUrl;
|
||||||
e = new HyperlinkEvent(e.getSource(), e.getEventType(), newUrl, e.getDescription(), e.getSourceElement());
|
e = new HyperlinkEvent(e.getSource(), e.getEventType(), newUrl, e.getDescription(),
|
||||||
|
e.getSourceElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,11 +319,9 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the description displayed in this window. This clears the
|
* Sets the description displayed in this window. This clears the history.
|
||||||
* history.
|
|
||||||
*
|
*
|
||||||
* @param item
|
* @param item The item whose description you want to display.
|
||||||
* The item whose description you want to display.
|
|
||||||
*/
|
*/
|
||||||
public void setDescriptionFor(Completion item) {
|
public void setDescriptionFor(Completion item) {
|
||||||
setDescriptionFor(item, false);
|
setDescriptionFor(item, false);
|
||||||
@@ -338,11 +330,9 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Sets the description displayed in this window.
|
* Sets the description displayed in this window.
|
||||||
*
|
*
|
||||||
* @param item
|
* @param item The item whose description you want to display.
|
||||||
* The item whose description you want to display.
|
* @param addToHistory Whether to add this page to the page history (as opposed
|
||||||
* @param addToHistory
|
* to clearing it and starting anew).
|
||||||
* Whether to add this page to the page history
|
|
||||||
* (as opposed to clearing it and starting anew).
|
|
||||||
*/
|
*/
|
||||||
protected void setDescriptionFor(Completion item, boolean addToHistory) {
|
protected void setDescriptionFor(Completion item, boolean addToHistory) {
|
||||||
setDescriptionFor(item, null, addToHistory);
|
setDescriptionFor(item, null, addToHistory);
|
||||||
@@ -351,12 +341,10 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Sets the description displayed in this window.
|
* Sets the description displayed in this window.
|
||||||
*
|
*
|
||||||
* @param item
|
* @param item The item whose description you want to display.
|
||||||
* The item whose description you want to display.
|
|
||||||
* @parma anchor The anchor to jump to, or <code>null</code> if none.
|
* @parma anchor The anchor to jump to, or <code>null</code> if none.
|
||||||
* @param addToHistory
|
* @param addToHistory Whether to add this page to the page history (as opposed
|
||||||
* Whether to add this page to the page history
|
* to clearing it and starting anew).
|
||||||
* (as opposed to clearing it and starting anew).
|
|
||||||
*/
|
*/
|
||||||
protected void setDescriptionFor(Completion item, String anchor, boolean addToHistory) {
|
protected void setDescriptionFor(Completion item, String anchor, boolean addToHistory) {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
@@ -403,11 +391,9 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
/**
|
/**
|
||||||
* Callback for custom <code>ExternalURLHandler</code>s.
|
* Callback for custom <code>ExternalURLHandler</code>s.
|
||||||
*
|
*
|
||||||
* @param completion
|
* @param completion The completion to display.
|
||||||
* The completion to display.
|
* @param anchor The anchor in the HTML to jump to, or <code>null</code> if
|
||||||
* @param anchor
|
* none.
|
||||||
* The anchor in the HTML to jump to, or <code>null</code>
|
|
||||||
* if none.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void showSummaryFor(Completion completion, String anchor) {
|
public void showSummaryFor(Completion completion, String anchor) {
|
||||||
@@ -442,8 +428,8 @@ class AutoCompleteDescWindow extends JWindow implements HyperlinkListener, DescW
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden to display a short name for the completion, since it's
|
* Overridden to display a short name for the completion, since it's used in the
|
||||||
* used in the tool tips for the "back" and "forward" buttons.
|
* tool tips for the "back" and "forward" buttons.
|
||||||
*
|
*
|
||||||
* @return A string representation of this history entry.
|
* @return A string representation of this history entry.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,10 +43,9 @@ import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual popup window of choices. When visible, this window intercepts
|
* The actual popup window of choices. When visible, this window intercepts
|
||||||
* certain keystrokes in the parent text component and uses them to navigate
|
* certain keystrokes in the parent text component and uses them to navigate the
|
||||||
* the completion choices instead. If Enter or Escape is pressed, the window
|
* completion choices instead. If Enter or Escape is pressed, the window hides
|
||||||
* hides itself and notifies the {@link AutoCompletion} to insert the selected
|
* itself and notifies the {@link AutoCompletion} to insert the selected text.
|
||||||
* text.
|
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -66,27 +65,26 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
*/
|
*/
|
||||||
private CompletionListModel model;
|
private CompletionListModel model;
|
||||||
/**
|
/**
|
||||||
* A hack to work around the fact that we clear our completion model (and
|
* A hack to work around the fact that we clear our completion model (and our
|
||||||
* our selection) when hiding the completion window. This allows us to
|
* selection) when hiding the completion window. This allows us to still know
|
||||||
* still know what the user selected after the popup is hidden.
|
* what the user selected after the popup is hidden.
|
||||||
*/
|
*/
|
||||||
private Completion lastSelection;
|
private Completion lastSelection;
|
||||||
/**
|
/**
|
||||||
* Optional popup window containing a description of the currently
|
* Optional popup window containing a description of the currently selected
|
||||||
* selected completion.
|
* completion.
|
||||||
*/
|
*/
|
||||||
private AutoCompleteDescWindow descWindow;
|
private AutoCompleteDescWindow descWindow;
|
||||||
/**
|
/**
|
||||||
* The preferred size of the optional description window. This field
|
* The preferred size of the optional description window. This field only exists
|
||||||
* only exists because the user may (and usually will) set the size of
|
* because the user may (and usually will) set the size of the description
|
||||||
* the description window before it exists (it must be parented to a
|
* window before it exists (it must be parented to a Window).
|
||||||
* Window).
|
|
||||||
*/
|
*/
|
||||||
private Dimension preferredDescWindowSize;
|
private Dimension preferredDescWindowSize;
|
||||||
/**
|
/**
|
||||||
* Whether the completion window and the optional description window
|
* Whether the completion window and the optional description window should be
|
||||||
* should be displayed above the current caret position (as opposed to
|
* displayed above the current caret position (as opposed to underneath it,
|
||||||
* underneath it, which is preferred unless there is not enough space).
|
* which is preferred unless there is not enough space).
|
||||||
*/
|
*/
|
||||||
private boolean aboveCaret;
|
private boolean aboveCaret;
|
||||||
private int lastLine;
|
private int lastLine;
|
||||||
@@ -103,7 +101,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
private KeyActionPair pageUpKap;
|
private KeyActionPair pageUpKap;
|
||||||
private KeyActionPair pageDownKap;
|
private KeyActionPair pageDownKap;
|
||||||
private KeyActionPair ctrlCKap;
|
private KeyActionPair ctrlCKap;
|
||||||
private KeyActionPair oldEscape, oldUp, oldDown, oldLeft, oldRight, oldEnter, oldTab, oldHome, oldEnd, oldPageUp, oldPageDown, oldCtrlC;
|
private KeyActionPair oldEscape, oldUp, oldDown, oldLeft, oldRight, oldEnter, oldTab, oldHome, oldEnd, oldPageUp,
|
||||||
|
oldPageDown, oldCtrlC;
|
||||||
/**
|
/**
|
||||||
* The space between the caret and the completion popup.
|
* The space between the caret and the completion popup.
|
||||||
*/
|
*/
|
||||||
@@ -116,10 +115,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param parent
|
* @param parent The parent window (hosting the text component).
|
||||||
* The parent window (hosting the text component).
|
* @param ac The auto-completion instance.
|
||||||
* @param ac
|
|
||||||
* The auto-completion instance.
|
|
||||||
*/
|
*/
|
||||||
public AutoCompletePopupWindow(Window parent, final AutoCompletion ac) {
|
public AutoCompletePopupWindow(Window parent, final AutoCompletion ac) {
|
||||||
super(parent);
|
super(parent);
|
||||||
@@ -131,7 +128,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
list.addListSelectionListener(this);
|
list.addListSelectionListener(this);
|
||||||
list.addMouseListener(this);
|
list.addMouseListener(this);
|
||||||
JPanel contentPane = new JPanel(new BorderLayout());
|
JPanel contentPane = new JPanel(new BorderLayout());
|
||||||
JScrollPane sp = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
JScrollPane sp = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||||
|
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||||
// In 1.4, JScrollPane.setCorner() has a bug where it won't accept
|
// In 1.4, JScrollPane.setCorner() has a bug where it won't accept
|
||||||
// JScrollPane.LOWER_TRAILING_CORNER, even though that constant is
|
// JScrollPane.LOWER_TRAILING_CORNER, even though that constant is
|
||||||
// defined. So we have to put the logic added in 1.5 to handle it
|
// defined. So we have to put the logic added in 1.5 to handle it
|
||||||
@@ -188,8 +186,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the mappings from keys to Actions we'll be putting into the
|
* Creates the mappings from keys to Actions we'll be putting into the text
|
||||||
* text component's ActionMap and InputMap.
|
* component's ActionMap and InputMap.
|
||||||
*/
|
*/
|
||||||
private void createKeyActionPairs() {
|
private void createKeyActionPairs() {
|
||||||
// Actions we'll install.
|
// Actions we'll install.
|
||||||
@@ -237,8 +235,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default list cell renderer used when a completion provider
|
* Returns the default list cell renderer used when a completion provider does
|
||||||
* does not supply its own.
|
* not supply its own.
|
||||||
*
|
*
|
||||||
* @return The default list cell renderer.
|
* @return The default list cell renderer.
|
||||||
* @see #setListCellRenderer(ListCellRenderer)
|
* @see #setListCellRenderer(ListCellRenderer)
|
||||||
@@ -268,8 +266,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers keyboard actions to listen for in the text component and
|
* Registers keyboard actions to listen for in the text component and intercept.
|
||||||
* intercept.
|
|
||||||
*
|
*
|
||||||
* @see #uninstallKeyBindings()
|
* @see #uninstallKeyBindings()
|
||||||
*/
|
*/
|
||||||
@@ -322,21 +319,25 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseEntered(MouseEvent e) {}
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseExited(MouseEvent e) {}
|
public void mouseExited(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {}
|
public void mousePressed(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {}
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Positions the description window relative to the completion choices
|
* Positions the description window relative to the completion choices window.
|
||||||
* window. We assume there is room on one side of the other for this
|
* We assume there is room on one side of the other for this entire window to
|
||||||
* entire window to fit.
|
* fit.
|
||||||
*/
|
*/
|
||||||
private void positionDescWindow() {
|
private void positionDescWindow() {
|
||||||
boolean showDescWindow = descWindow != null && ac.getShowDescWindow();
|
boolean showDescWindow = descWindow != null && ac.getShowDescWindow();
|
||||||
@@ -374,19 +375,14 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Puts back" the original key/Action pair for a keystroke. This is used
|
* "Puts back" the original key/Action pair for a keystroke. This is used when
|
||||||
* when this popup is hidden.
|
* this popup is hidden.
|
||||||
*
|
*
|
||||||
* @param im
|
* @param im The input map.
|
||||||
* The input map.
|
* @param am The action map.
|
||||||
* @param am
|
* @param key The keystroke whose key/Action pair to change.
|
||||||
* The action map.
|
* @param kap The (original) key/Action pair.
|
||||||
* @param key
|
* @see #replaceAction(InputMap, ActionMap, int, KeyActionPair, KeyActionPair)
|
||||||
* The keystroke whose key/Action pair to change.
|
|
||||||
* @param kap
|
|
||||||
* The (original) key/Action pair.
|
|
||||||
* @see #replaceAction(InputMap, ActionMap, int, KeyActionPair,
|
|
||||||
* KeyActionPair)
|
|
||||||
*/
|
*/
|
||||||
private void putBackAction(InputMap im, ActionMap am, int key, KeyActionPair kap) {
|
private void putBackAction(InputMap im, ActionMap am, int key, KeyActionPair kap) {
|
||||||
KeyStroke ks = KeyStroke.getKeyStroke(key, 0);
|
KeyStroke ks = KeyStroke.getKeyStroke(key, 0);
|
||||||
@@ -395,19 +391,13 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces a key/Action pair in an InputMap and ActionMap with a new
|
* Replaces a key/Action pair in an InputMap and ActionMap with a new pair.
|
||||||
* pair.
|
|
||||||
*
|
*
|
||||||
* @param im
|
* @param im The input map.
|
||||||
* The input map.
|
* @param am The action map.
|
||||||
* @param am
|
* @param key The keystroke whose information to replace.
|
||||||
* The action map.
|
* @param kap The new key/Action pair for <code>key</code>.
|
||||||
* @param key
|
* @param old A buffer in which to place the old key/Action pair.
|
||||||
* The keystroke whose information to replace.
|
|
||||||
* @param kap
|
|
||||||
* The new key/Action pair for <code>key</code>.
|
|
||||||
* @param old
|
|
||||||
* A buffer in which to place the old key/Action pair.
|
|
||||||
* @see #putBackAction(InputMap, ActionMap, int, KeyActionPair)
|
* @see #putBackAction(InputMap, ActionMap, int, KeyActionPair)
|
||||||
*/
|
*/
|
||||||
private void replaceAction(InputMap im, ActionMap am, int key, KeyActionPair kap, KeyActionPair old) {
|
private void replaceAction(InputMap im, ActionMap am, int key, KeyActionPair kap, KeyActionPair old) {
|
||||||
@@ -458,8 +448,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the completion item one "page down" from the currently selected
|
* Selects the completion item one "page down" from the currently selected one.
|
||||||
* one.
|
|
||||||
*
|
*
|
||||||
* @see #selectPageUpItem()
|
* @see #selectPageUpItem()
|
||||||
*/
|
*/
|
||||||
@@ -471,8 +460,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the completion item one "page up" from the currently selected
|
* Selects the completion item one "page up" from the currently selected one.
|
||||||
* one.
|
|
||||||
*
|
*
|
||||||
* @see #selectPageDownItem()
|
* @see #selectPageDownItem()
|
||||||
*/
|
*/
|
||||||
@@ -509,11 +497,10 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the completions to display in the choices list. The first
|
* Sets the completions to display in the choices list. The first completion is
|
||||||
* completion is selected.
|
* selected.
|
||||||
*
|
*
|
||||||
* @param completions
|
* @param completions The completions to display.
|
||||||
* The completions to display.
|
|
||||||
*/
|
*/
|
||||||
public void setCompletions(List<Completion> completions) {
|
public void setCompletions(List<Completion> completions) {
|
||||||
model.setContents(completions);
|
model.setContents(completions);
|
||||||
@@ -523,8 +510,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
/**
|
/**
|
||||||
* Sets the size of the description window.
|
* Sets the size of the description window.
|
||||||
*
|
*
|
||||||
* @param size
|
* @param size The new size. This cannot be <code>null</code>.
|
||||||
* The new size. This cannot be <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
public void setDescriptionWindowSize(Dimension size) {
|
public void setDescriptionWindowSize(Dimension size) {
|
||||||
if (descWindow != null) {
|
if (descWindow != null) {
|
||||||
@@ -535,12 +521,11 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the default list cell renderer to use when a completion provider
|
* Sets the default list cell renderer to use when a completion provider does
|
||||||
* does not supply its own.
|
* not supply its own.
|
||||||
*
|
*
|
||||||
* @param renderer
|
* @param renderer The renderer to use. If this is <code>null</code>, a default
|
||||||
* The renderer to use. If this is <code>null</code>,
|
* renderer is used.
|
||||||
* a default renderer is used.
|
|
||||||
* @see #getListCellRenderer()
|
* @see #getListCellRenderer()
|
||||||
*/
|
*/
|
||||||
public void setListCellRenderer(ListCellRenderer renderer) {
|
public void setListCellRenderer(ListCellRenderer renderer) {
|
||||||
@@ -550,11 +535,10 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the location of this window to be "good" relative to the specified
|
* Sets the location of this window to be "good" relative to the specified
|
||||||
* rectangle. That rectangle should be the location of the text
|
* rectangle. That rectangle should be the location of the text component's
|
||||||
* component's caret, in screen coordinates.
|
* caret, in screen coordinates.
|
||||||
*
|
*
|
||||||
* @param r
|
* @param r The text component's caret position, in screen coordinates.
|
||||||
* The text component's caret position, in screen coordinates.
|
|
||||||
*/
|
*/
|
||||||
public void setLocationRelativeTo(Rectangle r) {
|
public void setLocationRelativeTo(Rectangle r) {
|
||||||
// Multi-monitor support - make sure the completion window (and
|
// Multi-monitor support - make sure the completion window (and
|
||||||
@@ -600,8 +584,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
/**
|
/**
|
||||||
* Toggles the visibility of this popup window.
|
* Toggles the visibility of this popup window.
|
||||||
*
|
*
|
||||||
* @param visible
|
* @param visible Whether this window should be visible.
|
||||||
* Whether this window should be visible.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
@@ -685,8 +668,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the <tt>LookAndFeel</tt> of this window and the description
|
* Updates the <tt>LookAndFeel</tt> of this window and the description window.
|
||||||
* window.
|
|
||||||
*/
|
*/
|
||||||
public void updateUI() {
|
public void updateUI() {
|
||||||
SwingUtilities.updateComponentTreeUI(this);
|
SwingUtilities.updateComponentTreeUI(this);
|
||||||
@@ -698,8 +680,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
/**
|
/**
|
||||||
* Called when a new item is selected in the popup list.
|
* Called when a new item is selected in the popup list.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
@@ -784,7 +765,8 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSele
|
|||||||
public Object key;
|
public Object key;
|
||||||
public Action action;
|
public Action action;
|
||||||
|
|
||||||
public KeyActionPair() {}
|
public KeyActionPair() {
|
||||||
|
}
|
||||||
|
|
||||||
public KeyActionPair(Object key, Action a) {
|
public KeyActionPair(Object key, Action a) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ import javax.swing.text.Element;
|
|||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds auto-completion to a text component. Provides a popup window with a
|
* Adds auto-completion to a text component. Provides a popup window with a list
|
||||||
* list of auto-complete choices on a given keystroke, such as Crtrl+Space.
|
* of auto-complete choices on a given keystroke, such as Crtrl+Space.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Depending on the {@link CompletionProvider} installed, the following
|
* Depending on the {@link CompletionProvider} installed, the following
|
||||||
@@ -58,14 +58,14 @@ import javax.swing.text.JTextComponent;
|
|||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>An auto-complete choices list made visible via e.g. Ctrl+Space</li>
|
* <li>An auto-complete choices list made visible via e.g. Ctrl+Space</li>
|
||||||
* <li>A "description" window displayed alongside the choices list that
|
* <li>A "description" window displayed alongside the choices list that provides
|
||||||
* provides documentation on the currently selected completion choice
|
* documentation on the currently selected completion choice (as seen in Eclipse
|
||||||
* (as seen in Eclipse and NetBeans).</li>
|
* and NetBeans).</li>
|
||||||
* <li>Parameter assistance. If this is enabled, if the user enters a
|
* <li>Parameter assistance. If this is enabled, if the user enters a
|
||||||
* "parameterized" completion, such as a method or a function, then they
|
* "parameterized" completion, such as a method or a function, then they will
|
||||||
* will receive a tool tip describing the arguments they have to enter to
|
* receive a tool tip describing the arguments they have to enter to the
|
||||||
* the completion. Also, the arguments can be navigated via tab and
|
* completion. Also, the arguments can be navigated via tab and shift+tab (a la
|
||||||
* shift+tab (a la Eclipse and NetBeans).</li>
|
* Eclipse and NetBeans).</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
@@ -93,14 +93,14 @@ public class AutoCompletion {
|
|||||||
private AutoCompletePopupWindow popupWindow;
|
private AutoCompletePopupWindow popupWindow;
|
||||||
/**
|
/**
|
||||||
* The preferred size of the completion choices window. This field exists
|
* The preferred size of the completion choices window. This field exists
|
||||||
* because the user will likely set the preferred size of the window before
|
* because the user will likely set the preferred size of the window before it
|
||||||
* it is actually created.
|
* is actually created.
|
||||||
*/
|
*/
|
||||||
private Dimension preferredChoicesWindowSize;
|
private Dimension preferredChoicesWindowSize;
|
||||||
/**
|
/**
|
||||||
* The preferred size of the optional description window. This field only
|
* The preferred size of the optional description window. This field only exists
|
||||||
* exists because the user may (and usually will) set the size of the
|
* because the user may (and usually will) set the size of the description
|
||||||
* description window before it exists (it must be parented to a Window).
|
* window before it exists (it must be parented to a Window).
|
||||||
*/
|
*/
|
||||||
private Dimension preferredDescWindowSize;
|
private Dimension preferredDescWindowSize;
|
||||||
/**
|
/**
|
||||||
@@ -112,13 +112,12 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private CompletionProvider provider;
|
private CompletionProvider provider;
|
||||||
/**
|
/**
|
||||||
* The renderer to use for the completion choices. If this is
|
* The renderer to use for the completion choices. If this is <code>null</code>,
|
||||||
* <code>null</code>, then a default renderer is used.
|
* then a default renderer is used.
|
||||||
*/
|
*/
|
||||||
private ListCellRenderer renderer;
|
private ListCellRenderer renderer;
|
||||||
/**
|
/**
|
||||||
* The handler to use when an external URL is clicked in the help
|
* The handler to use when an external URL is clicked in the help documentation.
|
||||||
* documentation.
|
|
||||||
*/
|
*/
|
||||||
private ExternalURLHandler externalURLHandler;
|
private ExternalURLHandler externalURLHandler;
|
||||||
/**
|
/**
|
||||||
@@ -127,8 +126,8 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private static LinkRedirector linkRedirector;
|
private static LinkRedirector linkRedirector;
|
||||||
/**
|
/**
|
||||||
* Whether the description window should be displayed along with the
|
* Whether the description window should be displayed along with the completion
|
||||||
* completion choice window.
|
* choice window.
|
||||||
*/
|
*/
|
||||||
private boolean showDescWindow;
|
private boolean showDescWindow;
|
||||||
/**
|
/**
|
||||||
@@ -136,14 +135,14 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private boolean autoCompleteEnabled;
|
private boolean autoCompleteEnabled;
|
||||||
/**
|
/**
|
||||||
* Whether the auto-activation of auto-complete (after a delay, after the
|
* Whether the auto-activation of auto-complete (after a delay, after the user
|
||||||
* user types an appropriate character) is enabled.
|
* types an appropriate character) is enabled.
|
||||||
*/
|
*/
|
||||||
private boolean autoActivationEnabled;
|
private boolean autoActivationEnabled;
|
||||||
/**
|
/**
|
||||||
* Whether or not, when there is only a single auto-complete option that
|
* Whether or not, when there is only a single auto-complete option that matches
|
||||||
* matches the text at the current text position, that text should be
|
* the text at the current text position, that text should be auto-inserted,
|
||||||
* auto-inserted, instead of the completion window displaying.
|
* instead of the completion window displaying.
|
||||||
*/
|
*/
|
||||||
private boolean autoCompleteSingleChoices;
|
private boolean autoCompleteSingleChoices;
|
||||||
/**
|
/**
|
||||||
@@ -166,8 +165,8 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private Object oldTriggerKey;
|
private Object oldTriggerKey;
|
||||||
/**
|
/**
|
||||||
* The action previously assigned to {@link #trigger}, so we can reset it if
|
* The action previously assigned to {@link #trigger}, so we can reset it if the
|
||||||
* the user disables auto-completion.
|
* user disables auto-completion.
|
||||||
*/
|
*/
|
||||||
private Action oldTriggerAction;
|
private Action oldTriggerAction;
|
||||||
/**
|
/**
|
||||||
@@ -186,8 +185,8 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private ParentWindowListener parentWindowListener;
|
private ParentWindowListener parentWindowListener;
|
||||||
/**
|
/**
|
||||||
* Listens for events from the text component that affect the visibility of
|
* Listens for events from the text component that affect the visibility of the
|
||||||
* the popup windows.
|
* popup windows.
|
||||||
*/
|
*/
|
||||||
private TextComponentListener textComponentListener;
|
private TextComponentListener textComponentListener;
|
||||||
/**
|
/**
|
||||||
@@ -210,14 +209,14 @@ public class AutoCompletion {
|
|||||||
private EventListenerList listeners;
|
private EventListenerList listeners;
|
||||||
/**
|
/**
|
||||||
* Whether or not the popup should be hidden when user types a space (or any
|
* Whether or not the popup should be hidden when user types a space (or any
|
||||||
* character that resets the completion list to "all completions"). Defaults
|
* character that resets the completion list to "all completions"). Defaults to
|
||||||
* to true.
|
* true.
|
||||||
*/
|
*/
|
||||||
private boolean hideOnNoText;
|
private boolean hideOnNoText;
|
||||||
/**
|
/**
|
||||||
* Whether or not the popup should be hidden when the CompletionProvider
|
* Whether or not the popup should be hidden when the CompletionProvider
|
||||||
* changes. If set to false, caller has to ensure refresh of the popup
|
* changes. If set to false, caller has to ensure refresh of the popup content.
|
||||||
* content. Defaults to true.
|
* Defaults to true.
|
||||||
*/
|
*/
|
||||||
private boolean hideOnCompletionProviderChange;
|
private boolean hideOnCompletionProviderChange;
|
||||||
/**
|
/**
|
||||||
@@ -229,21 +228,18 @@ public class AutoCompletion {
|
|||||||
*/
|
*/
|
||||||
private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart";
|
private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart";
|
||||||
/**
|
/**
|
||||||
* Stores how to render auto-completion-specific highlights in text
|
* Stores how to render auto-completion-specific highlights in text components.
|
||||||
* components.
|
|
||||||
*/
|
*/
|
||||||
private static final AutoCompletionStyleContext styleContext = new AutoCompletionStyleContext();
|
private static final AutoCompletionStyleContext styleContext = new AutoCompletionStyleContext();
|
||||||
/**
|
/**
|
||||||
* Whether debug messages should be printed to stdout as AutoCompletion
|
* Whether debug messages should be printed to stdout as AutoCompletion runs.
|
||||||
* runs.
|
|
||||||
*/
|
*/
|
||||||
private static final boolean DEBUG = initDebug();
|
private static final boolean DEBUG = initDebug();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The completion provider. This cannot be <code>null</code>
|
||||||
* The completion provider. This cannot be <code>null</code>
|
|
||||||
*/
|
*/
|
||||||
public AutoCompletion(CompletionProvider provider) {
|
public AutoCompletion(CompletionProvider provider) {
|
||||||
setChoicesWindowSize(350, 200);
|
setChoicesWindowSize(350, 200);
|
||||||
@@ -267,8 +263,7 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Adds a listener interested in popup window events from this instance.
|
* Adds a listener interested in popup window events from this instance.
|
||||||
*
|
*
|
||||||
* @param l
|
* @param l The listener to add.
|
||||||
* The listener to add.
|
|
||||||
* @see #removeAutoCompletionListener(AutoCompletionListener)
|
* @see #removeAutoCompletionListener(AutoCompletionListener)
|
||||||
*/
|
*/
|
||||||
public void addAutoCompletionListener(AutoCompletionListener l) {
|
public void addAutoCompletionListener(AutoCompletionListener l) {
|
||||||
@@ -286,8 +281,7 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Fires an {@link AutoCompletionEvent} of the specified type.
|
* Fires an {@link AutoCompletionEvent} of the specified type.
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type The type of event to fire.
|
||||||
* The type of event to fire.
|
|
||||||
*/
|
*/
|
||||||
protected void fireAutoCompletionEvent(AutoCompletionEvent.Type type) {
|
protected void fireAutoCompletionEvent(AutoCompletionEvent.Type type) {
|
||||||
// Guaranteed to return a non-null array
|
// Guaranteed to return a non-null array
|
||||||
@@ -306,8 +300,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the delay between when the user types a character and when the
|
* Returns the delay between when the user types a character and when the code
|
||||||
* code completion popup should automatically appear (if applicable).
|
* completion popup should automatically appear (if applicable).
|
||||||
*
|
*
|
||||||
* @return The delay, in milliseconds.
|
* @return The delay, in milliseconds.
|
||||||
* @see #setAutoActivationDelay(int)
|
* @see #setAutoActivationDelay(int)
|
||||||
@@ -317,8 +311,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether, if a single auto-complete choice is available, it should
|
* Returns whether, if a single auto-complete choice is available, it should be
|
||||||
* be automatically inserted, without displaying the popup menu.
|
* automatically inserted, without displaying the popup menu.
|
||||||
*
|
*
|
||||||
* @return Whether to auto-complete single choices.
|
* @return Whether to auto-complete single choices.
|
||||||
* @see #setAutoCompleteSingleChoices(boolean)
|
* @see #setAutoCompleteSingleChoices(boolean)
|
||||||
@@ -346,8 +340,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default auto-complete "trigger key" for this OS. For Windows,
|
* Returns the default auto-complete "trigger key" for this OS. For Windows, for
|
||||||
* for example, it is Ctrl+Space.
|
* example, it is Ctrl+Space.
|
||||||
*
|
*
|
||||||
* @return The default auto-complete trigger key.
|
* @return The default auto-complete trigger key.
|
||||||
*/
|
*/
|
||||||
@@ -358,8 +352,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the handler to use when an external URL is clicked in the
|
* Returns the handler to use when an external URL is clicked in the description
|
||||||
* description window.
|
* window.
|
||||||
*
|
*
|
||||||
* @return The handler.
|
* @return The handler.
|
||||||
* @see #setExternalURLHandler(ExternalURLHandler)
|
* @see #setExternalURLHandler(ExternalURLHandler)
|
||||||
@@ -386,8 +380,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default list cell renderer used when a completion provider
|
* Returns the default list cell renderer used when a completion provider does
|
||||||
* does not supply its own.
|
* not supply its own.
|
||||||
*
|
*
|
||||||
* @return The default list cell renderer.
|
* @return The default list cell renderer.
|
||||||
* @see #setListCellRenderer(ListCellRenderer)
|
* @see #setListCellRenderer(ListCellRenderer)
|
||||||
@@ -397,10 +391,10 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the renderer to use for {@link Completion}s in the optional
|
* Returns the renderer to use for {@link Completion}s in the optional parameter
|
||||||
* parameter choices popup window (displayed when a
|
* choices popup window (displayed when a {@link ParameterizedCompletion} is
|
||||||
* {@link ParameterizedCompletion} is code-completed). If this returns
|
* code-completed). If this returns <code>null</code>, a default renderer is
|
||||||
* <code>null</code>, a default renderer is used.
|
* used.
|
||||||
*
|
*
|
||||||
* @return The renderer to use.
|
* @return The renderer to use.
|
||||||
* @see #setParamChoicesRenderer(ListCellRenderer)
|
* @see #setParamChoicesRenderer(ListCellRenderer)
|
||||||
@@ -417,14 +411,10 @@ public class AutoCompletion {
|
|||||||
* <tt>c.getReplacementText()</tt>. You usually will not need to modify this
|
* <tt>c.getReplacementText()</tt>. You usually will not need to modify this
|
||||||
* method.
|
* method.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c The completion being inserted.
|
||||||
* The completion being inserted.
|
* @param doc The document being modified.
|
||||||
* @param doc
|
* @param start The start of the text being replaced.
|
||||||
* The document being modified.
|
* @param len The length of the text being replaced.
|
||||||
* @param start
|
|
||||||
* The start of the text being replaced.
|
|
||||||
* @param len
|
|
||||||
* The length of the text being replaced.
|
|
||||||
* @return The text to replace with.
|
* @return The text to replace with.
|
||||||
*/
|
*/
|
||||||
protected String getReplacementText(Completion c, Document doc, int start, int len) {
|
protected String getReplacementText(Completion c, Document doc, int start, int len) {
|
||||||
@@ -443,8 +433,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the style context describing how auto-completion related
|
* Returns the style context describing how auto-completion related highlights
|
||||||
* highlights in the editor are rendered.
|
* in the editor are rendered.
|
||||||
*
|
*
|
||||||
* @return The style context.
|
* @return The style context.
|
||||||
*/
|
*/
|
||||||
@@ -466,8 +456,8 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Returns the orientation of the text component we're installed to.
|
* Returns the orientation of the text component we're installed to.
|
||||||
*
|
*
|
||||||
* @return The orientation of the text component, or <code>null</code> if we
|
* @return The orientation of the text component, or <code>null</code> if we are
|
||||||
* are not installed on one.
|
* not installed on one.
|
||||||
*/
|
*/
|
||||||
ComponentOrientation getTextComponentOrientation() {
|
ComponentOrientation getTextComponentOrientation() {
|
||||||
return textComponent == null ? null : textComponent.getComponentOrientation();
|
return textComponent == null ? null : textComponent.getComponentOrientation();
|
||||||
@@ -525,8 +515,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether debug should be enabled for the AutoCompletion
|
* Determines whether debug should be enabled for the AutoCompletion library.
|
||||||
* library. This method checks a system property, but takes care of
|
* This method checks a system property, but takes care of
|
||||||
* {@link SecurityException}s in case we're in an applet or WebStart.
|
* {@link SecurityException}s in case we're in an applet or WebStart.
|
||||||
*
|
*
|
||||||
* @return Whether debug should be enabled.
|
* @return Whether debug should be enabled.
|
||||||
@@ -545,8 +535,7 @@ public class AutoCompletion {
|
|||||||
* Inserts a completion. Any time a code completion event occurs, the actual
|
* Inserts a completion. Any time a code completion event occurs, the actual
|
||||||
* text insertion happens through this method.
|
* text insertion happens through this method.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c A completion to insert. This cannot be <code>null</code>.
|
||||||
* A completion to insert. This cannot be <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
protected final void insertCompletion(Completion c) {
|
protected final void insertCompletion(Completion c) {
|
||||||
insertCompletion(c, false);
|
insertCompletion(c, false);
|
||||||
@@ -556,11 +545,11 @@ public class AutoCompletion {
|
|||||||
* Inserts a completion. Any time a code completion event occurs, the actual
|
* Inserts a completion. Any time a code completion event occurs, the actual
|
||||||
* text insertion happens through this method.
|
* text insertion happens through this method.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c A completion to insert. This cannot be
|
||||||
* A completion to insert. This cannot be <code>null</code>.
|
* <code>null</code>.
|
||||||
* @param typedParamListStartChar
|
* @param typedParamListStartChar Whether the parameterized completion start
|
||||||
* Whether the parameterized completion start
|
* character was typed (typically
|
||||||
* character was typed (typically <code>'('</code>).
|
* <code>'('</code>).
|
||||||
*/
|
*/
|
||||||
protected void insertCompletion(Completion c, boolean typedParamListStartChar) {
|
protected void insertCompletion(Completion c, boolean typedParamListStartChar) {
|
||||||
JTextComponent textComp = getTextComponent();
|
JTextComponent textComp = getTextComponent();
|
||||||
@@ -582,11 +571,10 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs this auto-completion on a text component. If this
|
* Installs this auto-completion on a text component. If this
|
||||||
* {@link AutoCompletion} is already installed on another text component,
|
* {@link AutoCompletion} is already installed on another text component, it is
|
||||||
* it is uninstalled first.
|
* uninstalled first.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c The text component.
|
||||||
* The text component.
|
|
||||||
* @see #uninstall()
|
* @see #uninstall()
|
||||||
*/
|
*/
|
||||||
public void install(JTextComponent c) {
|
public void install(JTextComponent c) {
|
||||||
@@ -624,8 +612,7 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Installs a "trigger key" action onto the current text component.
|
* Installs a "trigger key" action onto the current text component.
|
||||||
*
|
*
|
||||||
* @param ks
|
* @param ks The keystroke that should trigger the action.
|
||||||
* The keystroke that should trigger the action.
|
|
||||||
* @see #uninstallTriggerKey()
|
* @see #uninstallTriggerKey()
|
||||||
*/
|
*/
|
||||||
private void installTriggerKey(KeyStroke ks) {
|
private void installTriggerKey(KeyStroke ks) {
|
||||||
@@ -639,9 +626,9 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns the action to call when the user presses the
|
* Creates and returns the action to call when the user presses the
|
||||||
* auto-completion trigger key (e.g. ctrl+space). This is a hook for
|
* auto-completion trigger key (e.g. ctrl+space). This is a hook for subclasses
|
||||||
* subclasses that want to provide their own behavior in this scenario.
|
* that want to provide their own behavior in this scenario. The default
|
||||||
* The default implementation returns an {@link AutoCompleteAction}.
|
* implementation returns an {@link AutoCompleteAction}.
|
||||||
*
|
*
|
||||||
* @return The action to use.
|
* @return The action to use.
|
||||||
* @see AutoCompleteAction
|
* @see AutoCompleteAction
|
||||||
@@ -651,10 +638,10 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether auto-activation is enabled (that is, whether the
|
* Returns whether auto-activation is enabled (that is, whether the completion
|
||||||
* completion popup will automatically appear after a delay when the user
|
* popup will automatically appear after a delay when the user types an
|
||||||
* types an appropriate character). Note that this parameter will be ignored
|
* appropriate character). Note that this parameter will be ignored if
|
||||||
* if auto-completion is disabled.
|
* auto-completion is disabled.
|
||||||
*
|
*
|
||||||
* @return Whether auto-activation is enabled.
|
* @return Whether auto-activation is enabled.
|
||||||
* @see #setAutoActivationEnabled(boolean)
|
* @see #setAutoActivationEnabled(boolean)
|
||||||
@@ -677,8 +664,7 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the popup should be hidden when the CompletionProvider
|
* Whether or not the popup should be hidden when the CompletionProvider
|
||||||
* changes. If set to false, caller has to ensure refresh of the popup
|
* changes. If set to false, caller has to ensure refresh of the popup content.
|
||||||
* content.
|
|
||||||
*
|
*
|
||||||
* @return Whether the popup should be hidden when the completion provider
|
* @return Whether the popup should be hidden when the completion provider
|
||||||
* changes.
|
* changes.
|
||||||
@@ -689,11 +675,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the popup should be hidden when user types a space (or
|
* Whether or not the popup should be hidden when user types a space (or any
|
||||||
* any character that resets the completion list to "all completions").
|
* character that resets the completion list to "all completions").
|
||||||
*
|
*
|
||||||
* @return Whether the popup should be hidden when the completion list is
|
* @return Whether the popup should be hidden when the completion list is reset
|
||||||
* reset to show all completions.
|
* to show all completions.
|
||||||
* @see #setHideOnNoText(boolean)
|
* @see #setHideOnNoText(boolean)
|
||||||
*/
|
*/
|
||||||
protected boolean isHideOnNoText() {
|
protected boolean isHideOnNoText() {
|
||||||
@@ -720,12 +706,12 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the popup window. First, this method gets the possible
|
* Refreshes the popup window. First, this method gets the possible completions
|
||||||
* completions for the current caret position. If there are none, and the
|
* for the current caret position. If there are none, and the popup is visible,
|
||||||
* popup is visible, it is hidden. If there are some completions and the
|
* it is hidden. If there are some completions and the popup is hidden, it is
|
||||||
* popup is hidden, it is made visible and made to display the completions.
|
* made visible and made to display the completions. If there are some
|
||||||
* If there are some completions and the popup is visible, its list is
|
* completions and the popup is visible, its list is updated to the current set
|
||||||
* updated to the current set of completions.
|
* of completions.
|
||||||
*
|
*
|
||||||
* @return The current line number of the caret.
|
* @return The current line number of the caret.
|
||||||
*/
|
*/
|
||||||
@@ -749,7 +735,8 @@ public class AutoCompletion {
|
|||||||
final List<Completion> completions = provider.getCompletions(textComponent);
|
final List<Completion> completions = provider.getCompletions(textComponent);
|
||||||
int count = completions == null ? 0 : completions.size();
|
int count = completions == null ? 0 : completions.size();
|
||||||
if (count > 1 || (count == 1 && (isPopupVisible() || text.equals(completions.get(0).getInputText())))
|
if (count > 1 || (count == 1 && (isPopupVisible() || text.equals(completions.get(0).getInputText())))
|
||||||
|| (count == 1 && (isPopupVisible() || textLen == 0)) || (count == 1 && !getAutoCompleteSingleChoices())) {
|
|| (count == 1 && (isPopupVisible() || textLen == 0))
|
||||||
|
|| (count == 1 && !getAutoCompleteSingleChoices())) {
|
||||||
if (popupWindow == null) {
|
if (popupWindow == null) {
|
||||||
popupWindow = new AutoCompletePopupWindow(parentWindow, this);
|
popupWindow = new AutoCompletePopupWindow(parentWindow, this);
|
||||||
popupWindowListener.install(popupWindow);
|
popupWindowListener.install(popupWindow);
|
||||||
@@ -800,8 +787,7 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Removes a listener interested in popup window events from this instance.
|
* Removes a listener interested in popup window events from this instance.
|
||||||
*
|
*
|
||||||
* @param l
|
* @param l The listener to remove.
|
||||||
* The listener to remove.
|
|
||||||
* @see #addAutoCompletionListener(AutoCompletionListener)
|
* @see #addAutoCompletionListener(AutoCompletionListener)
|
||||||
*/
|
*/
|
||||||
public void removeAutoCompletionListener(AutoCompletionListener l) {
|
public void removeAutoCompletionListener(AutoCompletionListener l) {
|
||||||
@@ -812,8 +798,7 @@ public class AutoCompletion {
|
|||||||
* Sets the delay between when the user types a character and when the code
|
* Sets the delay between when the user types a character and when the code
|
||||||
* completion popup should automatically appear (if applicable).
|
* completion popup should automatically appear (if applicable).
|
||||||
*
|
*
|
||||||
* @param ms
|
* @param ms The delay, in milliseconds. This should be greater than zero.
|
||||||
* The delay, in milliseconds. This should be greater than zero.
|
|
||||||
* @see #getAutoActivationDelay()
|
* @see #getAutoActivationDelay()
|
||||||
*/
|
*/
|
||||||
public void setAutoActivationDelay(int ms) {
|
public void setAutoActivationDelay(int ms) {
|
||||||
@@ -823,11 +808,10 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles whether auto-activation is enabled. Note that auto-activation
|
* Toggles whether auto-activation is enabled. Note that auto-activation also
|
||||||
* also depends on auto-completion itself being enabled.
|
* depends on auto-completion itself being enabled.
|
||||||
*
|
*
|
||||||
* @param enabled
|
* @param enabled Whether auto-activation is enabled.
|
||||||
* Whether auto-activation is enabled.
|
|
||||||
* @see #isAutoActivationEnabled()
|
* @see #isAutoActivationEnabled()
|
||||||
* @see #setAutoActivationDelay(int)
|
* @see #setAutoActivationDelay(int)
|
||||||
*/
|
*/
|
||||||
@@ -847,8 +831,7 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets whether auto-completion is enabled.
|
* Sets whether auto-completion is enabled.
|
||||||
*
|
*
|
||||||
* @param enabled
|
* @param enabled Whether auto-completion is enabled.
|
||||||
* Whether auto-completion is enabled.
|
|
||||||
* @see #isAutoCompleteEnabled()
|
* @see #isAutoCompleteEnabled()
|
||||||
*/
|
*/
|
||||||
public void setAutoCompleteEnabled(boolean enabled) {
|
public void setAutoCompleteEnabled(boolean enabled) {
|
||||||
@@ -862,8 +845,7 @@ public class AutoCompletion {
|
|||||||
* Sets whether, if a single auto-complete choice is available, it should be
|
* Sets whether, if a single auto-complete choice is available, it should be
|
||||||
* automatically inserted, without displaying the popup menu.
|
* automatically inserted, without displaying the popup menu.
|
||||||
*
|
*
|
||||||
* @param autoComplete
|
* @param autoComplete Whether to auto-complete single choices.
|
||||||
* Whether to auto-complete single choices.
|
|
||||||
* @see #getAutoCompleteSingleChoices()
|
* @see #getAutoCompleteSingleChoices()
|
||||||
*/
|
*/
|
||||||
public void setAutoCompleteSingleChoices(boolean autoComplete) {
|
public void setAutoCompleteSingleChoices(boolean autoComplete) {
|
||||||
@@ -873,11 +855,9 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the completion provider being used.
|
* Sets the completion provider being used.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The new completion provider. This cannot be
|
||||||
* The new completion provider. This cannot be
|
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException If <code>provider</code> is
|
||||||
* If <code>provider</code> is
|
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public void setCompletionProvider(CompletionProvider provider) {
|
public void setCompletionProvider(CompletionProvider provider) {
|
||||||
@@ -893,10 +873,8 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the size of the completion choices window.
|
* Sets the size of the completion choices window.
|
||||||
*
|
*
|
||||||
* @param w
|
* @param w The new width.
|
||||||
* The new width.
|
* @param h The new height.
|
||||||
* @param h
|
|
||||||
* The new height.
|
|
||||||
* @see #setDescriptionWindowSize(int, int)
|
* @see #setDescriptionWindowSize(int, int)
|
||||||
*/
|
*/
|
||||||
public void setChoicesWindowSize(int w, int h) {
|
public void setChoicesWindowSize(int w, int h) {
|
||||||
@@ -909,10 +887,8 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the size of the description window.
|
* Sets the size of the description window.
|
||||||
*
|
*
|
||||||
* @param w
|
* @param w The new width.
|
||||||
* The new width.
|
* @param h The new height.
|
||||||
* @param h
|
|
||||||
* The new height.
|
|
||||||
* @see #setChoicesWindowSize(int, int)
|
* @see #setChoicesWindowSize(int, int)
|
||||||
*/
|
*/
|
||||||
public void setDescriptionWindowSize(int w, int h) {
|
public void setDescriptionWindowSize(int w, int h) {
|
||||||
@@ -923,15 +899,14 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the handler to use when an external URL is clicked in the
|
* Sets the handler to use when an external URL is clicked in the description
|
||||||
* description window. This handler can perform some action, such as open
|
* window. This handler can perform some action, such as open the URL in a web
|
||||||
* the URL in a web browser. The default implementation will open the URL in
|
* browser. The default implementation will open the URL in a browser, but only
|
||||||
* a browser, but only if running in Java 6. If you want browser support for
|
* if running in Java 6. If you want browser support for Java 5 and below, or
|
||||||
* Java 5 and below, or otherwise want to respond to hyperlink clicks, you
|
* otherwise want to respond to hyperlink clicks, you will have to install your
|
||||||
* will have to install your own handler to do so.
|
* own handler to do so.
|
||||||
*
|
*
|
||||||
* @param handler
|
* @param handler The new handler.
|
||||||
* The new handler.
|
|
||||||
* @see #getExternalURLHandler()
|
* @see #getExternalURLHandler()
|
||||||
*/
|
*/
|
||||||
public void setExternalURLHandler(ExternalURLHandler handler) {
|
public void setExternalURLHandler(ExternalURLHandler handler) {
|
||||||
@@ -939,13 +914,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not the popup should be hidden when the
|
* Sets whether or not the popup should be hidden when the CompletionProvider
|
||||||
* CompletionProvider changes. If set to false, caller has to ensure refresh
|
* changes. If set to false, caller has to ensure refresh of the popup content.
|
||||||
* of the popup content.
|
|
||||||
*
|
*
|
||||||
* @param hideOnCompletionProviderChange
|
* @param hideOnCompletionProviderChange Whether the popup should be hidden when
|
||||||
* Whether the popup should be hidden
|
* the completion provider changes.
|
||||||
* when the completion provider changes.
|
|
||||||
* @see #isHideOnCompletionProviderChange()
|
* @see #isHideOnCompletionProviderChange()
|
||||||
*/
|
*/
|
||||||
protected void setHideOnCompletionProviderChange(boolean hideOnCompletionProviderChange) {
|
protected void setHideOnCompletionProviderChange(boolean hideOnCompletionProviderChange) {
|
||||||
@@ -953,12 +926,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not the popup should be hidden when user types a space
|
* Sets whether or not the popup should be hidden when user types a space (or
|
||||||
* (or any character that resets the completion list to "all completions").
|
* any character that resets the completion list to "all completions").
|
||||||
*
|
*
|
||||||
* @param hideOnNoText
|
* @param hideOnNoText Whether the popup sh ould be hidden when the completion
|
||||||
* Whether the popup sh ould be hidden when the
|
* list is reset to show all completions.
|
||||||
* completion list is reset to show all completions.
|
|
||||||
* @see #isHideOnNoText()
|
* @see #isHideOnNoText()
|
||||||
*/
|
*/
|
||||||
protected void setHideOnNoText(boolean hideOnNoText) {
|
protected void setHideOnNoText(boolean hideOnNoText) {
|
||||||
@@ -967,12 +939,10 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the redirector for external URL's found in code completion
|
* Sets the redirector for external URL's found in code completion
|
||||||
* documentation. When a non-local link in completion popups is clicked,
|
* documentation. When a non-local link in completion popups is clicked, this
|
||||||
* this redirector is given the chance to modify the URL fetched and
|
* redirector is given the chance to modify the URL fetched and displayed.
|
||||||
* displayed.
|
|
||||||
*
|
*
|
||||||
* @param linkRedirector
|
* @param linkRedirector The link redirector, or <code>null</code> for none.
|
||||||
* The link redirector, or <code>null</code> for none.
|
|
||||||
* @see #getLinkRedirector()
|
* @see #getLinkRedirector()
|
||||||
*/
|
*/
|
||||||
public static void setLinkRedirector(LinkRedirector linkRedirector) {
|
public static void setLinkRedirector(LinkRedirector linkRedirector) {
|
||||||
@@ -980,12 +950,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the default list cell renderer to use when a completion provider
|
* Sets the default list cell renderer to use when a completion provider does
|
||||||
* does not supply its own.
|
* not supply its own.
|
||||||
*
|
*
|
||||||
* @param renderer
|
* @param renderer The renderer to use. If this is <code>null</code>, a default
|
||||||
* The renderer to use. If this is <code>null</code>, a
|
* renderer is used.
|
||||||
* default renderer is used.
|
|
||||||
* @see #getListCellRenderer()
|
* @see #getListCellRenderer()
|
||||||
*/
|
*/
|
||||||
public void setListCellRenderer(ListCellRenderer renderer) {
|
public void setListCellRenderer(ListCellRenderer renderer) {
|
||||||
@@ -997,13 +966,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the renderer to use for {@link Completion}s in the optional
|
* Sets the renderer to use for {@link Completion}s in the optional parameter
|
||||||
* parameter choices popup window (displayed when a
|
* choices popup window (displayed when a {@link ParameterizedCompletion} is
|
||||||
* {@link ParameterizedCompletion} is code-completed). If this isn't set, a
|
* code-completed). If this isn't set, a default renderer is used.
|
||||||
* default renderer is used.
|
|
||||||
*
|
*
|
||||||
* @param r
|
* @param r The renderer to use.
|
||||||
* The renderer to use.
|
|
||||||
* @see #getParamChoicesRenderer()
|
* @see #getParamChoicesRenderer()
|
||||||
* @see #setParameterAssistanceEnabled(boolean)
|
* @see #setParameterAssistanceEnabled(boolean)
|
||||||
*/
|
*/
|
||||||
@@ -1013,13 +980,12 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether parameter assistance is enabled. If parameter assistance is
|
* Sets whether parameter assistance is enabled. If parameter assistance is
|
||||||
* enabled, and a "parameterized" completion (such as a function or method)
|
* enabled, and a "parameterized" completion (such as a function or method) is
|
||||||
* is inserted, the user will get "assistance" in inserting the parameters
|
* inserted, the user will get "assistance" in inserting the parameters in the
|
||||||
* in the form of a popup window with documentation and easy tabbing through
|
* form of a popup window with documentation and easy tabbing through the
|
||||||
* the arguments (as seen in Eclipse and NetBeans).
|
* arguments (as seen in Eclipse and NetBeans).
|
||||||
*
|
*
|
||||||
* @param enabled
|
* @param enabled Whether parameter assistance should be enabled.
|
||||||
* Whether parameter assistance should be enabled.
|
|
||||||
* @see #isParameterAssistanceEnabled()
|
* @see #isParameterAssistanceEnabled()
|
||||||
*/
|
*/
|
||||||
public void setParameterAssistanceEnabled(boolean enabled) {
|
public void setParameterAssistanceEnabled(boolean enabled) {
|
||||||
@@ -1027,11 +993,10 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the visibility of the auto-completion popup window. This fires
|
* Toggles the visibility of the auto-completion popup window. This fires an
|
||||||
* an {@link AutoCompletionEvent} of the appropriate type.
|
* {@link AutoCompletionEvent} of the appropriate type.
|
||||||
*
|
*
|
||||||
* @param visible
|
* @param visible Whether the window should be made visible or hidden.
|
||||||
* Whether the window should be made visible or hidden.
|
|
||||||
* @see #isPopupVisible()
|
* @see #isPopupVisible()
|
||||||
*/
|
*/
|
||||||
protected void setPopupVisible(boolean visible) {
|
protected void setPopupVisible(boolean visible) {
|
||||||
@@ -1041,11 +1006,10 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the "description window" should be shown beside the
|
* Sets whether the "description window" should be shown beside the completion
|
||||||
* completion window.
|
* window.
|
||||||
*
|
*
|
||||||
* @param show
|
* @param show Whether to show the description window.
|
||||||
* Whether to show the description window.
|
|
||||||
* @see #getShowDescWindow()
|
* @see #getShowDescWindow()
|
||||||
*/
|
*/
|
||||||
public void setShowDescWindow(boolean show) {
|
public void setShowDescWindow(boolean show) {
|
||||||
@@ -1057,10 +1021,8 @@ public class AutoCompletion {
|
|||||||
* Sets the keystroke that should be used to trigger the auto-complete popup
|
* Sets the keystroke that should be used to trigger the auto-complete popup
|
||||||
* window.
|
* window.
|
||||||
*
|
*
|
||||||
* @param ks
|
* @param ks The keystroke.
|
||||||
* The keystroke.
|
* @throws IllegalArgumentException If <code>ks</code> is <code>null</code>.
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* If <code>ks</code> is <code>null</code>.
|
|
||||||
* @see #getTriggerKey()
|
* @see #getTriggerKey()
|
||||||
*/
|
*/
|
||||||
public void setTriggerKey(KeyStroke ks) {
|
public void setTriggerKey(KeyStroke ks) {
|
||||||
@@ -1081,10 +1043,8 @@ public class AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Displays a "tool tip" detailing the inputs to the function just entered.
|
* Displays a "tool tip" detailing the inputs to the function just entered.
|
||||||
*
|
*
|
||||||
* @param pc
|
* @param pc The completion.
|
||||||
* The completion.
|
* @param typedParamListStartChar Whether the parameterized completion list
|
||||||
* @param typedParamListStartChar
|
|
||||||
* Whether the parameterized completion list
|
|
||||||
* starting character was typed.
|
* starting character was typed.
|
||||||
*/
|
*/
|
||||||
private void startParameterizedCompletionAssistance(ParameterizedCompletion pc, boolean typedParamListStartChar) {
|
private void startParameterizedCompletionAssistance(ParameterizedCompletion pc, boolean typedParamListStartChar) {
|
||||||
@@ -1159,8 +1119,7 @@ public class AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the LookAndFeel of the popup window. Applications can call this
|
* Updates the LookAndFeel of the popup window. Applications can call this
|
||||||
* method as appropriate if they support changing the LookAndFeel at
|
* method as appropriate if they support changing the LookAndFeel at runtime.
|
||||||
* runtime.
|
|
||||||
*/
|
*/
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
if (popupWindow != null) {
|
if (popupWindow != null) {
|
||||||
@@ -1176,10 +1135,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for events in the text component to auto-activate the code
|
* Listens for events in the text component to auto-activate the code completion
|
||||||
* completion popup.
|
* popup.
|
||||||
*/
|
*/
|
||||||
private class AutoActivationListener extends FocusAdapter implements DocumentListener, CaretListener, ActionListener {
|
private class AutoActivationListener extends FocusAdapter
|
||||||
|
implements DocumentListener, CaretListener, ActionListener {
|
||||||
|
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private boolean justInserted;
|
private boolean justInserted;
|
||||||
@@ -1250,8 +1210,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <code>Action</code> that displays the popup window if auto-completion
|
* The <code>Action</code> that displays the popup window if auto-completion is
|
||||||
* is enabled.
|
* enabled.
|
||||||
*/
|
*/
|
||||||
protected class AutoCompleteAction extends AbstractAction {
|
protected class AutoCompleteAction extends AbstractAction {
|
||||||
|
|
||||||
@@ -1340,7 +1300,8 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowGainedFocus(WindowEvent e) {}
|
public void windowGainedFocus(WindowEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowLostFocus(WindowEvent e) {
|
public void windowLostFocus(WindowEvent e) {
|
||||||
@@ -1393,12 +1354,11 @@ public class AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the component hierarchy for our text component changes.
|
* Called when the component hierarchy for our text component changes. When the
|
||||||
* When the text component is added to a new {@link Window}, this method
|
* text component is added to a new {@link Window}, this method registers
|
||||||
* registers listeners on that <code>Window</code>.
|
* listeners on that <code>Window</code>.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void hierarchyChanged(HierarchyEvent e) {
|
public void hierarchyChanged(HierarchyEvent e) {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ package org.fife.ui.autocomplete;
|
|||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event fired by an instance of {@link AutoCompletion}. This can be
|
* An event fired by an instance of {@link AutoCompletion}. This can be used by
|
||||||
* used by applications that wish to be notified of the auto-complete popup
|
* applications that wish to be notified of the auto-complete popup window
|
||||||
* window showing and hiding.
|
* showing and hiding.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -25,11 +25,8 @@ public class AutoCompletionEvent extends EventObject {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param source
|
* @param source The <code>AutoCompletion</code> instance that fired this event.
|
||||||
* The <code>AutoCompletion</code> instance that fired
|
* @param type The event type.
|
||||||
* this event.
|
|
||||||
* @param type
|
|
||||||
* The event type.
|
|
||||||
*/
|
*/
|
||||||
public AutoCompletionEvent(AutoCompletion source, Type type) {
|
public AutoCompletionEvent(AutoCompletion source, Type type) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|||||||
@@ -17,11 +17,10 @@ import java.util.EventListener;
|
|||||||
public interface AutoCompletionListener extends EventListener {
|
public interface AutoCompletionListener extends EventListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback notified when a change to the <code>AutoCompletion</code>'s
|
* Callback notified when a change to the <code>AutoCompletion</code>'s status
|
||||||
* status occurs.
|
* occurs.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
void autoCompleteUpdate(AutoCompletionEvent e);
|
void autoCompleteUpdate(AutoCompletionEvent e);
|
||||||
}
|
}
|
||||||
@@ -22,13 +22,13 @@ public class AutoCompletionStyleContext {
|
|||||||
*/
|
*/
|
||||||
private Color parameterizedCompletionCursorPositionColor;
|
private Color parameterizedCompletionCursorPositionColor;
|
||||||
/**
|
/**
|
||||||
* The color used to highlight copies of editable parameters in
|
* The color used to highlight copies of editable parameters in parameterized
|
||||||
* parameterized completions.
|
* completions.
|
||||||
*/
|
*/
|
||||||
private Color parameterCopyColor;
|
private Color parameterCopyColor;
|
||||||
/**
|
/**
|
||||||
* The color of the outline highlight used to denote editable parameters
|
* The color of the outline highlight used to denote editable parameters in
|
||||||
* in parameterized completions.
|
* parameterized completions.
|
||||||
*/
|
*/
|
||||||
private Color parameterOutlineColor;
|
private Color parameterOutlineColor;
|
||||||
|
|
||||||
@@ -39,8 +39,8 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color of the highlight painted on copies of editable
|
* Returns the color of the highlight painted on copies of editable parameters
|
||||||
* parameters in parameterized completions.
|
* in parameterized completions.
|
||||||
*
|
*
|
||||||
* @return The color used.
|
* @return The color used.
|
||||||
* @see #setParameterCopyColor(Color)
|
* @see #setParameterCopyColor(Color)
|
||||||
@@ -50,8 +50,8 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color used to denote the ending caret position for
|
* Returns the color used to denote the ending caret position for parameterized
|
||||||
* parameterized completions.
|
* completions.
|
||||||
*
|
*
|
||||||
* @return The color used.
|
* @return The color used.
|
||||||
* @see #setParameterizedCompletionCursorPositionColor(Color)
|
* @see #setParameterizedCompletionCursorPositionColor(Color)
|
||||||
@@ -61,8 +61,8 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color of the outline highlight used to denote editable
|
* Returns the color of the outline highlight used to denote editable parameters
|
||||||
* parameters in parameterized completions.
|
* in parameterized completions.
|
||||||
*
|
*
|
||||||
* @return The color used.
|
* @return The color used.
|
||||||
* @see #setParameterOutlineColor(Color)
|
* @see #setParameterOutlineColor(Color)
|
||||||
@@ -72,11 +72,10 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color of the highlight painted on copies of editable
|
* Sets the color of the highlight painted on copies of editable parameters in
|
||||||
* parameters in parameterized completions.
|
* parameterized completions.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use.
|
||||||
* The color to use.
|
|
||||||
* @see #setParameterCopyColor(Color)
|
* @see #setParameterCopyColor(Color)
|
||||||
*/
|
*/
|
||||||
public void setParameterCopyColor(Color color) {
|
public void setParameterCopyColor(Color color) {
|
||||||
@@ -84,11 +83,10 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color used to denote the ending caret position for
|
* Sets the color used to denote the ending caret position for parameterized
|
||||||
* parameterized completions.
|
* completions.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use.
|
||||||
* The color to use.
|
|
||||||
* @see #getParameterizedCompletionCursorPositionColor()
|
* @see #getParameterizedCompletionCursorPositionColor()
|
||||||
*/
|
*/
|
||||||
public void setParameterizedCompletionCursorPositionColor(Color color) {
|
public void setParameterizedCompletionCursorPositionColor(Color color) {
|
||||||
@@ -96,11 +94,10 @@ public class AutoCompletionStyleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color of the outline highlight used to denote editable
|
* Sets the color of the outline highlight used to denote editable parameters in
|
||||||
* parameters in parameterized completions.
|
* parameterized completions.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use.
|
||||||
* The color to use.
|
|
||||||
* @see #getParameterOutlineColor()
|
* @see #getParameterOutlineColor()
|
||||||
*/
|
*/
|
||||||
public void setParameterOutlineColor(Color color) {
|
public void setParameterOutlineColor(Color color) {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
package org.fife.ui.autocomplete;
|
package org.fife.ui.autocomplete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A straightforward {@link Completion} implementation. This implementation
|
* A straightforward {@link Completion} implementation. This implementation can
|
||||||
* can be used if you have a relatively short number of static completions
|
* be used if you have a relatively short number of static completions with no
|
||||||
* with no (or short) summaries.
|
* (or short) summaries.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This implementation uses the replacement text as the input text. It also
|
* This implementation uses the replacement text as the input text. It also
|
||||||
@@ -28,10 +28,8 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent completion provider.
|
||||||
* The parent completion provider.
|
* @param replacementText The text to replace.
|
||||||
* @param replacementText
|
|
||||||
* The text to replace.
|
|
||||||
*/
|
*/
|
||||||
public BasicCompletion(CompletionProvider provider, String replacementText) {
|
public BasicCompletion(CompletionProvider provider, String replacementText) {
|
||||||
this(provider, replacementText, null);
|
this(provider, replacementText, null);
|
||||||
@@ -40,12 +38,9 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent completion provider.
|
||||||
* The parent completion provider.
|
* @param replacementText The text to replace.
|
||||||
* @param replacementText
|
* @param shortDesc A short description of the completion. This will be
|
||||||
* The text to replace.
|
|
||||||
* @param shortDesc
|
|
||||||
* A short description of the completion. This will be
|
|
||||||
* displayed in the completion list. This may be
|
* displayed in the completion list. This may be
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
@@ -56,16 +51,12 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent completion provider.
|
||||||
* The parent completion provider.
|
* @param replacementText The text to replace.
|
||||||
* @param replacementText
|
* @param shortDesc A short description of the completion. This will be
|
||||||
* The text to replace.
|
|
||||||
* @param shortDesc
|
|
||||||
* A short description of the completion. This will be
|
|
||||||
* displayed in the completion list. This may be
|
* displayed in the completion list. This may be
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @param summary
|
* @param summary The summary of this completion. This should be HTML.
|
||||||
* The summary of this completion. This should be HTML.
|
|
||||||
* This may be <code>null</code>.
|
* This may be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public BasicCompletion(CompletionProvider provider, String replacementText, String shortDesc, String summary) {
|
public BasicCompletion(CompletionProvider provider, String replacementText, String shortDesc, String summary) {
|
||||||
@@ -84,8 +75,8 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the short description of this completion, usually used in
|
* Returns the short description of this completion, usually used in the
|
||||||
* the completion choices list.
|
* completion choices list.
|
||||||
*
|
*
|
||||||
* @return The short description, or <code>null</code> if there is none.
|
* @return The short description, or <code>null</code> if there is none.
|
||||||
* @see #setShortDescription(String)
|
* @see #setShortDescription(String)
|
||||||
@@ -105,8 +96,7 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the short description of this completion.
|
* Sets the short description of this completion.
|
||||||
*
|
*
|
||||||
* @param shortDesc
|
* @param shortDesc The short description of this completion.
|
||||||
* The short description of this completion.
|
|
||||||
* @see #getShortDescription()
|
* @see #getShortDescription()
|
||||||
*/
|
*/
|
||||||
public void setShortDescription(String shortDesc) {
|
public void setShortDescription(String shortDesc) {
|
||||||
@@ -116,8 +106,7 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the summary for this completion.
|
* Sets the summary for this completion.
|
||||||
*
|
*
|
||||||
* @param summary
|
* @param summary The summary for this completion.
|
||||||
* The summary for this completion.
|
|
||||||
* @see #getSummary()
|
* @see #getSummary()
|
||||||
*/
|
*/
|
||||||
public void setSummary(String summary) {
|
public void setSummary(String summary) {
|
||||||
@@ -125,8 +114,8 @@ public class BasicCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string representation of this completion. If the short
|
* Returns a string representation of this completion. If the short description
|
||||||
* description is not <code>null</code>, this method will return:
|
* is not <code>null</code>, this method will return:
|
||||||
*
|
*
|
||||||
* <code>getInputText() + " - " + shortDesc</code>
|
* <code>getInputText() + " - " + shortDesc</code>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ import javax.swing.Icon;
|
|||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a completion choice. A {@link CompletionProvider} returns lists
|
* Represents a completion choice. A {@link CompletionProvider} returns lists of
|
||||||
* of objects implementing this interface. A <tt>Completion</tt> contains the
|
* objects implementing this interface. A <tt>Completion</tt> contains the
|
||||||
* following information:
|
* following information:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The text the user must (begin to) input for this to be a completion
|
* <li>The text the user must (begin to) input for this to be a completion
|
||||||
* choice.
|
* choice.
|
||||||
* <li>The text that will be filled in if the user chooses this completion.
|
* <li>The text that will be filled in if the user chooses this completion. Note
|
||||||
* Note that often, this is the same as the text the user must (begin to)
|
* that often, this is the same as the text the user must (begin to) enter, but
|
||||||
* enter, but this doesn't have to be the case.
|
* this doesn't have to be the case.
|
||||||
* <li>Summary HTML that describes this completion. This is information that
|
* <li>Summary HTML that describes this completion. This is information that can
|
||||||
* can be displayed in a helper "tooltip"-style window beside the
|
* be displayed in a helper "tooltip"-style window beside the completion list.
|
||||||
* completion list. This may be <code>null</code>. It may also be
|
* This may be <code>null</code>. It may also be lazily generated to cut down on
|
||||||
* lazily generated to cut down on memory usage.
|
* memory usage.
|
||||||
* <li>The <tt>CompletionProvider</tt> that returned this completion.
|
* <li>The <tt>CompletionProvider</tt> that returned this completion.
|
||||||
* <li>Tool tip text that can be displayed when a mouse hovers over this
|
* <li>Tool tip text that can be displayed when a mouse hovers over this
|
||||||
* completion in a text component.
|
* completion in a text component.
|
||||||
@@ -36,26 +36,23 @@ import javax.swing.text.JTextComponent;
|
|||||||
public interface Completion extends Comparable<Completion> {
|
public interface Completion extends Comparable<Completion> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares this completion to another one lexicographically, ignoring
|
* Compares this completion to another one lexicographically, ignoring case.
|
||||||
* case.
|
|
||||||
*
|
*
|
||||||
* @param other
|
* @param other Another completion instance.
|
||||||
* Another completion instance.
|
|
||||||
* @return How this completion compares to the other one.
|
* @return How this completion compares to the other one.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Completion other);
|
public int compareTo(Completion other);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the portion of this completion that has already been entered
|
* Returns the portion of this completion that has already been entered into the
|
||||||
* into the text component. The match is case-insensitive.
|
* text component. The match is case-insensitive.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This is a convenience method for:
|
* This is a convenience method for:
|
||||||
* <code>getProvider().getAlreadyEnteredText(comp)</code>.
|
* <code>getProvider().getAlreadyEnteredText(comp)</code>.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component.
|
||||||
* The text component.
|
|
||||||
* @return The already-entered portion of this completion.
|
* @return The already-entered portion of this completion.
|
||||||
*/
|
*/
|
||||||
public String getAlreadyEntered(JTextComponent comp);
|
public String getAlreadyEntered(JTextComponent comp);
|
||||||
@@ -68,14 +65,14 @@ public interface Completion extends Comparable<Completion> {
|
|||||||
public Icon getIcon();
|
public Icon getIcon();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text that the user has to (start) typing for this completion
|
* Returns the text that the user has to (start) typing for this completion to
|
||||||
* to be offered. Note that this will usually be the same value as
|
* be offered. Note that this will usually be the same value as
|
||||||
* {@link #getReplacementText()}, but not always (a completion could be
|
* {@link #getReplacementText()}, but not always (a completion could be a way to
|
||||||
* a way to implement shorthand, for example, "<code>sysout</code>" mapping
|
* implement shorthand, for example, "<code>sysout</code>" mapping to
|
||||||
* to "<code>System.out.println(</code>").
|
* "<code>System.out.println(</code>").
|
||||||
*
|
*
|
||||||
* @return The text the user has to (start) typing for this completion to
|
* @return The text the user has to (start) typing for this completion to be
|
||||||
* be offered.
|
* offered.
|
||||||
* @see #getReplacementText()
|
* @see #getReplacementText()
|
||||||
*/
|
*/
|
||||||
public String getInputText();
|
public String getInputText();
|
||||||
@@ -89,25 +86,25 @@ public interface Completion extends Comparable<Completion> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "relevance" of this completion. This is used when sorting
|
* Returns the "relevance" of this completion. This is used when sorting
|
||||||
* completions by their relevance. It is an abstract concept that may
|
* completions by their relevance. It is an abstract concept that may mean
|
||||||
* mean different things to different languages, and may depend on the
|
* different things to different languages, and may depend on the context of the
|
||||||
* context of the completion.
|
* completion.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* By default, all completions have a relevance of <code>0</code>. The
|
* By default, all completions have a relevance of <code>0</code>. The higher
|
||||||
* higher the value returned by this method, the higher up in the list
|
* the value returned by this method, the higher up in the list this completion
|
||||||
* this completion will be; the lower the value returned, the lower it will
|
* will be; the lower the value returned, the lower it will be.
|
||||||
* be. <code>Completion</code>s with equal relevance values will be
|
* <code>Completion</code>s with equal relevance values will be sorted
|
||||||
* sorted alphabetically.
|
* alphabetically.
|
||||||
*
|
*
|
||||||
* @return The relevance of this completion.
|
* @return The relevance of this completion.
|
||||||
*/
|
*/
|
||||||
public int getRelevance();
|
public int getRelevance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text to insert as the result of this auto-completion. This
|
* Returns the text to insert as the result of this auto-completion. This is the
|
||||||
* is the "complete" text, including any text that replaces what the user
|
* "complete" text, including any text that replaces what the user has already
|
||||||
* has already typed.
|
* typed.
|
||||||
*
|
*
|
||||||
* @return The replacement text.
|
* @return The replacement text.
|
||||||
* @see #getInputText()
|
* @see #getInputText()
|
||||||
@@ -115,31 +112,26 @@ public interface Completion extends Comparable<Completion> {
|
|||||||
public String getReplacementText();
|
public String getReplacementText();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the description of this auto-complete choice. This can be
|
* Returns the description of this auto-complete choice. This can be used in a
|
||||||
* used in a popup "description window."
|
* popup "description window."
|
||||||
*
|
*
|
||||||
* @return This item's description. This should be HTML. It may be
|
* @return This item's description. This should be HTML. It may be
|
||||||
* <code>null</code> if there is no description for this
|
* <code>null</code> if there is no description for this completion.
|
||||||
* completion.
|
|
||||||
*/
|
*/
|
||||||
public String getSummary();
|
public String getSummary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tool tip text to display for mouse hovers over this
|
* Returns the tool tip text to display for mouse hovers over this completion.
|
||||||
* completion.
|
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Note that for this functionality to be enabled, a
|
* Note that for this functionality to be enabled, a <tt>JTextComponent</tt>
|
||||||
* <tt>JTextComponent</tt> must be registered with the
|
* must be registered with the <tt>ToolTipManager</tt>, and the text component
|
||||||
* <tt>ToolTipManager</tt>, and the text component must know to search
|
* must know to search for this value. In the case of an
|
||||||
* for this value. In the case of an
|
* <a href="http://fifesoft.com/rsyntaxtextarea">RSyntaxTextArea</a>, this can
|
||||||
* <a href="http://fifesoft.com/rsyntaxtextarea">RSyntaxTextArea</a>, this
|
* be done with a <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> that calls into
|
||||||
* can be done with a <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> that
|
|
||||||
* calls into
|
|
||||||
* {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}.
|
* {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}.
|
||||||
*
|
*
|
||||||
* @return The tool tip text for this completion, or <code>null</code> if
|
* @return The tool tip text for this completion, or <code>null</code> if none.
|
||||||
* none.
|
|
||||||
*/
|
*/
|
||||||
public String getToolTipText();
|
public String getToolTipText();
|
||||||
}
|
}
|
||||||
@@ -26,8 +26,8 @@ import javax.swing.text.View;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A cell renderer that adds some pizazz when rendering the standard
|
* A cell renderer that adds some pizazz when rendering the standard
|
||||||
* {@link Completion} types, like Eclipse and NetBeans do. Specifically,
|
* {@link Completion} types, like Eclipse and NetBeans do. Specifically, this
|
||||||
* this renderer handles:
|
* renderer handles:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link FunctionCompletion}s</li>
|
* <li>{@link FunctionCompletion}s</li>
|
||||||
@@ -43,18 +43,18 @@ import javax.swing.text.View;
|
|||||||
public class CompletionCellRenderer extends DefaultListCellRenderer {
|
public class CompletionCellRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The alternating background color, or <code>null</code> if alternating
|
* The alternating background color, or <code>null</code> if alternating row
|
||||||
* row colors should not be used.
|
* colors should not be used.
|
||||||
*/
|
*/
|
||||||
private static Color altBG;
|
private static Color altBG;
|
||||||
/**
|
/**
|
||||||
* The font to use when rendering items, or <code>null</code> if the
|
* The font to use when rendering items, or <code>null</code> if the list's
|
||||||
* list's default font should be used.
|
* default font should be used.
|
||||||
*/
|
*/
|
||||||
private Font font;
|
private Font font;
|
||||||
/**
|
/**
|
||||||
* Whether to display the types of fields and return types of functions
|
* Whether to display the types of fields and return types of functions in the
|
||||||
* in the completion text.
|
* completion text.
|
||||||
*/
|
*/
|
||||||
private boolean showTypes;
|
private boolean showTypes;
|
||||||
/**
|
/**
|
||||||
@@ -101,14 +101,13 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. This is primarily a hook for Substance, or any other
|
* Constructor. This is primarily a hook for Substance, or any other Look and
|
||||||
* Look and Feel whose renderers look drastically different than standard
|
* Feel whose renderers look drastically different than standard
|
||||||
* <code>DefaultListCellRenderer</code>s. Everything except for the text
|
* <code>DefaultListCellRenderer</code>s. Everything except for the text
|
||||||
* rendering will be done by the delegate. In almost all scenarios, you
|
* rendering will be done by the delegate. In almost all scenarios, you will
|
||||||
* will want to use the no-argument constructor instead of this one.
|
* want to use the no-argument constructor instead of this one.
|
||||||
*
|
*
|
||||||
* @param delegate
|
* @param delegate The delegate renderer.
|
||||||
* The delegate renderer.
|
|
||||||
* @see #delegateToSubstanceRenderer()
|
* @see #delegateToSubstanceRenderer()
|
||||||
*/
|
*/
|
||||||
public CompletionCellRenderer(DefaultListCellRenderer delegate) {
|
public CompletionCellRenderer(DefaultListCellRenderer delegate) {
|
||||||
@@ -117,8 +116,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the icon to use if no icon is found for a specific completion.
|
* Creates the icon to use if no icon is found for a specific completion. The
|
||||||
* The default implementation returns a 16x16 empty icon.
|
* default implementation returns a 16x16 empty icon.
|
||||||
*
|
*
|
||||||
* @return The icon.
|
* @return The icon.
|
||||||
* @see #getEmptyIcon()
|
* @see #getEmptyIcon()
|
||||||
@@ -128,8 +127,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a decent "parameter" color based on the current default
|
* Returns a decent "parameter" color based on the current default foreground
|
||||||
* foreground color.
|
* color.
|
||||||
*
|
*
|
||||||
* @return The parameter color to use.
|
* @return The parameter color to use.
|
||||||
*/
|
*/
|
||||||
@@ -138,8 +137,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a decent "type" color based on the current default foreground
|
* Returns a decent "type" color based on the current default foreground color.
|
||||||
* color.
|
|
||||||
*
|
*
|
||||||
* @return The type color to use.
|
* @return The type color to use.
|
||||||
*/
|
*/
|
||||||
@@ -148,12 +146,11 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to delegate rendering to a Substance cell renderer. This
|
* Attempts to delegate rendering to a Substance cell renderer. This should only
|
||||||
* should only be called if Substance is known to be on the classpath.
|
* be called if Substance is known to be on the classpath.
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception If Substance is not on the classpath, or some other error
|
||||||
* If Substance is not on the classpath, or some other
|
* occurs creating the Substance cell renderer.
|
||||||
* error occurs creating the Substance cell renderer.
|
|
||||||
* @see Util#getUseSubstanceRenderers()
|
* @see Util#getUseSubstanceRenderers()
|
||||||
* @see #setDelegateRenderer(DefaultListCellRenderer)
|
* @see #setDelegateRenderer(DefaultListCellRenderer)
|
||||||
*/
|
*/
|
||||||
@@ -187,8 +184,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Returns the font used when rendering completions.
|
* Returns the font used when rendering completions.
|
||||||
*
|
*
|
||||||
* @return The font. If this is <code>null</code>, then the default list
|
* @return The font. If this is <code>null</code>, then the default list font is
|
||||||
* font is used.
|
* used.
|
||||||
* @see #setDisplayFont(Font)
|
* @see #setDisplayFont(Font)
|
||||||
*/
|
*/
|
||||||
public Font getDisplayFont() {
|
public Font getDisplayFont() {
|
||||||
@@ -196,8 +193,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the icon to use if no icon is found for a specific completion.
|
* Returns the icon to use if no icon is found for a specific completion. This
|
||||||
* This icon is lazily created if necessary.
|
* icon is lazily created if necessary.
|
||||||
*
|
*
|
||||||
* @return The icon.
|
* @return The icon.
|
||||||
* @see #createEmptyIcon()
|
* @see #createEmptyIcon()
|
||||||
@@ -212,9 +209,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Returns an icon.
|
* Returns an icon.
|
||||||
*
|
*
|
||||||
* @param resource
|
* @param resource The icon to retrieve. This should either be a file, or a
|
||||||
* The icon to retrieve. This should either be a file,
|
* resource loadable by the current ClassLoader.
|
||||||
* or a resource loadable by the current ClassLoader.
|
|
||||||
* @return The icon.
|
* @return The icon.
|
||||||
*/
|
*/
|
||||||
protected Icon getIcon(String resource) {
|
protected Icon getIcon(String resource) {
|
||||||
@@ -233,19 +229,15 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Returns the renderer.
|
* Returns the renderer.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param value The {@link Completion} being rendered.
|
||||||
* @param value
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The {@link Completion} being rendered.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
super.getListCellRendererComponent(list, value, index, selected, hasFocus);
|
super.getListCellRendererComponent(list, value, index, selected, hasFocus);
|
||||||
if (font != null) {
|
if (font != null) {
|
||||||
setFont(font); // Overrides super's setFont(list.getFont()).
|
setFont(font); // Overrides super's setFont(list.getFont()).
|
||||||
@@ -284,8 +276,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the types of fields and return types of methods are
|
* Returns whether the types of fields and return types of methods are shown in
|
||||||
* shown in the completion text.
|
* the completion text.
|
||||||
*
|
*
|
||||||
* @return Whether to show the types.
|
* @return Whether to show the types.
|
||||||
* @see #setShowTypes(boolean)
|
* @see #setShowTypes(boolean)
|
||||||
@@ -346,18 +338,14 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Prepares this renderer to display a function completion.
|
* Prepares this renderer to display a function completion.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param fc The completion to render.
|
||||||
* @param fc
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The completion to render.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
protected void prepareForFunctionCompletion(JList list, FunctionCompletion fc, int index, boolean selected, boolean hasFocus) {
|
protected void prepareForFunctionCompletion(JList list, FunctionCompletion fc, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
StringBuilder sb = new StringBuilder(PREFIX);
|
StringBuilder sb = new StringBuilder(PREFIX);
|
||||||
sb.append(fc.getName());
|
sb.append(fc.getName());
|
||||||
char paramListStart = fc.getProvider().getParameterListStart();
|
char paramListStart = fc.getProvider().getParameterListStart();
|
||||||
@@ -408,18 +396,14 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Prepares this renderer to display a markup tag completion.
|
* Prepares this renderer to display a markup tag completion.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param mc The completion to render.
|
||||||
* @param mc
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The completion to render.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
protected void prepareForMarkupTagCompletion(JList list, MarkupTagCompletion mc, int index, boolean selected, boolean hasFocus) {
|
protected void prepareForMarkupTagCompletion(JList list, MarkupTagCompletion mc, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
StringBuilder sb = new StringBuilder(PREFIX);
|
StringBuilder sb = new StringBuilder(PREFIX);
|
||||||
sb.append(mc.getName());
|
sb.append(mc.getName());
|
||||||
setText(sb.toString());
|
setText(sb.toString());
|
||||||
@@ -429,16 +413,11 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
* Prepares this renderer to display a completion not specifically handled
|
* Prepares this renderer to display a completion not specifically handled
|
||||||
* elsewhere.
|
* elsewhere.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param c The completion to render.
|
||||||
* @param c
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The completion to render.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
protected void prepareForOtherCompletion(JList list, Completion c, int index, boolean selected, boolean hasFocus) {
|
protected void prepareForOtherCompletion(JList list, Completion c, int index, boolean selected, boolean hasFocus) {
|
||||||
StringBuilder sb = new StringBuilder(PREFIX);
|
StringBuilder sb = new StringBuilder(PREFIX);
|
||||||
@@ -462,18 +441,14 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Prepares this renderer to display a template completion.
|
* Prepares this renderer to display a template completion.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param tc The completion to render.
|
||||||
* @param tc
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The completion to render.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
protected void prepareForTemplateCompletion(JList list, TemplateCompletion tc, int index, boolean selected, boolean hasFocus) {
|
protected void prepareForTemplateCompletion(JList list, TemplateCompletion tc, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
StringBuilder sb = new StringBuilder(PREFIX);
|
StringBuilder sb = new StringBuilder(PREFIX);
|
||||||
sb.append(tc.getInputText());
|
sb.append(tc.getInputText());
|
||||||
String definition = tc.getShortDescription();
|
String definition = tc.getShortDescription();
|
||||||
@@ -493,18 +468,14 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Prepares this renderer to display a variable completion.
|
* Prepares this renderer to display a variable completion.
|
||||||
*
|
*
|
||||||
* @param list
|
* @param list The list of choices being rendered.
|
||||||
* The list of choices being rendered.
|
* @param vc The completion to render.
|
||||||
* @param vc
|
* @param index The index into <code>list</code> being rendered.
|
||||||
* The completion to render.
|
* @param selected Whether the item is selected.
|
||||||
* @param index
|
* @param hasFocus Whether the item has focus.
|
||||||
* The index into <code>list</code> being rendered.
|
|
||||||
* @param selected
|
|
||||||
* Whether the item is selected.
|
|
||||||
* @param hasFocus
|
|
||||||
* Whether the item has focus.
|
|
||||||
*/
|
*/
|
||||||
protected void prepareForVariableCompletion(JList list, VariableCompletion vc, int index, boolean selected, boolean hasFocus) {
|
protected void prepareForVariableCompletion(JList list, VariableCompletion vc, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
StringBuilder sb = new StringBuilder(PREFIX);
|
StringBuilder sb = new StringBuilder(PREFIX);
|
||||||
sb.append(vc.getName());
|
sb.append(vc.getName());
|
||||||
if (getShowTypes() && vc.getType() != null) {
|
if (getShowTypes() && vc.getType() != null) {
|
||||||
@@ -523,8 +494,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Sets the background color to use on alternating lines.
|
* Sets the background color to use on alternating lines.
|
||||||
*
|
*
|
||||||
* @param altBG
|
* @param altBG The new alternate background color. If this is
|
||||||
* The new alternate background color. If this is
|
|
||||||
* <code>null</code>, alternating lines will not use different
|
* <code>null</code>, alternating lines will not use different
|
||||||
* background colors.
|
* background colors.
|
||||||
* @see #getAlternateBackground()
|
* @see #getAlternateBackground()
|
||||||
@@ -534,14 +504,12 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the delegate renderer. Most users will never use this method; it
|
* Sets the delegate renderer. Most users will never use this method; it is
|
||||||
* is primarily a hook for Substance and other Look and Feels whose
|
* primarily a hook for Substance and other Look and Feels whose renderers look
|
||||||
* renderers look drastically different from the standard
|
* drastically different from the standard <code>DefaultListCellRenderer</code>.
|
||||||
* <code>DefaultListCellRenderer</code>.
|
|
||||||
*
|
*
|
||||||
* @param delegate
|
* @param delegate The new delegate renderer. If this is <code>null</code>, the
|
||||||
* The new delegate renderer. If this is <code>null</code>,
|
* default rendering of this component is used.
|
||||||
* the default rendering of this component is used.
|
|
||||||
* @see #getDelegateRenderer()
|
* @see #getDelegateRenderer()
|
||||||
* @see #delegateToSubstanceRenderer()
|
* @see #delegateToSubstanceRenderer()
|
||||||
*/
|
*/
|
||||||
@@ -552,9 +520,8 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Sets the font to use when rendering completion items.
|
* Sets the font to use when rendering completion items.
|
||||||
*
|
*
|
||||||
* @param font
|
* @param font The font to use. If this is <code>null</code>, then the default
|
||||||
* The font to use. If this is <code>null</code>, then
|
* list font is used.
|
||||||
* the default list font is used.
|
|
||||||
* @see #getDisplayFont()
|
* @see #getDisplayFont()
|
||||||
*/
|
*/
|
||||||
public void setDisplayFont(Font font) {
|
public void setDisplayFont(Font font) {
|
||||||
@@ -562,11 +529,10 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the icon to display based off of a completion, falling back to the
|
* Sets the icon to display based off of a completion, falling back to the empty
|
||||||
* empty icon if the completion has no icon.
|
* icon if the completion has no icon.
|
||||||
*
|
*
|
||||||
* @param completion
|
* @param completion The completion to check.
|
||||||
* The completion to check.
|
|
||||||
* @see #setIconWithDefault(Completion, Icon)
|
* @see #setIconWithDefault(Completion, Icon)
|
||||||
*/
|
*/
|
||||||
protected void setIconWithDefault(Completion completion) {
|
protected void setIconWithDefault(Completion completion) {
|
||||||
@@ -574,13 +540,11 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the icon to display based off of a completion, falling back to a
|
* Sets the icon to display based off of a completion, falling back to a default
|
||||||
* default icon if the completion has no icon.
|
* icon if the completion has no icon.
|
||||||
*
|
*
|
||||||
* @param completion
|
* @param completion The completion to check.
|
||||||
* The completion to check.
|
* @param defaultIcon The icon to use if <code>completion</code> does not
|
||||||
* @param defaultIcon
|
|
||||||
* The icon to use if <code>completion</code> does not
|
|
||||||
* specify an icon.
|
* specify an icon.
|
||||||
* @see #setIconWithDefault(Completion)
|
* @see #setIconWithDefault(Completion)
|
||||||
*/
|
*/
|
||||||
@@ -592,8 +556,7 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Sets the color to use for function arguments.
|
* Sets the color to use for function arguments.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use. This is ignored if <code>null</code>.
|
||||||
* The color to use. This is ignored if <code>null</code>.
|
|
||||||
* @see #setTypeColor(Color)
|
* @see #setTypeColor(Color)
|
||||||
*/
|
*/
|
||||||
public void setParamColor(Color color) {
|
public void setParamColor(Color color) {
|
||||||
@@ -603,11 +566,10 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the types of fields and return types of methods are
|
* Sets whether the types of fields and return types of methods are shown in the
|
||||||
* shown in the completion text.
|
* completion text.
|
||||||
*
|
*
|
||||||
* @param show
|
* @param show Whether to show the types.
|
||||||
* Whether to show the types.
|
|
||||||
* @see #getShowTypes()
|
* @see #getShowTypes()
|
||||||
*/
|
*/
|
||||||
public void setShowTypes(boolean show) {
|
public void setShowTypes(boolean show) {
|
||||||
@@ -616,11 +578,10 @@ public class CompletionCellRenderer extends DefaultListCellRenderer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color to use for function/field types. Note that if
|
* Sets the color to use for function/field types. Note that if
|
||||||
* {@link #getShowTypes()} returns <code>false</code>, this property
|
* {@link #getShowTypes()} returns <code>false</code>, this property effectively
|
||||||
* effectively does nothing.
|
* does nothing.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use for types. This is ignored if
|
||||||
* The color to use for types. This is ignored if
|
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @see #setShowTypes(boolean)
|
* @see #setShowTypes(boolean)
|
||||||
* @see #setParamColor(Color)
|
* @see #setParamColor(Color)
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ import java.util.List;
|
|||||||
import javax.swing.AbstractListModel;
|
import javax.swing.AbstractListModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list model implementation that allows the bulk addition of elements.
|
* A list model implementation that allows the bulk addition of elements. This
|
||||||
* This is the only feature missing from <code>DefaultListModel</code> that
|
* is the only feature missing from <code>DefaultListModel</code> that we need.
|
||||||
* we need.
|
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -35,8 +34,8 @@ class CompletionListModel extends AbstractListModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all of the elements from this list. The list will
|
* Removes all of the elements from this list. The list will be empty after this
|
||||||
* be empty after this call returns (unless it throws an exception).
|
* call returns (unless it throws an exception).
|
||||||
*
|
*
|
||||||
* @see #setContents(Collection)
|
* @see #setContents(Collection)
|
||||||
*/
|
*/
|
||||||
@@ -67,8 +66,7 @@ class CompletionListModel extends AbstractListModel {
|
|||||||
/**
|
/**
|
||||||
* Sets the contents of this model. All previous contents are removed.
|
* Sets the contents of this model. All previous contents are removed.
|
||||||
*
|
*
|
||||||
* @param contents
|
* @param contents The new contents of this model.
|
||||||
* The new contents of this model.
|
|
||||||
*/
|
*/
|
||||||
public void setContents(Collection<Completion> contents) {
|
public void setContents(Collection<Completion> contents) {
|
||||||
clear();
|
clear();
|
||||||
|
|||||||
@@ -36,38 +36,34 @@ public interface CompletionProvider {
|
|||||||
public void clearParameterizedCompletionParams();
|
public void clearParameterizedCompletionParams();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text just before the current caret position that could be
|
* Returns the text just before the current caret position that could be the
|
||||||
* the start of something auto-completable.
|
* start of something auto-completable.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component.
|
||||||
* The text component.
|
* @return The text. A return value of <code>null</code> means nothing should be
|
||||||
* @return The text. A return value of <code>null</code> means nothing
|
* auto-completed; a value of an empty string (<code>""</code>) means
|
||||||
* should be auto-completed; a value of an empty string
|
* auto-completion should still be considered (i.e., all possible
|
||||||
* (<code>""</code>) means auto-completion should still be
|
* choices are valid).
|
||||||
* considered (i.e., all possible choices are valid).
|
|
||||||
*/
|
*/
|
||||||
public String getAlreadyEnteredText(JTextComponent comp);
|
public String getAlreadyEnteredText(JTextComponent comp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the possible completions for the text component at the current
|
* Gets the possible completions for the text component at the current caret
|
||||||
* caret position.
|
* position.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component.
|
||||||
* The text component.
|
* @return The list of {@link Completion}s. If no completions are available,
|
||||||
* @return The list of {@link Completion}s. If no completions are
|
* this method should return an empty list.
|
||||||
* available, this method should return an empty list.
|
|
||||||
*/
|
*/
|
||||||
public List<Completion> getCompletions(JTextComponent comp);
|
public List<Completion> getCompletions(JTextComponent comp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the completions that have been entered at the specified visual
|
* Returns the completions that have been entered at the specified visual
|
||||||
* location. This can be used for tool tips when the user hovers the
|
* location. This can be used for tool tips when the user hovers the mouse over
|
||||||
* mouse over completed text.
|
* completed text.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component.
|
||||||
* The text component.
|
* @param p The position, usually from a <tt>MouseEvent</tt>.
|
||||||
* @param p
|
|
||||||
* The position, usually from a <tt>MouseEvent</tt>.
|
|
||||||
* @return The completions, or an empty list if there are none.
|
* @return The completions, or an empty list if there are none.
|
||||||
*/
|
*/
|
||||||
public List<Completion> getCompletionsAt(JTextComponent comp, Point p);
|
public List<Completion> getCompletionsAt(JTextComponent comp, Point p);
|
||||||
@@ -75,8 +71,8 @@ public interface CompletionProvider {
|
|||||||
/**
|
/**
|
||||||
* Returns the cell renderer for completions returned from this provider.
|
* Returns the cell renderer for completions returned from this provider.
|
||||||
*
|
*
|
||||||
* @return The cell renderer, or <code>null</code> if the default should
|
* @return The cell renderer, or <code>null</code> if the default should be
|
||||||
* be used.
|
* used.
|
||||||
* @see #setListCellRenderer(ListCellRenderer)
|
* @see #setListCellRenderer(ListCellRenderer)
|
||||||
*/
|
*/
|
||||||
public ListCellRenderer getListCellRenderer();
|
public ListCellRenderer getListCellRenderer();
|
||||||
@@ -87,29 +83,27 @@ public interface CompletionProvider {
|
|||||||
* completion, such as a function or method. For any parameter to the
|
* completion, such as a function or method. For any parameter to the
|
||||||
* function/method, this object can return possible completions.
|
* function/method, this object can return possible completions.
|
||||||
*
|
*
|
||||||
* @return The parameter choices provider, or <code>null</code> if
|
* @return The parameter choices provider, or <code>null</code> if none is
|
||||||
* none is installed.
|
* installed.
|
||||||
*/
|
*/
|
||||||
public ParameterChoicesProvider getParameterChoicesProvider();
|
public ParameterChoicesProvider getParameterChoicesProvider();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of parameterized completions that have been entered
|
* Returns a list of parameterized completions that have been entered at the
|
||||||
* at the current caret position of a text component (and thus can have
|
* current caret position of a text component (and thus can have their
|
||||||
* their completion choices displayed).
|
* completion choices displayed).
|
||||||
*
|
*
|
||||||
* @param tc
|
* @param tc The text component.
|
||||||
* The text component.
|
* @return The list of {@link ParameterizedCompletion}s. If no completions are
|
||||||
* @return The list of {@link ParameterizedCompletion}s. If no completions
|
* available, this may be <code>null</code>.
|
||||||
* are available, this may be <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
public List<ParameterizedCompletion> getParameterizedCompletions(JTextComponent tc);
|
public List<ParameterizedCompletion> getParameterizedCompletions(JTextComponent tc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text that marks the end of a list of parameters to a
|
* Returns the text that marks the end of a list of parameters to a function or
|
||||||
* function or method.
|
* method.
|
||||||
*
|
*
|
||||||
* @return The text for a parameter list end, for example,
|
* @return The text for a parameter list end, for example, '<code>)</code>'.
|
||||||
* '<code>)</code>'.
|
|
||||||
* @see #getParameterListStart()
|
* @see #getParameterListStart()
|
||||||
* @see #getParameterListSeparator()
|
* @see #getParameterListSeparator()
|
||||||
* @see #setParameterizedCompletionParams(char, String, char)
|
* @see #setParameterizedCompletionParams(char, String, char)
|
||||||
@@ -119,8 +113,7 @@ public interface CompletionProvider {
|
|||||||
/**
|
/**
|
||||||
* Returns the text that separates parameters to a function or method.
|
* Returns the text that separates parameters to a function or method.
|
||||||
*
|
*
|
||||||
* @return The text that separates parameters, for example,
|
* @return The text that separates parameters, for example, "<code>, </code>".
|
||||||
* "<code>, </code>".
|
|
||||||
* @see #getParameterListStart()
|
* @see #getParameterListStart()
|
||||||
* @see #getParameterListEnd()
|
* @see #getParameterListEnd()
|
||||||
* @see #setParameterizedCompletionParams(char, String, char)
|
* @see #setParameterizedCompletionParams(char, String, char)
|
||||||
@@ -128,11 +121,10 @@ public interface CompletionProvider {
|
|||||||
public String getParameterListSeparator();
|
public String getParameterListSeparator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text that marks the start of a list of parameters to a
|
* Returns the text that marks the start of a list of parameters to a function
|
||||||
* function or method.
|
* or method.
|
||||||
*
|
*
|
||||||
* @return The text for a parameter list start, for example,
|
* @return The text for a parameter list start, for example, "<code>(</code>".
|
||||||
* "<code>(</code>".
|
|
||||||
* @see #getParameterListEnd()
|
* @see #getParameterListEnd()
|
||||||
* @see #getParameterListSeparator()
|
* @see #getParameterListSeparator()
|
||||||
* @see #setParameterizedCompletionParams(char, String, char)
|
* @see #setParameterizedCompletionParams(char, String, char)
|
||||||
@@ -149,15 +141,14 @@ public interface CompletionProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called if auto-activation is enabled in the parent
|
* This method is called if auto-activation is enabled in the parent
|
||||||
* {@link AutoCompletion} after the user types a single character. This
|
* {@link AutoCompletion} after the user types a single character. This provider
|
||||||
* provider should check the text at the current caret position of the
|
* should check the text at the current caret position of the text component,
|
||||||
* text component, and decide whether auto-activation would be appropriate
|
* and decide whether auto-activation would be appropriate here. For example, a
|
||||||
* here. For example, a <code>CompletionProvider</code> for Java might
|
* <code>CompletionProvider</code> for Java might want to return
|
||||||
* want to return <code>true</code> for this method only if the last
|
* <code>true</code> for this method only if the last character typed was a
|
||||||
* character typed was a '<code>.</code>'.
|
* '<code>.</code>'.
|
||||||
*
|
*
|
||||||
* @param tc
|
* @param tc The text component.
|
||||||
* The text component.
|
|
||||||
* @return Whether auto-activation would be appropriate.
|
* @return Whether auto-activation would be appropriate.
|
||||||
*/
|
*/
|
||||||
public boolean isAutoActivateOkay(JTextComponent tc);
|
public boolean isAutoActivateOkay(JTextComponent tc);
|
||||||
@@ -165,30 +156,26 @@ public interface CompletionProvider {
|
|||||||
/**
|
/**
|
||||||
* Sets the renderer to use when displaying completion choices.
|
* Sets the renderer to use when displaying completion choices.
|
||||||
*
|
*
|
||||||
* @param r
|
* @param r The renderer to use.
|
||||||
* The renderer to use.
|
|
||||||
* @see #getListCellRenderer()
|
* @see #getListCellRenderer()
|
||||||
*/
|
*/
|
||||||
public void setListCellRenderer(ListCellRenderer r);
|
public void setListCellRenderer(ListCellRenderer r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the values used to identify and insert "parameterized completions"
|
* Sets the values used to identify and insert "parameterized completions" (e.g.
|
||||||
* (e.g. functions or methods). If this method isn't called, functions
|
* functions or methods). If this method isn't called, functions and methods
|
||||||
* and methods will not have their parameters auto-completed.
|
* will not have their parameters auto-completed.
|
||||||
*
|
*
|
||||||
* @param listStart
|
* @param listStart The character that marks the beginning of a list of
|
||||||
* The character that marks the beginning of a list of
|
|
||||||
* parameters, such as '<tt>(</tt>' in C or Java.
|
* parameters, such as '<tt>(</tt>' in C or Java.
|
||||||
* @param separator
|
* @param separator Text that should separate parameters in a parameter list
|
||||||
* Text that should separate parameters in a parameter
|
* when one is inserted. For example, "<tt>, </tt>".
|
||||||
* list when one is inserted. For example, "<tt>, </tt>".
|
* @param listEnd The character that marks the end of a list of parameters,
|
||||||
* @param listEnd
|
|
||||||
* The character that marks the end of a list of parameters,
|
|
||||||
* such as '<tt>)</tt>' in C or Java.
|
* such as '<tt>)</tt>' in C or Java.
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException If either <tt>listStart</tt> or
|
||||||
* If either <tt>listStart</tt> or
|
* <tt>listEnd</tt> is not printable ASCII, or
|
||||||
* <tt>listEnd</tt> is not printable ASCII, or if
|
* if <tt>separator</tt> is <code>null</code>
|
||||||
* <tt>separator</tt> is <code>null</code> or an empty string.
|
* or an empty string.
|
||||||
* @see #clearParameterizedCompletionParams()
|
* @see #clearParameterizedCompletionParams()
|
||||||
*/
|
*/
|
||||||
public void setParameterizedCompletionParams(char listStart, String separator, char listEnd);
|
public void setParameterizedCompletionParams(char listStart, String separator, char listEnd);
|
||||||
@@ -196,9 +183,8 @@ public interface CompletionProvider {
|
|||||||
/**
|
/**
|
||||||
* Sets the parent completion provider.
|
* Sets the parent completion provider.
|
||||||
*
|
*
|
||||||
* @param parent
|
* @param parent The parent provider. <code>null</code> means there will be no
|
||||||
* The parent provider. <code>null</code> means there will
|
* parent provider.
|
||||||
* be no parent provider.
|
|
||||||
* @see #getParent()
|
* @see #getParent()
|
||||||
*/
|
*/
|
||||||
public void setParent(CompletionProvider parent);
|
public void setParent(CompletionProvider parent);
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ public abstract class CompletionProviderBase implements CompletionProvider {
|
|||||||
} catch (BadLocationException ble) { // Never happens
|
} catch (BadLocationException ble) { // Never happens
|
||||||
ble.printStackTrace();
|
ble.printStackTrace();
|
||||||
}
|
}
|
||||||
return (autoActivateAfterLetters && Character.isLetter(ch)) || (autoActivateChars != null && autoActivateChars.indexOf(ch) > -1);
|
return (autoActivateAfterLetters && Character.isLetter(ch))
|
||||||
|
|| (autoActivateChars != null && autoActivateChars.indexOf(ch) > -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import org.xml.sax.SAXParseException;
|
|||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser for an XML file describing a procedural language such as C. XML
|
* Parser for an XML file describing a procedural language such as C. XML files
|
||||||
* files will be validated against the <code>CompletionXml.dtd</code> DTD
|
* will be validated against the <code>CompletionXml.dtd</code> DTD found in
|
||||||
* found in this package.
|
* this package.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -68,18 +68,16 @@ public class CompletionXMLParser extends DefaultHandler {
|
|||||||
*/
|
*/
|
||||||
private String funcCompletionType;
|
private String funcCompletionType;
|
||||||
/**
|
/**
|
||||||
* The class loader to use to load custom completion classes, such as
|
* The class loader to use to load custom completion classes, such as the one
|
||||||
* the one defined by {@link #funcCompletionType}. If this is
|
* defined by {@link #funcCompletionType}. If this is <code>null</code>, then a
|
||||||
* <code>null</code>, then a default class loader is used. This field
|
* default class loader is used. This field will usually be <code>null</code>.
|
||||||
* will usually be <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
private static ClassLoader DEFAULT_COMPLETION_CLASS_LOADER;
|
private static ClassLoader DEFAULT_COMPLETION_CLASS_LOADER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to get completions for.
|
||||||
* The provider to get completions for.
|
|
||||||
* @see #reset(CompletionProvider)
|
* @see #reset(CompletionProvider)
|
||||||
*/
|
*/
|
||||||
public CompletionXMLParser(CompletionProvider provider) {
|
public CompletionXMLParser(CompletionProvider provider) {
|
||||||
@@ -89,15 +87,12 @@ public class CompletionXMLParser extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to get completions for.
|
||||||
* The provider to get completions for.
|
* @param cl The class loader to use, if necessary, when loading classes
|
||||||
* @param cl
|
|
||||||
* The class loader to use, if necessary, when loading classes
|
|
||||||
* from the XML (custom {@link FunctionCompletion}s, for
|
* from the XML (custom {@link FunctionCompletion}s, for
|
||||||
* example).
|
* example). This may be <code>null</code> if the default is to
|
||||||
* This may be <code>null</code> if the default is to be used, or
|
* be used, or if the XML does not define specific classes for
|
||||||
* if the XML does not define specific classes for completion
|
* completion types.
|
||||||
* types.
|
|
||||||
* @see #reset(CompletionProvider)
|
* @see #reset(CompletionProvider)
|
||||||
*/
|
*/
|
||||||
public CompletionXMLParser(CompletionProvider provider, ClassLoader cl) {
|
public CompletionXMLParser(CompletionProvider provider, ClassLoader cl) {
|
||||||
@@ -295,8 +290,7 @@ public class CompletionXMLParser extends DefaultHandler {
|
|||||||
/**
|
/**
|
||||||
* Resets this parser to grab more completions.
|
* Resets this parser to grab more completions.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The new provider to get completions for.
|
||||||
* The new provider to get completions for.
|
|
||||||
*/
|
*/
|
||||||
public void reset(CompletionProvider provider) {
|
public void reset(CompletionProvider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
@@ -312,16 +306,14 @@ public class CompletionXMLParser extends DefaultHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the class loader to use when loading custom classes to use for
|
* Sets the class loader to use when loading custom classes to use for various
|
||||||
* various {@link Completion} types, such as {@link FunctionCompletion}s,
|
* {@link Completion} types, such as {@link FunctionCompletion}s, from XML.
|
||||||
* from XML.
|
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Users should very rarely have a need to use this method.
|
* Users should very rarely have a need to use this method.
|
||||||
*
|
*
|
||||||
* @param cl
|
* @param cl The class loader to use. If this is <code>null</code>, then a
|
||||||
* The class loader to use. If this is <code>null</code>, then
|
* default is used.
|
||||||
* a default is used.
|
|
||||||
*/
|
*/
|
||||||
public static void setDefaultCompletionClassLoader(ClassLoader cl) {
|
public static void setDefaultCompletionClassLoader(ClassLoader cl) {
|
||||||
DEFAULT_COMPLETION_CLASS_LOADER = cl;
|
DEFAULT_COMPLETION_CLASS_LOADER = cl;
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ import org.xml.sax.SAXException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic completion provider implementation. This provider has no
|
* A basic completion provider implementation. This provider has no
|
||||||
* understanding of language semantics. It simply checks the text entered up
|
* understanding of language semantics. It simply checks the text entered up to
|
||||||
* to the caret position for a match against known completions. This is all
|
* the caret position for a match against known completions. This is all that is
|
||||||
* that is needed in the majority of cases.
|
* needed in the majority of cases.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -43,11 +43,11 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
*/
|
*/
|
||||||
private String lastCompletionsAtText;
|
private String lastCompletionsAtText;
|
||||||
/**
|
/**
|
||||||
* Used to speed up {@link #getCompletionsAt(JTextComponent, Point)},
|
* Used to speed up {@link #getCompletionsAt(JTextComponent, Point)}, since this
|
||||||
* since this may be called multiple times in succession (this is usually
|
* may be called multiple times in succession (this is usually called by
|
||||||
* called by <tt>JTextComponent.getToolTipText()</tt>, and if the user
|
* <tt>JTextComponent.getToolTipText()</tt>, and if the user wiggles the mouse
|
||||||
* wiggles the mouse while a tool tip is displayed, this method gets
|
* while a tool tip is displayed, this method gets repeatedly called. It can be
|
||||||
* repeatedly called. It can be costly so we try to speed it up a tad).
|
* costly so we try to speed it up a tad).
|
||||||
*/
|
*/
|
||||||
private List<Completion> lastParameterizedCompletionsAt;
|
private List<Completion> lastParameterizedCompletionsAt;
|
||||||
|
|
||||||
@@ -61,11 +61,10 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a completion provider that provides completion for a simple
|
* Creates a completion provider that provides completion for a simple list of
|
||||||
* list of words.
|
* words.
|
||||||
*
|
*
|
||||||
* @param words
|
* @param words The words to offer as completion suggestions. If this is
|
||||||
* The words to offer as completion suggestions. If this is
|
|
||||||
* <code>null</code>, no completions will be known.
|
* <code>null</code>, no completions will be known.
|
||||||
* @see BasicCompletion
|
* @see BasicCompletion
|
||||||
*/
|
*/
|
||||||
@@ -75,12 +74,12 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text just before the current caret position that could be
|
* Returns the text just before the current caret position that could be the
|
||||||
* the start of something auto-completable.
|
* start of something auto-completable.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This method returns all characters before the caret that are matched
|
* This method returns all characters before the caret that are matched by
|
||||||
* by {@link #isValidChar(char)}.
|
* {@link #isValidChar(char)}.
|
||||||
*
|
*
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@@ -221,13 +220,12 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the specified character is valid in an auto-completion.
|
* Returns whether the specified character is valid in an auto-completion. The
|
||||||
* The default implementation is equivalent to
|
* default implementation is equivalent to
|
||||||
* "<code>Character.isLetterOrDigit(ch) || ch=='_'</code>". Subclasses
|
* "<code>Character.isLetterOrDigit(ch) || ch=='_'</code>". Subclasses can
|
||||||
* can override this method to change what characters are matched.
|
* override this method to change what characters are matched.
|
||||||
*
|
*
|
||||||
* @param ch
|
* @param ch The character.
|
||||||
* The character.
|
|
||||||
* @return Whether the character is valid.
|
* @return Whether the character is valid.
|
||||||
*/
|
*/
|
||||||
protected boolean isValidChar(char ch) {
|
protected boolean isValidChar(char ch) {
|
||||||
@@ -238,10 +236,8 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
* Loads completions from an XML file. The XML should validate against
|
* Loads completions from an XML file. The XML should validate against
|
||||||
* <code>CompletionXml.dtd</code>.
|
* <code>CompletionXml.dtd</code>.
|
||||||
*
|
*
|
||||||
* @param file
|
* @param file An XML file to load from.
|
||||||
* An XML file to load from.
|
* @throws IOException If an IO error occurs.
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
public void loadFromXML(File file) throws IOException {
|
public void loadFromXML(File file) throws IOException {
|
||||||
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
|
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
|
||||||
@@ -253,32 +249,26 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads completions from an XML input stream. The XML should validate
|
* Loads completions from an XML input stream. The XML should validate against
|
||||||
* against <code>CompletionXml.dtd</code>.
|
* <code>CompletionXml.dtd</code>.
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in The input stream to read from.
|
||||||
* The input stream to read from.
|
* @throws IOException If an IO error occurs.
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
public void loadFromXML(InputStream in) throws IOException {
|
public void loadFromXML(InputStream in) throws IOException {
|
||||||
loadFromXML(in, null);
|
loadFromXML(in, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads completions from an XML input stream. The XML should validate
|
* Loads completions from an XML input stream. The XML should validate against
|
||||||
* against <code>CompletionXml.dtd</code>.
|
* <code>CompletionXml.dtd</code>.
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in The input stream to read from.
|
||||||
* The input stream to read from.
|
* @param cl The class loader to use when loading any extra classes defined in
|
||||||
* @param cl
|
* the XML, such as custom {@link FunctionCompletion}s. This may be
|
||||||
* The class loader to use when loading any extra classes defined
|
* <code>null</code> if the default is to be used, or if no custom
|
||||||
* in the XML, such as custom {@link FunctionCompletion}s. This
|
* completions are defined in the XML.
|
||||||
* may be <code>null</code> if the default is to be used, or if
|
* @throws IOException If an IO error occurs.
|
||||||
* no
|
|
||||||
* custom completions are defined in the XML.
|
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
public void loadFromXML(InputStream in, ClassLoader cl) throws IOException {
|
public void loadFromXML(InputStream in, ClassLoader cl) throws IOException {
|
||||||
// long start = System.currentTimeMillis();
|
// long start = System.currentTimeMillis();
|
||||||
@@ -314,10 +304,8 @@ public class DefaultCompletionProvider extends AbstractCompletionProvider {
|
|||||||
* Loads completions from an XML file. The XML should validate against
|
* Loads completions from an XML file. The XML should validate against
|
||||||
* <code>CompletionXml.dtd</code>.
|
* <code>CompletionXml.dtd</code>.
|
||||||
*
|
*
|
||||||
* @param resource
|
* @param resource A resource the current ClassLoader can get to.
|
||||||
* A resource the current ClassLoader can get to.
|
* @throws IOException If an IO error occurs.
|
||||||
* @throws IOException
|
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
public void loadFromXML(String resource) throws IOException {
|
public void loadFromXML(String resource) throws IOException {
|
||||||
ClassLoader cl = getClass().getClassLoader();
|
ClassLoader cl = getClass().getClassLoader();
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import javax.swing.JList;
|
|||||||
import javax.swing.ListCellRenderer;
|
import javax.swing.ListCellRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List cell renderer that delegates to a {@link CompletionProvider}'s
|
* List cell renderer that delegates to a {@link CompletionProvider}'s renderer,
|
||||||
* renderer, if it has one. If it doesn't, it calls into a fallback renderer.
|
* if it has one. If it doesn't, it calls into a fallback renderer. If a
|
||||||
* If a fallback renderer isn't specified, it simply renders
|
* fallback renderer isn't specified, it simply renders
|
||||||
* <code>(({@link Completion})value).toString()</code>.
|
* <code>(({@link Completion})value).toString()</code>.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
@@ -26,8 +26,8 @@ import javax.swing.ListCellRenderer;
|
|||||||
class DelegatingCellRenderer extends DefaultListCellRenderer {
|
class DelegatingCellRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The renderer to fall back on if one isn't specified by a provider.
|
* The renderer to fall back on if one isn't specified by a provider. This is
|
||||||
* This is usually <tt>this</tt>.
|
* usually <tt>this</tt>.
|
||||||
*/
|
*/
|
||||||
private ListCellRenderer fallback;
|
private ListCellRenderer fallback;
|
||||||
|
|
||||||
@@ -45,7 +45,8 @@ class DelegatingCellRenderer extends DefaultListCellRenderer {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected, boolean hasFocus) {
|
public Component getListCellRendererComponent(JList list, Object value, int index, boolean selected,
|
||||||
|
boolean hasFocus) {
|
||||||
Completion c = (Completion) value;
|
Completion c = (Completion) value;
|
||||||
CompletionProvider p = c.getProvider();
|
CompletionProvider p = c.getProvider();
|
||||||
ListCellRenderer r = p.getListCellRenderer();
|
ListCellRenderer r = p.getListCellRenderer();
|
||||||
@@ -61,9 +62,8 @@ class DelegatingCellRenderer extends DefaultListCellRenderer {
|
|||||||
/**
|
/**
|
||||||
* Sets the fallback cell renderer.
|
* Sets the fallback cell renderer.
|
||||||
*
|
*
|
||||||
* @param fallback
|
* @param fallback The fallback cell renderer. If this is <code>null</code>,
|
||||||
* The fallback cell renderer. If this is
|
* <tt>this</tt> will be used.
|
||||||
* <code>null</code>, <tt>this</tt> will be used.
|
|
||||||
* @see #getFallbackCellRenderer()
|
* @see #getFallbackCellRenderer()
|
||||||
*/
|
*/
|
||||||
public void setFallbackCellRenderer(ListCellRenderer fallback) {
|
public void setFallbackCellRenderer(ListCellRenderer fallback) {
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ package org.fife.ui.autocomplete;
|
|||||||
public interface DescWindowCallback {
|
public interface DescWindowCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback allowing a new code completion's description to be displayed
|
* Callback allowing a new code completion's description to be displayed in the
|
||||||
* in the description window.
|
* description window.
|
||||||
*
|
*
|
||||||
* @param completion
|
* @param completion The new completion.
|
||||||
* The new completion.
|
* @param anchor The anchor to scroll to, or <code>null</code> if none.
|
||||||
* @param anchor
|
|
||||||
* The anchor to scroll to, or <code>null</code> if none.
|
|
||||||
*/
|
*/
|
||||||
public void showSummaryFor(Completion completion, String anchor);
|
public void showSummaryFor(Completion completion, String anchor);
|
||||||
}
|
}
|
||||||
@@ -39,5 +39,6 @@ public class EmptyIcon implements Icon, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintIcon(Component c, Graphics g, int x, int y) {}
|
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,12 +10,12 @@ package org.fife.ui.autocomplete;
|
|||||||
import javax.swing.event.HyperlinkEvent;
|
import javax.swing.event.HyperlinkEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for when an external URL is clicked in the description window.
|
* A callback for when an external URL is clicked in the description window. If
|
||||||
* If no handler is installed, and if running in Java 6, the system default
|
* no handler is installed, and if running in Java 6, the system default web
|
||||||
* web browser is used to open the URL. If not running Java 6, nothing will
|
* browser is used to open the URL. If not running Java 6, nothing will happen.
|
||||||
* happen. If you want browser support for pre-Java 6 JRE's, you will need
|
* If you want browser support for pre-Java 6 JRE's, you will need to register
|
||||||
* to register one of these callbacks on your {@link AutoCompletion}, and
|
* one of these callbacks on your {@link AutoCompletion}, and open the URL in a
|
||||||
* open the URL in a web browser yourself.
|
* web browser yourself.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Alternatively, folks implementing robust code completion support for a
|
* Alternatively, folks implementing robust code completion support for a
|
||||||
@@ -31,13 +31,9 @@ public interface ExternalURLHandler {
|
|||||||
/**
|
/**
|
||||||
* Called when an external URL is clicked in the description window.
|
* Called when an external URL is clicked in the description window.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event containing the hyperlink clicked.
|
||||||
* The event containing the hyperlink clicked.
|
* @param c The completion currently being displayed.
|
||||||
* @param c
|
* @param callback Allows you to display new content in the description window.
|
||||||
* The completion currently being displayed.
|
|
||||||
* @param callback
|
|
||||||
* Allows you to display new content in the description
|
|
||||||
* window.
|
|
||||||
*/
|
*/
|
||||||
public void urlClicked(HyperlinkEvent e, Completion c, DescWindowCallback callback);
|
public void urlClicked(HyperlinkEvent e, Completion c, DescWindowCallback callback);
|
||||||
}
|
}
|
||||||
@@ -20,14 +20,14 @@ import javax.swing.plaf.basic.BasicListUI;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom list UI, used by the completion choices list. If the number of
|
* A custom list UI, used by the completion choices list. If the number of
|
||||||
* completion choices is "large," it does a fast estimate of the preferred
|
* completion choices is "large," it does a fast estimate of the preferred width
|
||||||
* width and height of list items. This allows HTML renderers to be used (such
|
* and height of list items. This allows HTML renderers to be used (such as
|
||||||
* as {@link CompletionCellRenderer}), with thousands of completion choices,
|
* {@link CompletionCellRenderer}), with thousands of completion choices, with
|
||||||
* with no performance penalty. With standard BasicListUI subclasses, this can
|
* no performance penalty. With standard BasicListUI subclasses, this can cause
|
||||||
* cause very poor performance <b>each time</b> the list is displayed, which
|
* very poor performance <b>each time</b> the list is displayed, which is bad
|
||||||
* is bad for lists that are repeatedly hidden and re-displayed, such as
|
* for lists that are repeatedly hidden and re-displayed, such as completion
|
||||||
* completion choices. This is all because the calculation to get the
|
* choices. This is all because the calculation to get the preferred size of
|
||||||
* preferred size of each list item, when it is displayed with HTML, is slow.
|
* each list item, when it is displayed with HTML, is slow.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -35,19 +35,19 @@ import javax.swing.plaf.basic.BasicListUI;
|
|||||||
class FastListUI extends BasicListUI {
|
class FastListUI extends BasicListUI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the selection background was overridden (usually because of
|
* Whether the selection background was overridden (usually because of Nimbus)
|
||||||
* Nimbus) so we know to manually uninstall the color we installed.
|
* so we know to manually uninstall the color we installed.
|
||||||
*/
|
*/
|
||||||
private boolean overriddenBackground;
|
private boolean overriddenBackground;
|
||||||
/**
|
/**
|
||||||
* Whether the selection foreground was overridden (usually because of
|
* Whether the selection foreground was overridden (usually because of Nimbus)
|
||||||
* Nimbus) so we know to manually uninstall the color we installed.
|
* so we know to manually uninstall the color we installed.
|
||||||
*/
|
*/
|
||||||
private boolean overriddenForeground;
|
private boolean overriddenForeground;
|
||||||
/**
|
/**
|
||||||
* If there are more than this many completions in a single list, this
|
* If there are more than this many completions in a single list, this UI will
|
||||||
* UI will estimate the cell width and height needed for each item instead
|
* estimate the cell width and height needed for each item instead of computing
|
||||||
* of computing it, for performance reasons.
|
* it, for performance reasons.
|
||||||
*/
|
*/
|
||||||
private static final int ESTIMATION_THRESHOLD = 200;
|
private static final int ESTIMATION_THRESHOLD = 200;
|
||||||
|
|
||||||
@@ -86,10 +86,9 @@ class FastListUI extends BasicListUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden to ensure we have selection background/foreground colors
|
* Overridden to ensure we have selection background/foreground colors defined,
|
||||||
* defined, even if we're in some weirdo LAF such as Nimbus which doesn't
|
* even if we're in some weirdo LAF such as Nimbus which doesn't define them.
|
||||||
* define them. Since FastListUI extends BasicListUI, we need these values
|
* Since FastListUI extends BasicListUI, we need these values to be defined.
|
||||||
* to be defined.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void installDefaults() {
|
protected void installDefaults() {
|
||||||
@@ -119,10 +118,9 @@ class FastListUI extends BasicListUI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recalculates the cell width and height of each cell in the list. This
|
* Recalculates the cell width and height of each cell in the list. This method
|
||||||
* method is overridden to do a fast estimation if the completion list is
|
* is overridden to do a fast estimation if the completion list is too long, to
|
||||||
* too long, to improve performance for lists with huge amounts of
|
* improve performance for lists with huge amounts of completions.
|
||||||
* completions.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateLayoutState() {
|
protected void updateLayoutState() {
|
||||||
|
|||||||
@@ -37,12 +37,9 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent provider.
|
||||||
* The parent provider.
|
* @param name The name of this function.
|
||||||
* @param name
|
* @param returnType The return type of this function.
|
||||||
* The name of this function.
|
|
||||||
* @param returnType
|
|
||||||
* The return type of this function.
|
|
||||||
*/
|
*/
|
||||||
public FunctionCompletion(CompletionProvider provider, String name, String returnType) {
|
public FunctionCompletion(CompletionProvider provider, String name, String returnType) {
|
||||||
super(provider, name, returnType);
|
super(provider, name, returnType);
|
||||||
@@ -58,8 +55,7 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Adds HTML describing the parameters to this function to a buffer.
|
* Adds HTML describing the parameters to this function to a buffer.
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
*/
|
*/
|
||||||
protected void addParameters(StringBuilder sb) {
|
protected void addParameters(StringBuilder sb) {
|
||||||
// TODO: Localize me
|
// TODO: Localize me
|
||||||
@@ -90,8 +86,7 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Overridden to compare methods by their comparison strings.
|
* Overridden to compare methods by their comparison strings.
|
||||||
*
|
*
|
||||||
* @param c2
|
* @param c2 A <code>Completion</code> to compare to.
|
||||||
* A <code>Completion</code> to compare to.
|
|
||||||
* @return The sort order.
|
* @return The sort order.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -114,11 +109,9 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
*/
|
*/
|
||||||
private String getCompareString() {
|
private String getCompareString() {
|
||||||
/*
|
/*
|
||||||
* This string compares the following parts of methods in this order,
|
* This string compares the following parts of methods in this order, to
|
||||||
* to optimize sort order in completion lists.
|
* optimize sort order in completion lists. 1. First, by name 2. Next, by number
|
||||||
* 1. First, by name
|
* of parameters. 3. Finally, by parameter type.
|
||||||
* 2. Next, by number of parameters.
|
|
||||||
* 3. Finally, by parameter type.
|
|
||||||
*/
|
*/
|
||||||
if (compareString == null) {
|
if (compareString == null) {
|
||||||
StringBuilder sb = new StringBuilder(getName());
|
StringBuilder sb = new StringBuilder(getName());
|
||||||
@@ -141,8 +134,8 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "definition string" for this function completion. For
|
* Returns the "definition string" for this function completion. For example,
|
||||||
* example, for the C "<code>printf</code>" function, this would return
|
* for the C "<code>printf</code>" function, this would return
|
||||||
* "<code>int printf(const char *, ...)</code>".
|
* "<code>int printf(const char *, ...)</code>".
|
||||||
*
|
*
|
||||||
* @return The definition string.
|
* @return The definition string.
|
||||||
@@ -269,8 +262,7 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Returns the text to insert for a parameter.
|
* Returns the text to insert for a parameter.
|
||||||
*
|
*
|
||||||
* @param param
|
* @param param The parameter.
|
||||||
* The parameter.
|
|
||||||
* @return The text.
|
* @return The text.
|
||||||
*/
|
*/
|
||||||
private String getParamText(ParameterizedCompletion.Parameter param) {
|
private String getParamText(ParameterizedCompletion.Parameter param) {
|
||||||
@@ -324,8 +316,7 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Sets the parameters to this function.
|
* Sets the parameters to this function.
|
||||||
*
|
*
|
||||||
* @param params
|
* @param params The parameters. This should be a list of
|
||||||
* The parameters. This should be a list of
|
|
||||||
* {@link ParameterizedCompletion.Parameter}s.
|
* {@link ParameterizedCompletion.Parameter}s.
|
||||||
* @see #getParam(int)
|
* @see #getParam(int)
|
||||||
* @see #getParamCount()
|
* @see #getParamCount()
|
||||||
@@ -340,8 +331,7 @@ public class FunctionCompletion extends VariableCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Sets the description of the return value of this function.
|
* Sets the description of the return value of this function.
|
||||||
*
|
*
|
||||||
* @param desc
|
* @param desc The description.
|
||||||
* The description.
|
|
||||||
* @see #getReturnValueDescription()
|
* @see #getReturnValueDescription()
|
||||||
*/
|
*/
|
||||||
public void setReturnValueDescription(String desc) {
|
public void setReturnValueDescription(String desc) {
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ import org.fife.ui.rtextarea.ToolTipSupplier;
|
|||||||
* <li>A documentation comment</li>
|
* <li>A documentation comment</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* This allows for different completion choices in comments than in code,
|
* This allows for different completion choices in comments than in code, for
|
||||||
* for example.
|
* example.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This provider also implements the
|
* This provider also implements the
|
||||||
* <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> interface, which allows it
|
* <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> interface, which allows it to
|
||||||
* to display tooltips for completion choices. Thus the standard
|
* display tooltips for completion choices. Thus the standard
|
||||||
* {@link VariableCompletion} and {@link FunctionCompletion} completions should
|
* {@link VariableCompletion} and {@link FunctionCompletion} completions should
|
||||||
* be able to display tooltips with the variable declaration or function
|
* be able to display tooltips with the variable declaration or function
|
||||||
* definition (provided the <tt>RSyntaxTextArea</tt> was registered with the
|
* definition (provided the <tt>RSyntaxTextArea</tt> was registered with the
|
||||||
@@ -51,8 +51,7 @@ import org.fife.ui.rtextarea.ToolTipSupplier;
|
|||||||
public class LanguageAwareCompletionProvider extends CompletionProviderBase implements ToolTipSupplier {
|
public class LanguageAwareCompletionProvider extends CompletionProviderBase implements ToolTipSupplier {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The provider to use when no provider is assigned to a particular token
|
* The provider to use when no provider is assigned to a particular token type.
|
||||||
* type.
|
|
||||||
*/
|
*/
|
||||||
private CompletionProvider defaultProvider;
|
private CompletionProvider defaultProvider;
|
||||||
/**
|
/**
|
||||||
@@ -69,32 +68,31 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
private CompletionProvider docCommentCompletionProvider;
|
private CompletionProvider docCommentCompletionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor subclasses can use when they don't have their default
|
* Constructor subclasses can use when they don't have their default provider
|
||||||
* provider created at construction time. They should call
|
* created at construction time. They should call
|
||||||
* {@link #setDefaultCompletionProvider(CompletionProvider)} in this
|
* {@link #setDefaultCompletionProvider(CompletionProvider)} in this
|
||||||
* constructor.
|
* constructor.
|
||||||
*/
|
*/
|
||||||
protected LanguageAwareCompletionProvider() {}
|
protected LanguageAwareCompletionProvider() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param defaultProvider
|
* @param defaultProvider The provider to use when no provider is assigned to a
|
||||||
* The provider to use when no provider is assigned
|
* particular token type. This cannot be
|
||||||
* to a particular token type. This cannot be <code>null</code>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public LanguageAwareCompletionProvider(CompletionProvider defaultProvider) {
|
public LanguageAwareCompletionProvider(CompletionProvider defaultProvider) {
|
||||||
setDefaultCompletionProvider(defaultProvider);
|
setDefaultCompletionProvider(defaultProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calling this method will result in an
|
* Calling this method will result in an {@link UnsupportedOperationException}
|
||||||
* {@link UnsupportedOperationException} being thrown. To set the
|
* being thrown. To set the parameter completion parameters, do so on the
|
||||||
* parameter completion parameters, do so on the provider returned by
|
* provider returned by {@link #getDefaultCompletionProvider()}.
|
||||||
* {@link #getDefaultCompletionProvider()}.
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOperationException
|
* @throws UnsupportedOperationException Always.
|
||||||
* Always.
|
|
||||||
* @see #setParameterizedCompletionParams(char, String, char)
|
* @see #setParameterizedCompletionParams(char, String, char)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -135,10 +133,8 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
/**
|
/**
|
||||||
* Does the dirty work of creating a list of completions.
|
* Does the dirty work of creating a list of completions.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component to look in.
|
||||||
* The text component to look in.
|
* @return The list of possible completions, or an empty list if there are none.
|
||||||
* @return The list of possible completions, or an empty list if there
|
|
||||||
* are none.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<Completion> getCompletionsImpl(JTextComponent comp) {
|
protected List<Completion> getCompletionsImpl(JTextComponent comp) {
|
||||||
@@ -152,8 +148,8 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the completion provider used when one isn't defined for a
|
* Returns the completion provider used when one isn't defined for a particular
|
||||||
* particular token type.
|
* token type.
|
||||||
*
|
*
|
||||||
* @return The completion provider to use.
|
* @return The completion provider to use.
|
||||||
* @see #setDefaultCompletionProvider(CompletionProvider)
|
* @see #setDefaultCompletionProvider(CompletionProvider)
|
||||||
@@ -209,11 +205,10 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the completion provider to use at the current caret position in
|
* Returns the completion provider to use at the current caret position in a
|
||||||
* a text component.
|
* text component.
|
||||||
*
|
*
|
||||||
* @param comp
|
* @param comp The text component to check.
|
||||||
* The text component to check.
|
|
||||||
* @return The completion provider to use.
|
* @return The completion provider to use.
|
||||||
*/
|
*/
|
||||||
private CompletionProvider getProviderFor(JTextComponent comp) {
|
private CompletionProvider getProviderFor(JTextComponent comp) {
|
||||||
@@ -304,8 +299,7 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
/**
|
/**
|
||||||
* Sets the comment completion provider.
|
* Sets the comment completion provider.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to use in comments.
|
||||||
* The provider to use in comments.
|
|
||||||
* @see #getCommentCompletionProvider()
|
* @see #getCommentCompletionProvider()
|
||||||
*/
|
*/
|
||||||
public void setCommentCompletionProvider(CompletionProvider provider) {
|
public void setCommentCompletionProvider(CompletionProvider provider) {
|
||||||
@@ -315,8 +309,7 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
/**
|
/**
|
||||||
* Sets the default completion provider.
|
* Sets the default completion provider.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to use when no provider is assigned to a
|
||||||
* The provider to use when no provider is assigned to a
|
|
||||||
* particular token type. This cannot be <code>null</code>.
|
* particular token type. This cannot be <code>null</code>.
|
||||||
* @see #getDefaultCompletionProvider()
|
* @see #getDefaultCompletionProvider()
|
||||||
*/
|
*/
|
||||||
@@ -330,8 +323,7 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
/**
|
/**
|
||||||
* Sets the documentation comment completion provider.
|
* Sets the documentation comment completion provider.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to use in comments.
|
||||||
* The provider to use in comments.
|
|
||||||
* @see #getDocCommentCompletionProvider()
|
* @see #getDocCommentCompletionProvider()
|
||||||
*/
|
*/
|
||||||
public void setDocCommentCompletionProvider(CompletionProvider provider) {
|
public void setDocCommentCompletionProvider(CompletionProvider provider) {
|
||||||
@@ -339,13 +331,11 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calling this method will result in an
|
* Calling this method will result in an {@link UnsupportedOperationException}
|
||||||
* {@link UnsupportedOperationException} being thrown. To set the
|
* being thrown. To set the parameter completion parameters, do so on the
|
||||||
* parameter completion parameters, do so on the provider returned by
|
* provider returned by {@link #getDefaultCompletionProvider()}.
|
||||||
* {@link #getDefaultCompletionProvider()}.
|
|
||||||
*
|
*
|
||||||
* @throws UnsupportedOperationException
|
* @throws UnsupportedOperationException Always.
|
||||||
* Always.
|
|
||||||
* @see #clearParameterizedCompletionParams()
|
* @see #clearParameterizedCompletionParams()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -356,8 +346,7 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
/**
|
/**
|
||||||
* Sets the completion provider to use while in a string.
|
* Sets the completion provider to use while in a string.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider to use.
|
||||||
* The provider to use.
|
|
||||||
* @see #getStringCompletionProvider()
|
* @see #getStringCompletionProvider()
|
||||||
*/
|
*/
|
||||||
public void setStringCompletionProvider(CompletionProvider provider) {
|
public void setStringCompletionProvider(CompletionProvider provider) {
|
||||||
@@ -368,17 +357,15 @@ public class LanguageAwareCompletionProvider extends CompletionProviderBase impl
|
|||||||
* Returns the tool tip to display for a mouse event.
|
* Returns the tool tip to display for a mouse event.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* For this method to be called, the <tt>RSyntaxTextArea</tt> must be
|
* For this method to be called, the <tt>RSyntaxTextArea</tt> must be registered
|
||||||
* registered with the <tt>javax.swing.ToolTipManager</tt> like so:
|
* with the <tt>javax.swing.ToolTipManager</tt> like so:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* ToolTipManager.sharedInstance().registerComponent(textArea);
|
* ToolTipManager.sharedInstance().registerComponent(textArea);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area.
|
||||||
* The text area.
|
* @param e The mouse event.
|
||||||
* @param e
|
|
||||||
* The mouse event.
|
|
||||||
* @return The tool tip text, or <code>null</code> if none.
|
* @return The tool tip text, or <code>null</code> if none.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ package org.fife.ui.autocomplete;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possibly redirects one URL to another. Useful if you want "external" URL's
|
* Possibly redirects one URL to another. Useful if you want "external" URL's in
|
||||||
* in code completion documentation to point to a local copy instead, for
|
* code completion documentation to point to a local copy instead, for example.
|
||||||
* example.
|
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
|
|||||||
@@ -31,10 +31,8 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent provider instance.
|
||||||
* The parent provider instance.
|
* @param name The name of the tag.
|
||||||
* @param name
|
|
||||||
* The name of the tag.
|
|
||||||
*/
|
*/
|
||||||
public MarkupTagCompletion(CompletionProvider provider, String name) {
|
public MarkupTagCompletion(CompletionProvider provider, String name) {
|
||||||
super(provider);
|
super(provider);
|
||||||
@@ -44,8 +42,7 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Adds HTML describing the attributes of this tag to a buffer.
|
* Adds HTML describing the attributes of this tag to a buffer.
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
*/
|
*/
|
||||||
protected void addAttributes(StringBuilder sb) {
|
protected void addAttributes(StringBuilder sb) {
|
||||||
// TODO: Localize me.
|
// TODO: Localize me.
|
||||||
@@ -86,8 +83,7 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Returns the specified {@link ParameterizedCompletion.Parameter}.
|
* Returns the specified {@link ParameterizedCompletion.Parameter}.
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index The index of the attribute to retrieve.
|
||||||
* The index of the attribute to retrieve.
|
|
||||||
* @return The attribute.
|
* @return The attribute.
|
||||||
* @see #getAttributeCount()
|
* @see #getAttributeCount()
|
||||||
*/
|
*/
|
||||||
@@ -116,11 +112,9 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a short description of this variable. This should be an
|
* Returns a short description of this variable. This should be an HTML snippet.
|
||||||
* HTML snippet.
|
|
||||||
*
|
*
|
||||||
* @return A short description of this variable. This may be
|
* @return A short description of this variable. This may be <code>null</code>.
|
||||||
* <code>null</code>.
|
|
||||||
* @see #setDescription(String)
|
* @see #setDescription(String)
|
||||||
*/
|
*/
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
@@ -158,11 +152,10 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds some HTML describing where this variable is defined, if this
|
* Adds some HTML describing where this variable is defined, if this information
|
||||||
* information is known.
|
* is known.
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
*/
|
*/
|
||||||
protected void possiblyAddDefinedIn(StringBuilder sb) {
|
protected void possiblyAddDefinedIn(StringBuilder sb) {
|
||||||
if (definedIn != null) {
|
if (definedIn != null) {
|
||||||
@@ -172,11 +165,9 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the description text as HTML to a buffer, if a description is
|
* Adds the description text as HTML to a buffer, if a description is defined.
|
||||||
* defined.
|
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
*/
|
*/
|
||||||
protected void possiblyAddDescription(StringBuilder sb) {
|
protected void possiblyAddDescription(StringBuilder sb) {
|
||||||
if (desc != null) {
|
if (desc != null) {
|
||||||
@@ -189,8 +180,7 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets where this variable is defined.
|
* Sets where this variable is defined.
|
||||||
*
|
*
|
||||||
* @param definedIn
|
* @param definedIn Where this variable is defined.
|
||||||
* Where this variable is defined.
|
|
||||||
* @see #getDefinedIn()
|
* @see #getDefinedIn()
|
||||||
*/
|
*/
|
||||||
public void setDefinedIn(String definedIn) {
|
public void setDefinedIn(String definedIn) {
|
||||||
@@ -198,12 +188,9 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the short description of this tag. This should be an
|
* Sets the short description of this tag. This should be an HTML snippet.
|
||||||
* HTML snippet.
|
|
||||||
*
|
*
|
||||||
* @param desc
|
* @param desc A short description of this tag. This may be <code>null</code>.
|
||||||
* A short description of this tag. This may be
|
|
||||||
* <code>null</code>.
|
|
||||||
* @see #getDescription()
|
* @see #getDescription()
|
||||||
*/
|
*/
|
||||||
public void setDescription(String desc) {
|
public void setDescription(String desc) {
|
||||||
@@ -213,8 +200,7 @@ public class MarkupTagCompletion extends AbstractCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets the attributes of this tag.
|
* Sets the attributes of this tag.
|
||||||
*
|
*
|
||||||
* @param attrs
|
* @param attrs The attributes.
|
||||||
* The attributes.
|
|
||||||
* @see #getAttribute(int)
|
* @see #getAttribute(int)
|
||||||
* @see #getAttributeCount()
|
* @see #getAttributeCount()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ import javax.swing.text.Position;
|
|||||||
import javax.swing.text.View;
|
import javax.swing.text.View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Highlight painter that draws an outline around the text. This is used to
|
* Highlight painter that draws an outline around the text. This is used to draw
|
||||||
* draw bounds around function/method parameters.
|
* bounds around function/method parameters.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* NOTE: Whenever you see text like "Workaround for Java Highlight issues",
|
* NOTE: Whenever you see text like "Workaround for Java Highlight issues", this
|
||||||
* this is because highlighted text in a JTextComponent gets "pushed" forward
|
* is because highlighted text in a JTextComponent gets "pushed" forward when
|
||||||
* when the caret is at the Highlight's start, when we need it to instead get
|
* the caret is at the Highlight's start, when we need it to instead get
|
||||||
* prepended to. For this reason, the auto-complete package adds its Highlights
|
* prepended to. For this reason, the auto-complete package adds its Highlights
|
||||||
* 1 char too long (1 char earlier than where it should really start), but only
|
* 1 char too long (1 char earlier than where it should really start), but only
|
||||||
* paint the Highlight from the 2nd char on.
|
* paint the Highlight from the 2nd char on.
|
||||||
@@ -36,17 +36,16 @@ import javax.swing.text.View;
|
|||||||
class OutlineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
|
class OutlineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DefaultHighlightPainter doesn't allow changing color, so we must cache
|
* DefaultHighlightPainter doesn't allow changing color, so we must cache ours
|
||||||
* ours here.
|
* here.
|
||||||
*/
|
*/
|
||||||
private Color color;
|
private Color color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to draw the bounding boxes with. This cannot be
|
||||||
* The color to draw the bounding boxes with. This cannot
|
* <code>null</code>.
|
||||||
* be <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
public OutlineHighlightPainter(Color color) {
|
public OutlineHighlightPainter(Color color) {
|
||||||
super(color);
|
super(color);
|
||||||
@@ -114,8 +113,7 @@ class OutlineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter
|
|||||||
/**
|
/**
|
||||||
* Sets the color to paint the bounding boxes with.
|
* Sets the color to paint the bounding boxes with.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The new color. This cannot be <code>null</code>.
|
||||||
* The new color. This cannot be <code>null</code>.
|
|
||||||
* @see #getColor()
|
* @see #getColor()
|
||||||
*/
|
*/
|
||||||
public void setColor(Color color) {
|
public void setColor(Color color) {
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import java.util.List;
|
|||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides completions for a {@link ParameterizedCompletion}'s parameters.
|
* Provides completions for a {@link ParameterizedCompletion}'s parameters. So,
|
||||||
* So, for example, if the user code-completes a function or method, if
|
* for example, if the user code-completes a function or method, if a
|
||||||
* a <code>ParameterChoicesProvider</code> is installed, it can return possible
|
* <code>ParameterChoicesProvider</code> is installed, it can return possible
|
||||||
* completions for the parameters to that function or method.
|
* completions for the parameters to that function or method.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
@@ -25,12 +25,10 @@ public interface ParameterChoicesProvider {
|
|||||||
/**
|
/**
|
||||||
* Returns a list of choices for a specific parameter.
|
* Returns a list of choices for a specific parameter.
|
||||||
*
|
*
|
||||||
* @param tc
|
* @param tc The text component.
|
||||||
* The text component.
|
* @param param The currently focused parameter.
|
||||||
* @param param
|
* @return The list of parameters. This may be <code>null</code> for "no
|
||||||
* The currently focused parameter.
|
* parameters," but might also be an empty list.
|
||||||
* @return The list of parameters. This may be <code>null</code> for
|
|
||||||
* "no parameters," but might also be an empty list.
|
|
||||||
*/
|
*/
|
||||||
public List<Completion> getParameterChoices(JTextComponent tc, ParameterizedCompletion.Parameter param);
|
public List<Completion> getParameterChoices(JTextComponent tc, ParameterizedCompletion.Parameter param);
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,8 @@ import javax.swing.text.JTextComponent;
|
|||||||
public interface ParameterizedCompletion extends Completion {
|
public interface ParameterizedCompletion extends Completion {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "definition string" for this completion. For example,
|
* Returns the "definition string" for this completion. For example, for the C
|
||||||
* for the C "<code>printf</code>" function, this would return
|
* "<code>printf</code>" function, this would return
|
||||||
* "<code>int printf(const char *, ...)</code>".
|
* "<code>int printf(const char *, ...)</code>".
|
||||||
*
|
*
|
||||||
* @return The definition string.
|
* @return The definition string.
|
||||||
@@ -28,8 +28,7 @@ public interface ParameterizedCompletion extends Completion {
|
|||||||
/**
|
/**
|
||||||
* Returns the specified {@link Parameter}.
|
* Returns the specified {@link Parameter}.
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index The index of the parameter to retrieve.
|
||||||
* The index of the parameter to retrieve.
|
|
||||||
* @return The parameter.
|
* @return The parameter.
|
||||||
* @see #getParamCount()
|
* @see #getParamCount()
|
||||||
*/
|
*/
|
||||||
@@ -46,8 +45,8 @@ public interface ParameterizedCompletion extends Completion {
|
|||||||
public ParameterizedCompletionInsertionInfo getInsertionInfo(JTextComponent tc, boolean replaceTabsWithSpaces);
|
public ParameterizedCompletionInsertionInfo getInsertionInfo(JTextComponent tc, boolean replaceTabsWithSpaces);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a tool tip displaying assistance for each parameter
|
* Returns whether a tool tip displaying assistance for each parameter while it
|
||||||
* while it is being edited is appropriate for this completion.
|
* is being edited is appropriate for this completion.
|
||||||
*
|
*
|
||||||
* @return Whether the tool tip is appropriate to display.
|
* @return Whether the tool tip is appropriate to display.
|
||||||
*/
|
*/
|
||||||
@@ -66,16 +65,13 @@ public interface ParameterizedCompletion extends Completion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type The type of this parameter. This may be <code>null</code> for
|
||||||
* The type of this parameter. This may be
|
* languages without specific types, dynamic typing, etc. Usually
|
||||||
* <code>null</code> for languages without specific types,
|
* you'll pass a String for this value, but you may pass any object
|
||||||
* dynamic typing, etc. Usually you'll pass a String for this
|
* representing a type in your language, as long as its
|
||||||
* value, but you may pass any object representing a type in
|
* <code>toString()</code> method returns a string representation of
|
||||||
* your language, as long as its <code>toString()</code>
|
* the type.
|
||||||
* method
|
* @param name The name of the parameter.
|
||||||
* returns a string representation of the type.
|
|
||||||
* @param name
|
|
||||||
* The name of the parameter.
|
|
||||||
*/
|
*/
|
||||||
public Parameter(Object type, String name) {
|
public Parameter(Object type, String name) {
|
||||||
this(type, name, false);
|
this(type, name, false);
|
||||||
@@ -84,25 +80,19 @@ public interface ParameterizedCompletion extends Completion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type The type of this parameter. This may be <code>null</code> for
|
||||||
* The type of this parameter. This may be
|
* languages without specific types, dynamic typing, etc.
|
||||||
* <code>null</code> for languages without specific types,
|
* Usually you'll pass a String for this value, but you may pass
|
||||||
* dynamic typing, etc. Usually you'll pass a String for this
|
* any object representing a type in your language, as long as
|
||||||
* value, but you may pass any object representing a type in
|
* its <code>toString()</code> method returns a string
|
||||||
* your language, as long as its <code>toString()</code>
|
* representation of the type.
|
||||||
* method
|
* @param name The name of the parameter.
|
||||||
* returns a string representation of the type.
|
* @param endParam Whether this parameter is an "ending parameter;" that is,
|
||||||
* @param name
|
* whether this parameter is at a logical "ending point" in the
|
||||||
* The name of the parameter.
|
* completion text. If the user types in a parameter that is an
|
||||||
* @param endParam
|
* ending point, parameter completion mode terminates. Set this
|
||||||
* Whether this parameter is an "ending parameter;"
|
* to <code>true</code> for a trailing parameter after a
|
||||||
* that is, whether this parameter is at a logical "ending
|
* function call's closing ')', for example.
|
||||||
* point" in the completion text. If the user types in a
|
|
||||||
* parameter that is an ending point, parameter completion
|
|
||||||
* mode
|
|
||||||
* terminates. Set this to <code>true</code> for a trailing
|
|
||||||
* parameter after a function call's closing ')', for
|
|
||||||
* example.
|
|
||||||
*/
|
*/
|
||||||
public Parameter(Object type, String name, boolean endParam) {
|
public Parameter(Object type, String name, boolean endParam) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -137,11 +127,10 @@ public interface ParameterizedCompletion extends Completion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether this parameter is an "ending parameter;"
|
* @return Whether this parameter is an "ending parameter;" that is, whether
|
||||||
* that is, whether this parameter is at a logical "ending
|
* this parameter is at a logical "ending point" in the completion text.
|
||||||
* point" in the completion text. If the user types in a
|
* If the user types in a parameter that is an ending point, parameter
|
||||||
* parameter that is an ending point, parameter completion mode
|
* completion mode terminates.
|
||||||
* terminates.
|
|
||||||
*/
|
*/
|
||||||
public boolean isEndParam() {
|
public boolean isEndParam() {
|
||||||
return isEndParam;
|
return isEndParam;
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ import javax.swing.text.JTextComponent;
|
|||||||
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A small popup window offering a list of likely choices for a parameter
|
* A small popup window offering a list of likely choices for a parameter when
|
||||||
* when the user has code-completed a parameterized completion. For example,
|
* the user has code-completed a parameterized completion. For example, if they
|
||||||
* if they have just code-completed the C function "<code>fprintf</code>",
|
* have just code-completed the C function "<code>fprintf</code>", when entering
|
||||||
* when entering the file name, this popup might display all local variables
|
* the file name, this popup might display all local variables of type
|
||||||
* of type "<code>char *</code>".
|
* "<code>char *</code>".
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -60,22 +60,20 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
*/
|
*/
|
||||||
private JScrollPane sp;
|
private JScrollPane sp;
|
||||||
/**
|
/**
|
||||||
* Comparator used to sort completions by their relevance before sorting
|
* Comparator used to sort completions by their relevance before sorting them
|
||||||
* them lexicographically.
|
* lexicographically.
|
||||||
*/
|
*/
|
||||||
private static final Comparator<Completion> sortByRelevanceComparator = new SortByRelevanceComparator();
|
private static final Comparator<Completion> sortByRelevanceComparator = new SortByRelevanceComparator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param parent
|
* @param parent The parent window (hosting the text component).
|
||||||
* The parent window (hosting the text component).
|
* @param ac The auto-completion instance.
|
||||||
* @param ac
|
* @param context The completion context.
|
||||||
* The auto-completion instance.
|
|
||||||
* @param context
|
|
||||||
* The completion context.
|
|
||||||
*/
|
*/
|
||||||
public ParameterizedCompletionChoicesWindow(Window parent, AutoCompletion ac, final ParameterizedCompletionContext context) {
|
public ParameterizedCompletionChoicesWindow(Window parent, AutoCompletion ac,
|
||||||
|
final ParameterizedCompletionContext context) {
|
||||||
super(parent);
|
super(parent);
|
||||||
this.ac = ac;
|
this.ac = ac;
|
||||||
ComponentOrientation o = ac.getTextComponentOrientation();
|
ComponentOrientation o = ac.getTextComponentOrientation();
|
||||||
@@ -107,8 +105,7 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
/**
|
/**
|
||||||
* Returns the selected value.
|
* Returns the selected value.
|
||||||
*
|
*
|
||||||
* @return The selected value, or <code>null</code> if nothing is
|
* @return The selected value, or <code>null</code> if nothing is selected.
|
||||||
* selected.
|
|
||||||
*/
|
*/
|
||||||
public String getSelectedChoice() {
|
public String getSelectedChoice() {
|
||||||
Completion c = (Completion) list.getSelectedValue();
|
Completion c = (Completion) list.getSelectedValue();
|
||||||
@@ -118,8 +115,7 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
/**
|
/**
|
||||||
* Changes the selected index.
|
* Changes the selected index.
|
||||||
*
|
*
|
||||||
* @param amount
|
* @param amount The amount by which to change the selected index.
|
||||||
* The amount by which to change the selected index.
|
|
||||||
*/
|
*/
|
||||||
public void incSelection(int amount) {
|
public void incSelection(int amount) {
|
||||||
int selection = list.getSelectedIndex();
|
int selection = list.getSelectedIndex();
|
||||||
@@ -135,12 +131,10 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this window to offer suggestions for the parameters of
|
* Initializes this window to offer suggestions for the parameters of a specific
|
||||||
* a specific completion.
|
* completion.
|
||||||
*
|
*
|
||||||
* @param pc
|
* @param pc The completion whose parameters we should offer suggestions for.
|
||||||
* The completion whose parameters we should offer suggestions
|
|
||||||
* for.
|
|
||||||
*/
|
*/
|
||||||
public void initialize(ParameterizedCompletion pc) {
|
public void initialize(ParameterizedCompletion pc) {
|
||||||
CompletionProvider provider = pc.getProvider();
|
CompletionProvider provider = pc.getProvider();
|
||||||
@@ -162,8 +156,7 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
/**
|
/**
|
||||||
* Sets the location of this window relative to the given rectangle.
|
* Sets the location of this window relative to the given rectangle.
|
||||||
*
|
*
|
||||||
* @param r
|
* @param r The visual position of the caret (in screen coordinates).
|
||||||
* The visual position of the caret (in screen coordinates).
|
|
||||||
*/
|
*/
|
||||||
public void setLocationRelativeTo(Rectangle r) {
|
public void setLocationRelativeTo(Rectangle r) {
|
||||||
// Multi-monitor support - make sure the completion window (and
|
// Multi-monitor support - make sure the completion window (and
|
||||||
@@ -189,16 +182,14 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the choices for the specified parameter matching the given
|
* Displays the choices for the specified parameter matching the given text.
|
||||||
* text. This will display or hide this popup window as necessary.
|
* This will display or hide this popup window as necessary.
|
||||||
*
|
*
|
||||||
* @param param
|
* @param param The index of the parameter the caret is currently in. This may
|
||||||
* The index of the parameter the caret is currently in.
|
* be <code>-1</code> if not in a parameter (i.e., on the comma
|
||||||
* This may be <code>-1</code> if not in a parameter (i.e., on
|
* between parameters).
|
||||||
* the comma between parameters).
|
* @param prefix Text in the parameter before the dot. This may be
|
||||||
* @param prefix
|
* <code>null</code> to represent the empty string.
|
||||||
* Text in the parameter before the dot. This may
|
|
||||||
* be <code>null</code> to represent the empty string.
|
|
||||||
*/
|
*/
|
||||||
public void setParameter(int param, String prefix) {
|
public void setParameter(int param, String prefix) {
|
||||||
model.clear();
|
model.clear();
|
||||||
@@ -254,8 +245,7 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
|
|||||||
/**
|
/**
|
||||||
* Toggles the visibility of this popup window.
|
* Toggles the visibility of this popup window.
|
||||||
*
|
*
|
||||||
* @param visible
|
* @param visible Whether this window should be visible.
|
||||||
* Whether this window should be visible.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ import org.fife.ui.rtextarea.ChangeableHighlightPainter;
|
|||||||
/**
|
/**
|
||||||
* Manages UI and state specific to parameterized completions - the parameter
|
* Manages UI and state specific to parameterized completions - the parameter
|
||||||
* description tool tip, the parameter completion choices list, the actual
|
* description tool tip, the parameter completion choices list, the actual
|
||||||
* highlights in the editor, etc. This component installs new key bindings
|
* highlights in the editor, etc. This component installs new key bindings when
|
||||||
* when appropriate to allow the user to cycle through the parameters of the
|
* appropriate to allow the user to cycle through the parameters of the
|
||||||
* completion, and optionally cycle through completion choices for those
|
* completion, and optionally cycle through completion choices for those
|
||||||
* parameters.
|
* parameters.
|
||||||
*
|
*
|
||||||
@@ -95,13 +95,13 @@ class ParameterizedCompletionContext {
|
|||||||
*/
|
*/
|
||||||
private Listener listener;
|
private Listener listener;
|
||||||
/**
|
/**
|
||||||
* The minimum offset into the document that the caret can move to
|
* The minimum offset into the document that the caret can move to before this
|
||||||
* before this tool tip disappears.
|
* tool tip disappears.
|
||||||
*/
|
*/
|
||||||
private int minPos;
|
private int minPos;
|
||||||
/**
|
/**
|
||||||
* The maximum offset into the document that the caret can move to
|
* The maximum offset into the document that the caret can move to before this
|
||||||
* before this tool tip disappears.
|
* tool tip disappears.
|
||||||
*/
|
*/
|
||||||
private Position maxPos; // Moves with text inserted.
|
private Position maxPos; // Moves with text inserted.
|
||||||
private Position defaultEndOffs;
|
private Position defaultEndOffs;
|
||||||
@@ -208,8 +208,7 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides any popup windows and terminates parameterized completion
|
* Hides any popup windows and terminates parameterized completion assistance.
|
||||||
* assistance.
|
|
||||||
*
|
*
|
||||||
* @see #activate()
|
* @see #activate()
|
||||||
*/
|
*/
|
||||||
@@ -228,13 +227,11 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text inserted for the parameter containing the specified
|
* Returns the text inserted for the parameter containing the specified offset.
|
||||||
* offset.
|
|
||||||
*
|
*
|
||||||
* @param offs
|
* @param offs The offset into the document.
|
||||||
* The offset into the document.
|
* @return The text of the parameter containing the offset, or <code>null</code>
|
||||||
* @return The text of the parameter containing the offset, or
|
* if the offset is not in a parameter.
|
||||||
* <code>null</code> if the offset is not in a parameter.
|
|
||||||
*/
|
*/
|
||||||
public String getArgumentText(int offs) {
|
public String getArgumentText(int offs) {
|
||||||
List<Highlight> paramHighlights = getParameterHighlights();
|
List<Highlight> paramHighlights = getParameterHighlights();
|
||||||
@@ -262,8 +259,8 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Returns the highlight of the current parameter.
|
* Returns the highlight of the current parameter.
|
||||||
*
|
*
|
||||||
* @return The current parameter's highlight, or <code>null</code> if
|
* @return The current parameter's highlight, or <code>null</code> if the caret
|
||||||
* the caret is not in a parameter's bounds.
|
* is not in a parameter's bounds.
|
||||||
* @see #getCurrentParameterStartOffset()
|
* @see #getCurrentParameterStartOffset()
|
||||||
*/
|
*/
|
||||||
private Highlight getCurrentParameterHighlight() {
|
private Highlight getCurrentParameterHighlight() {
|
||||||
@@ -300,8 +297,8 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Returns the starting offset of the current parameter.
|
* Returns the starting offset of the current parameter.
|
||||||
*
|
*
|
||||||
* @return The current parameter's starting offset, or <code>-1</code> if
|
* @return The current parameter's starting offset, or <code>-1</code> if the
|
||||||
* the caret is not in a parameter's bounds.
|
* caret is not in a parameter's bounds.
|
||||||
* @see #getCurrentParameterHighlight()
|
* @see #getCurrentParameterHighlight()
|
||||||
*/
|
*/
|
||||||
private int getCurrentParameterStartOffset() {
|
private int getCurrentParameterStartOffset() {
|
||||||
@@ -310,13 +307,12 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highlight from a list that comes "first" in a list. Even
|
* Returns the highlight from a list that comes "first" in a list. Even though
|
||||||
* though most parameter highlights are ordered, sometimes they aren't
|
* most parameter highlights are ordered, sometimes they aren't (e.g. the
|
||||||
* (e.g. the "cursor" parameter in a template completion is always last,
|
* "cursor" parameter in a template completion is always last, even though it
|
||||||
* even though it can be anywhere in the template).
|
* can be anywhere in the template).
|
||||||
*
|
*
|
||||||
* @param highlights
|
* @param highlights The list of highlights. Assumed to be non-empty.
|
||||||
* The list of highlights. Assumed to be non-empty.
|
|
||||||
* @return The highlight that comes first in the document.
|
* @return The highlight that comes first in the document.
|
||||||
* @see #getLastHighlight(List)
|
* @see #getLastHighlight(List)
|
||||||
*/
|
*/
|
||||||
@@ -334,13 +330,12 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highlight from a list that comes "last" in that list. Even
|
* Returns the highlight from a list that comes "last" in that list. Even though
|
||||||
* though most parameter highlights are ordered, sometimes they aren't
|
* most parameter highlights are ordered, sometimes they aren't (e.g. the
|
||||||
* (e.g. the "cursor" parameter in a template completion is always last,
|
* "cursor" parameter in a template completion is always last, even though it
|
||||||
* even though it can be anywhere in the template.
|
* can be anywhere in the template.
|
||||||
*
|
*
|
||||||
* @param highlights
|
* @param highlights The list of highlights. Assumed to be non-empty.
|
||||||
* The list of highlights. Assumed to be non-empty.
|
|
||||||
* @return The highlight that comes last in the document.
|
* @return The highlight that comes last in the document.
|
||||||
* @see #getFirstHighlight(List)
|
* @see #getFirstHighlight(List)
|
||||||
*/
|
*/
|
||||||
@@ -373,8 +368,8 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Inserts the choice selected in the parameter choices window.
|
* Inserts the choice selected in the parameter choices window.
|
||||||
*
|
*
|
||||||
* @return Whether the choice was inserted. This will be <code>false</code>
|
* @return Whether the choice was inserted. This will be <code>false</code> if
|
||||||
* if the window is not visible, or no choice is selected.
|
* the window is not visible, or no choice is selected.
|
||||||
*/
|
*/
|
||||||
boolean insertSelectedChoice() {
|
boolean insertSelectedChoice() {
|
||||||
if (paramChoicesWindow != null && paramChoicesWindow.isVisible()) {
|
if (paramChoicesWindow != null && paramChoicesWindow.isVisible()) {
|
||||||
@@ -398,8 +393,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs key bindings on the text component that facilitate the user
|
* Installs key bindings on the text component that facilitate the user editing
|
||||||
* editing this completion's parameters.
|
* this completion's parameters.
|
||||||
*
|
*
|
||||||
* @see #uninstallKeyBindings()
|
* @see #uninstallKeyBindings()
|
||||||
*/
|
*/
|
||||||
@@ -507,8 +502,8 @@ class ParameterizedCompletionContext {
|
|||||||
List<Highlight> highlights = getParameterHighlights();
|
List<Highlight> highlights = getParameterHighlights();
|
||||||
for (int i = 0; i < highlights.size(); i++) {
|
for (int i = 0; i < highlights.size(); i++) {
|
||||||
Highlight h = highlights.get(i);
|
Highlight h = highlights.get(i);
|
||||||
if (currentPrev == null || currentPrev.getStartOffset() >= dot
|
if (currentPrev == null || currentPrev.getStartOffset() >= dot || (h.getStartOffset() < selStart
|
||||||
|| (h.getStartOffset() < selStart && (h.getStartOffset() > currentPrev.getStartOffset() || pos == lastSelectedParam))) {
|
&& (h.getStartOffset() > currentPrev.getStartOffset() || pos == lastSelectedParam))) {
|
||||||
currentPrev = h;
|
currentPrev = h;
|
||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
@@ -613,17 +608,14 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces highlighted text with new text. Takes special care so that
|
* Replaces highlighted text with new text. Takes special care so that the
|
||||||
* the highlight stays just around the newly-highlighted text, since
|
* highlight stays just around the newly-highlighted text, since Swing's
|
||||||
* Swing's <code>Highlight</code> classes are funny about insertions at
|
* <code>Highlight</code> classes are funny about insertions at their start
|
||||||
* their start offsets.
|
* offsets.
|
||||||
*
|
*
|
||||||
* @param doc
|
* @param doc The document.
|
||||||
* The document.
|
* @param h The highlight whose text to change.
|
||||||
* @param h
|
* @param replacement The new text to be in the highlight.
|
||||||
* The highlight whose text to change.
|
|
||||||
* @param replacement
|
|
||||||
* The new text to be in the highlight.
|
|
||||||
* @return The replacement highlight for <code>h</code>.
|
* @return The replacement highlight for <code>h</code>.
|
||||||
*/
|
*/
|
||||||
private Highlight replaceHighlightedText(Document doc, Highlight h, String replacement) {
|
private Highlight replaceHighlightedText(Document doc, Highlight h, String replacement) {
|
||||||
@@ -684,9 +676,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the text in the tool tip to have the current parameter
|
* Updates the text in the tool tip to have the current parameter displayed in
|
||||||
* displayed in bold. The "current parameter" is determined from the
|
* bold. The "current parameter" is determined from the current caret position.
|
||||||
* current caret position.
|
|
||||||
*
|
*
|
||||||
* @return The "prefix" of text in the caret's parameter before the caret.
|
* @return The "prefix" of text in the caret's parameter before the caret.
|
||||||
*/
|
*/
|
||||||
@@ -779,8 +770,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the user types the character marking the closing of the
|
* Called when the user types the character marking the closing of the parameter
|
||||||
* parameter list, such as '<code>)</code>'.
|
* list, such as '<code>)</code>'.
|
||||||
*/
|
*/
|
||||||
private class ClosingAction extends AbstractAction {
|
private class ClosingAction extends AbstractAction {
|
||||||
|
|
||||||
@@ -846,8 +837,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for various events in the text component while this tool tip
|
* Listens for various events in the text component while this tool tip is
|
||||||
* is visible.
|
* visible.
|
||||||
*/
|
*/
|
||||||
private class Listener implements FocusListener, CaretListener, DocumentListener {
|
private class Listener implements FocusListener, CaretListener, DocumentListener {
|
||||||
|
|
||||||
@@ -856,8 +847,7 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Called when the text component's caret moves.
|
* Called when the text component's caret moves.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void caretUpdate(CaretEvent e) {
|
public void caretUpdate(CaretEvent e) {
|
||||||
@@ -877,13 +867,13 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changedUpdate(DocumentEvent e) {}
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the text component gains focus.
|
* Called when the text component gains focus.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void focusGained(FocusEvent e) {
|
public void focusGained(FocusEvent e) {
|
||||||
@@ -893,8 +883,7 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Called when the text component loses focus.
|
* Called when the text component loses focus.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void focusLost(FocusEvent e) {
|
public void focusLost(FocusEvent e) {
|
||||||
@@ -923,8 +912,7 @@ class ParameterizedCompletionContext {
|
|||||||
/**
|
/**
|
||||||
* Installs this listener onto a text component.
|
* Installs this listener onto a text component.
|
||||||
*
|
*
|
||||||
* @param tc
|
* @param tc The text component to install onto.
|
||||||
* The text component to install onto.
|
|
||||||
* @see #uninstall()
|
* @see #uninstall()
|
||||||
*/
|
*/
|
||||||
public void install(JTextComponent tc) {
|
public void install(JTextComponent tc) {
|
||||||
@@ -950,7 +938,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < info.getReplacementCopyCount(); i++) {
|
for (int i = 0; i < info.getReplacementCopyCount(); i++) {
|
||||||
ReplacementCopy rc = info.getReplacementCopy(i);
|
ReplacementCopy rc = info.getReplacementCopy(i);
|
||||||
paramCopyInfos.add(new ParamCopyInfo(rc.getId(), (Highlight) h.addHighlight(rc.getStart(), rc.getEnd(), paramCopyP)));
|
paramCopyInfos.add(new ParamCopyInfo(rc.getId(),
|
||||||
|
(Highlight) h.addHighlight(rc.getStart(), rc.getEnd(), paramCopyP)));
|
||||||
}
|
}
|
||||||
// Go back and start at the first parameter.
|
// Go back and start at the first parameter.
|
||||||
tc.setCaretPosition(info.getSelectionStart());
|
tc.setCaretPosition(info.getSelectionStart());
|
||||||
@@ -1007,8 +996,8 @@ class ParameterizedCompletionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action performed when the user presses the up or down arrow keys and
|
* Action performed when the user presses the up or down arrow keys and the
|
||||||
* the parameter completion choices popup is visible.
|
* parameter completion choices popup is visible.
|
||||||
*/
|
*/
|
||||||
private class NextChoiceAction extends AbstractAction {
|
private class NextChoiceAction extends AbstractAction {
|
||||||
|
|
||||||
|
|||||||
@@ -45,19 +45,17 @@ class ParameterizedCompletionDescriptionToolTip {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param owner
|
* @param owner The parent window.
|
||||||
* The parent window.
|
* @param ac The parent auto-completion.
|
||||||
* @param ac
|
* @param pc The completion being described.
|
||||||
* The parent auto-completion.
|
|
||||||
* @param pc
|
|
||||||
* The completion being described.
|
|
||||||
*/
|
*/
|
||||||
public ParameterizedCompletionDescriptionToolTip(Window owner, ParameterizedCompletionContext context, AutoCompletion ac,
|
public ParameterizedCompletionDescriptionToolTip(Window owner, ParameterizedCompletionContext context,
|
||||||
ParameterizedCompletion pc) {
|
AutoCompletion ac, ParameterizedCompletion pc) {
|
||||||
tooltip = new JWindow(owner);
|
tooltip = new JWindow(owner);
|
||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
descLabel = new JLabel();
|
descLabel = new JLabel();
|
||||||
descLabel.setBorder(BorderFactory.createCompoundBorder(TipUtil.getToolTipBorder(), BorderFactory.createEmptyBorder(2, 5, 2, 5)));
|
descLabel.setBorder(BorderFactory.createCompoundBorder(TipUtil.getToolTipBorder(),
|
||||||
|
BorderFactory.createEmptyBorder(2, 5, 2, 5)));
|
||||||
descLabel.setOpaque(true);
|
descLabel.setOpaque(true);
|
||||||
descLabel.setBackground(TipUtil.getToolTipBackground());
|
descLabel.setBackground(TipUtil.getToolTipBackground());
|
||||||
// It appears that if a JLabel is set as a content pane directly, when
|
// It appears that if a JLabel is set as a content pane directly, when
|
||||||
@@ -91,8 +89,7 @@ class ParameterizedCompletionDescriptionToolTip {
|
|||||||
/**
|
/**
|
||||||
* Sets the location of this tool tip relative to the given rectangle.
|
* Sets the location of this tool tip relative to the given rectangle.
|
||||||
*
|
*
|
||||||
* @param r
|
* @param r The visual position of the caret (in screen coordinates).
|
||||||
* The visual position of the caret (in screen coordinates).
|
|
||||||
*/
|
*/
|
||||||
public void setLocationRelativeTo(Rectangle r) {
|
public void setLocationRelativeTo(Rectangle r) {
|
||||||
// Multi-monitor support - make sure the completion window (and
|
// Multi-monitor support - make sure the completion window (and
|
||||||
@@ -123,8 +120,7 @@ class ParameterizedCompletionDescriptionToolTip {
|
|||||||
/**
|
/**
|
||||||
* Toggles the visibility of this tool tip.
|
* Toggles the visibility of this tool tip.
|
||||||
*
|
*
|
||||||
* @param visible
|
* @param visible Whether this tool tip should be visible.
|
||||||
* Whether this tool tip should be visible.
|
|
||||||
* @see #isVisible()
|
* @see #isVisible()
|
||||||
*/
|
*/
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
@@ -132,11 +128,10 @@ class ParameterizedCompletionDescriptionToolTip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the text in the tool tip to have the current parameter
|
* Updates the text in the tool tip to have the current parameter displayed in
|
||||||
* displayed in bold.
|
* bold.
|
||||||
*
|
*
|
||||||
* @param selectedParam
|
* @param selectedParam The index of the selected parameter.
|
||||||
* The index of the selected parameter.
|
|
||||||
* @return Whether the text needed to be updated.
|
* @return Whether the text needed to be updated.
|
||||||
*/
|
*/
|
||||||
public boolean updateText(int selectedParam) {
|
public boolean updateText(int selectedParam) {
|
||||||
@@ -172,8 +167,7 @@ class ParameterizedCompletionDescriptionToolTip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the <tt>LookAndFeel</tt> of this window and the description
|
* Updates the <tt>LookAndFeel</tt> of this window and the description window.
|
||||||
* window.
|
|
||||||
*/
|
*/
|
||||||
public void updateUI() {
|
public void updateUI() {
|
||||||
SwingUtilities.updateComponentTreeUI(tooltip);
|
SwingUtilities.updateComponentTreeUI(tooltip);
|
||||||
|
|||||||
@@ -44,13 +44,11 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks a region of the replacement text as representing a variable name
|
* Marks a region of the replacement text as representing a variable name or
|
||||||
* or some other construct that the user should replace.
|
* some other construct that the user should replace.
|
||||||
*
|
*
|
||||||
* @param start
|
* @param start The start offset.
|
||||||
* The start offset.
|
* @param end The end offset.
|
||||||
* @param end
|
|
||||||
* The end offset.
|
|
||||||
* @see #getReplacementCount()
|
* @see #getReplacementCount()
|
||||||
* @see #getReplacementLocation(int)
|
* @see #getReplacementLocation(int)
|
||||||
*/
|
*/
|
||||||
@@ -66,8 +64,8 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum offset the caret can move to before being outside
|
* Returns the maximum offset the caret can move to before being outside of the
|
||||||
* of the text inserted for this completion.
|
* text inserted for this completion.
|
||||||
*
|
*
|
||||||
* @return The maximum offset.
|
* @return The maximum offset.
|
||||||
* @see #getMinOffset()
|
* @see #getMinOffset()
|
||||||
@@ -77,8 +75,8 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the minimum offset the caret can move to before being outside
|
* Returns the minimum offset the caret can move to before being outside of the
|
||||||
* of the text inserted for this completion.
|
* text inserted for this completion.
|
||||||
*
|
*
|
||||||
* @return The minimum offset.
|
* @return The minimum offset.
|
||||||
* @see #getMaxOffset()
|
* @see #getMaxOffset()
|
||||||
@@ -105,11 +103,10 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the starting- and ending-offsets of the replacement regions
|
* Returns the starting- and ending-offsets of the replacement regions in the
|
||||||
* in the completion.
|
* completion.
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index The replacement region.
|
||||||
* The replacement region.
|
|
||||||
* @return The range in the document of that replacement region.
|
* @return The range in the document of that replacement region.
|
||||||
* @see #getReplacementCount()
|
* @see #getReplacementCount()
|
||||||
*/
|
*/
|
||||||
@@ -118,9 +115,9 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset that should be the end of the initially selected
|
* Returns the offset that should be the end of the initially selected text when
|
||||||
* text when the completion is inserted (i.e., the end offset of the first
|
* the completion is inserted (i.e., the end offset of the first replacement
|
||||||
* replacement region).
|
* region).
|
||||||
*
|
*
|
||||||
* @return The end offset for the initial selection.
|
* @return The end offset for the initial selection.
|
||||||
* @see #getSelectionStart()
|
* @see #getSelectionStart()
|
||||||
@@ -130,9 +127,9 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset that should be the start of the initially selected
|
* Returns the offset that should be the start of the initially selected text
|
||||||
* text when the completion is inserted (i.e., the start offset of the
|
* when the completion is inserted (i.e., the start offset of the first
|
||||||
* first replacement region).
|
* replacement region).
|
||||||
*
|
*
|
||||||
* @return The start offset for the initial selection.
|
* @return The start offset for the initial selection.
|
||||||
* @see #getSelectionEnd()
|
* @see #getSelectionEnd()
|
||||||
@@ -152,8 +149,8 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not there is an initial selected region for the
|
* Returns whether or not there is an initial selected region for the completion
|
||||||
* completion (i.e., whether the completion actually has any parameters).
|
* (i.e., whether the completion actually has any parameters).
|
||||||
*
|
*
|
||||||
* @return Whether there is a region to initially select for the completion.
|
* @return Whether there is a region to initially select for the completion.
|
||||||
*/
|
*/
|
||||||
@@ -164,10 +161,8 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
/**
|
/**
|
||||||
* Sets the initially selected region for the completion.
|
* Sets the initially selected region for the completion.
|
||||||
*
|
*
|
||||||
* @param selStart
|
* @param selStart The selection start.
|
||||||
* The selection start.
|
* @param selEnd The selection end.
|
||||||
* @param selEnd
|
|
||||||
* The selection end.
|
|
||||||
* @see #getSelectionEnd()
|
* @see #getSelectionEnd()
|
||||||
* @see #getSelectionStart()
|
* @see #getSelectionStart()
|
||||||
*/
|
*/
|
||||||
@@ -177,13 +172,11 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the document range the caret can move around in before being
|
* Sets the document range the caret can move around in before being outside of
|
||||||
* outside of the text inserted for the completion.
|
* the text inserted for the completion.
|
||||||
*
|
*
|
||||||
* @param minOffs
|
* @param minOffs The minimum offset.
|
||||||
* The minimum offset.
|
* @param maxOffs The maximum offset, that will track its location as the
|
||||||
* @param maxOffs
|
|
||||||
* The maximum offset, that will track its location as the
|
|
||||||
* document is modified.
|
* document is modified.
|
||||||
* @see #getMinOffset()
|
* @see #getMinOffset()
|
||||||
* @see #getMaxOffset()
|
* @see #getMaxOffset()
|
||||||
@@ -200,8 +193,7 @@ class ParameterizedCompletionInsertionInfo {
|
|||||||
/**
|
/**
|
||||||
* Sets the text to insert for the completion.
|
* Sets the text to insert for the completion.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param text The text to insert.
|
||||||
* The text to insert.
|
|
||||||
* @see #getTextToInsert()
|
* @see #getTextToInsert()
|
||||||
*/
|
*/
|
||||||
public void setTextToInsert(String text) {
|
public void setTextToInsert(String text) {
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import javax.swing.Action;
|
|||||||
/**
|
/**
|
||||||
* An <code>AutoCompletion</code> that adds the ability to cycle through a set
|
* An <code>AutoCompletion</code> that adds the ability to cycle through a set
|
||||||
* of <code>CompletionProvider</code>s via the trigger key. This allows the
|
* of <code>CompletionProvider</code>s via the trigger key. This allows the
|
||||||
* application to logically "group together" completions of similar kinds;
|
* application to logically "group together" completions of similar kinds; for
|
||||||
* for example, Java code completions vs. template completions.
|
* example, Java code completions vs. template completions.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
@@ -40,8 +40,7 @@ public class RoundRobinAutoCompletion extends AutoCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider A single completion provider.
|
||||||
* A single completion provider.
|
|
||||||
* @see #addCompletionProvider(CompletionProvider)
|
* @see #addCompletionProvider(CompletionProvider)
|
||||||
*/
|
*/
|
||||||
public RoundRobinAutoCompletion(CompletionProvider provider) {
|
public RoundRobinAutoCompletion(CompletionProvider provider) {
|
||||||
@@ -60,23 +59,22 @@ public class RoundRobinAutoCompletion extends AutoCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an additional <code>CompletionProvider</code> to the list to
|
* Adds an additional <code>CompletionProvider</code> to the list to cycle
|
||||||
* cycle through.
|
* through.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The new completion provider.
|
||||||
* The new completion provider.
|
|
||||||
*/
|
*/
|
||||||
public void addCompletionProvider(CompletionProvider provider) {
|
public void addCompletionProvider(CompletionProvider provider) {
|
||||||
cycle.add(provider);
|
cycle.add(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to the next Provider internally. Needs refresh of the popup window
|
* Moves to the next Provider internally. Needs refresh of the popup window to
|
||||||
* to display the changes.
|
* display the changes.
|
||||||
*
|
*
|
||||||
* @return true if the next provider was the default one (thus returned to
|
* @return true if the next provider was the default one (thus returned to the
|
||||||
* the default view). May be used in case you like to hide the
|
* default view). May be used in case you like to hide the popup in this
|
||||||
* popup in this case.
|
* case.
|
||||||
*/
|
*/
|
||||||
public boolean advanceProvider() {
|
public boolean advanceProvider() {
|
||||||
CompletionProvider currentProvider = getCompletionProvider();
|
CompletionProvider currentProvider = getCompletionProvider();
|
||||||
@@ -106,8 +104,8 @@ public class RoundRobinAutoCompletion extends AutoCompletion {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the auto-complete action that ensures the proper
|
* An implementation of the auto-complete action that ensures the proper
|
||||||
* <code>CompletionProvider</code> is displayed based on the context in
|
* <code>CompletionProvider</code> is displayed based on the context in which
|
||||||
* which the user presses the trigger key.
|
* the user presses the trigger key.
|
||||||
*/
|
*/
|
||||||
private class CycleAutoCompleteAction extends AutoCompleteAction {
|
private class CycleAutoCompleteAction extends AutoCompleteAction {
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,9 @@ public class ShorthandCompletion extends BasicCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider that returns this completion.
|
||||||
* The provider that returns this completion.
|
* @param inputText The text the user inputs to get this completion.
|
||||||
* @param inputText
|
* @param replacementText The replacement text of the completion.
|
||||||
* The text the user inputs to get this completion.
|
|
||||||
* @param replacementText
|
|
||||||
* The replacement text of the completion.
|
|
||||||
*/
|
*/
|
||||||
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText) {
|
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText) {
|
||||||
super(provider, replacementText);
|
super(provider, replacementText);
|
||||||
@@ -41,18 +38,15 @@ public class ShorthandCompletion extends BasicCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider that returns this completion.
|
||||||
* The provider that returns this completion.
|
* @param inputText The text the user inputs to get this completion.
|
||||||
* @param inputText
|
* @param replacementText The replacement text of the completion.
|
||||||
* The text the user inputs to get this completion.
|
* @param shortDesc A short description of the completion. This will be
|
||||||
* @param replacementText
|
|
||||||
* The replacement text of the completion.
|
|
||||||
* @param shortDesc
|
|
||||||
* A short description of the completion. This will be
|
|
||||||
* displayed in the completion list. This may be
|
* displayed in the completion list. This may be
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText, String shortDesc) {
|
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText,
|
||||||
|
String shortDesc) {
|
||||||
super(provider, replacementText, shortDesc);
|
super(provider, replacementText, shortDesc);
|
||||||
this.inputText = inputText;
|
this.inputText = inputText;
|
||||||
}
|
}
|
||||||
@@ -60,21 +54,17 @@ public class ShorthandCompletion extends BasicCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider that returns this completion.
|
||||||
* The provider that returns this completion.
|
* @param inputText The text the user inputs to get this completion.
|
||||||
* @param inputText
|
* @param replacementText The replacement text of the completion.
|
||||||
* The text the user inputs to get this completion.
|
* @param shortDesc A short description of the completion. This will be
|
||||||
* @param replacementText
|
|
||||||
* The replacement text of the completion.
|
|
||||||
* @param shortDesc
|
|
||||||
* A short description of the completion. This will be
|
|
||||||
* displayed in the completion list. This may be
|
* displayed in the completion list. This may be
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @param summary
|
* @param summary The summary of this completion. This should be HTML.
|
||||||
* The summary of this completion. This should be HTML.
|
|
||||||
* This may be <code>null</code>.
|
* This may be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText, String shortDesc, String summary) {
|
public ShorthandCompletion(CompletionProvider provider, String inputText, String replacementText, String shortDesc,
|
||||||
|
String summary) {
|
||||||
super(provider, replacementText, shortDesc, summary);
|
super(provider, replacementText, shortDesc, summary);
|
||||||
this.inputText = inputText;
|
this.inputText = inputText;
|
||||||
}
|
}
|
||||||
@@ -93,8 +83,7 @@ public class ShorthandCompletion extends BasicCompletion {
|
|||||||
* If a summary has been set, that summary is returned. Otherwise, the
|
* If a summary has been set, that summary is returned. Otherwise, the
|
||||||
* replacement text is returned.
|
* replacement text is returned.
|
||||||
*
|
*
|
||||||
* @return A description of this completion (the text that will be
|
* @return A description of this completion (the text that will be inserted).
|
||||||
* inserted).
|
|
||||||
* @see #getReplacementText()
|
* @see #getReplacementText()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -104,9 +93,9 @@ public class ShorthandCompletion extends BasicCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "body" of the HTML returned by {@link #getSummary()} when
|
* Returns the "body" of the HTML returned by {@link #getSummary()} when no
|
||||||
* no summary text has been set. This is defined to return the replacement
|
* summary text has been set. This is defined to return the replacement text in
|
||||||
* text in a monospaced font.
|
* a monospaced font.
|
||||||
*
|
*
|
||||||
* @return The summary text's body, if no other summary has been defined.
|
* @return The summary text's body, if no other summary has been defined.
|
||||||
* @see #getReplacementText()
|
* @see #getReplacementText()
|
||||||
|
|||||||
@@ -51,11 +51,10 @@ class SizeGrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden to ensure that the cursor for this component is appropriate
|
* Overridden to ensure that the cursor for this component is appropriate for
|
||||||
* for the orientation.
|
* the orientation.
|
||||||
*
|
*
|
||||||
* @param o
|
* @param o The new orientation.
|
||||||
* The new orientation.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void applyComponentOrientation(ComponentOrientation o) {
|
public void applyComponentOrientation(ComponentOrientation o) {
|
||||||
@@ -98,8 +97,7 @@ class SizeGrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Paints this panel.
|
* Paints this panel.
|
||||||
*
|
*
|
||||||
* @param g
|
* @param g The graphics context.
|
||||||
* The graphics context.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
@@ -152,8 +150,7 @@ class SizeGrip extends JPanel {
|
|||||||
* Ensures that the cursor for this component is appropriate for the
|
* Ensures that the cursor for this component is appropriate for the
|
||||||
* orientation.
|
* orientation.
|
||||||
*
|
*
|
||||||
* @param ltr
|
* @param ltr Whether the current component orientation is LTR.
|
||||||
* Whether the current component orientation is LTR.
|
|
||||||
*/
|
*/
|
||||||
protected void possiblyFixCursor(boolean ltr) {
|
protected void possiblyFixCursor(boolean ltr) {
|
||||||
int cursor = Cursor.NE_RESIZE_CURSOR;
|
int cursor = Cursor.NE_RESIZE_CURSOR;
|
||||||
@@ -184,10 +181,10 @@ class SizeGrip extends JPanel {
|
|||||||
* appropriately.
|
* appropriately.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* NOTE: We use SwingUtilities.convertPointToScreen() instead of just using
|
* NOTE: We use SwingUtilities.convertPointToScreen() instead of just using the
|
||||||
* the locations relative to the corner component because the latter proved
|
* locations relative to the corner component because the latter proved buggy -
|
||||||
* buggy - stretch the window too wide and some kind of arithmetic error
|
* stretch the window too wide and some kind of arithmetic error started
|
||||||
* started happening somewhere - our window would grow way too large.
|
* happening somewhere - our window would grow way too large.
|
||||||
*/
|
*/
|
||||||
private class MouseHandler extends MouseInputAdapter {
|
private class MouseHandler extends MouseInputAdapter {
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ package org.fife.ui.autocomplete;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two <code>Completion</code>s by their relevance before
|
* Compares two <code>Completion</code>s by their relevance before sorting them
|
||||||
* sorting them lexicographically.
|
* lexicographically.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* In the above example, the first <code>${i}</code> is a parameter for the
|
* In the above example, the first <code>${i}</code> is a parameter for the user
|
||||||
* user to type into; all the other <code>${i}</code> instances are
|
* to type into; all the other <code>${i}</code> instances are automatically
|
||||||
* automatically changed to what the user types in the first one. The parameter
|
* changed to what the user types in the first one. The parameter named
|
||||||
* named <code>${cursor}</code> is the "ending position" of the template. It's
|
* <code>${cursor}</code> is the "ending position" of the template. It's where
|
||||||
* where the caret moves after it cycles through all other parameters. If the
|
* the caret moves after it cycles through all other parameters. If the user
|
||||||
* user types into it, template mode terminates. If more than one
|
* types into it, template mode terminates. If more than one
|
||||||
* <code>${cursor}</code> parameter is specified, behavior is undefined.
|
* <code>${cursor}</code> parameter is specified, behavior is undefined.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
@@ -51,8 +51,8 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
|
|||||||
* fault-tolerant.
|
* fault-tolerant.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Leading whitespace is automatically added to lines if the template spans
|
* Leading whitespace is automatically added to lines if the template spans more
|
||||||
* more than one line, and if used with a text component using a
|
* than one line, and if used with a text component using a
|
||||||
* <code>PlainDocument</code>, tabs will be converted to spaces if requested.
|
* <code>PlainDocument</code>, tabs will be converted to spaces if requested.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
@@ -110,8 +110,8 @@ public class TemplateCompletion extends AbstractCompletion implements Parameteri
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>null</code>; template completions insert all of their
|
* Returns <code>null</code>; template completions insert all of their text via
|
||||||
* text via <code>getInsertionInfo()</code>.
|
* <code>getInsertionInfo()</code>.
|
||||||
*
|
*
|
||||||
* @return <code>null</code> always.
|
* @return <code>null</code> always.
|
||||||
*/
|
*/
|
||||||
@@ -234,8 +234,7 @@ public class TemplateCompletion extends AbstractCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Returns whether a parameter is already defined with a specific name.
|
* Returns whether a parameter is already defined with a specific name.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name The name.
|
||||||
* The name.
|
|
||||||
* @return Whether a parameter is defined with that name.
|
* @return Whether a parameter is defined with that name.
|
||||||
*/
|
*/
|
||||||
private boolean isParamDefined(String name) {
|
private boolean isParamDefined(String name) {
|
||||||
@@ -251,8 +250,7 @@ public class TemplateCompletion extends AbstractCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Parses a template string into logical pieces used by this class.
|
* Parses a template string into logical pieces used by this class.
|
||||||
*
|
*
|
||||||
* @param template
|
* @param template The template to parse.
|
||||||
* The template to parse.
|
|
||||||
*/
|
*/
|
||||||
private void parse(String template) {
|
private void parse(String template) {
|
||||||
int offs = 0;
|
int offs = 0;
|
||||||
@@ -319,8 +317,7 @@ public class TemplateCompletion extends AbstractCompletion implements Parameteri
|
|||||||
/**
|
/**
|
||||||
* Sets the short description of this template completion.
|
* Sets the short description of this template completion.
|
||||||
*
|
*
|
||||||
* @param shortDesc
|
* @param shortDesc The new short description.
|
||||||
* The new short description.
|
|
||||||
* @see #getShortDescription()
|
* @see #getShortDescription()
|
||||||
*/
|
*/
|
||||||
public void setShortDescription(String shortDesc) {
|
public void setShortDescription(String shortDesc) {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
package org.fife.ui.autocomplete;
|
package org.fife.ui.autocomplete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A piece of a <code>TemplateCompletion</code>. You add instances of this
|
* A piece of a <code>TemplateCompletion</code>. You add instances of this class
|
||||||
* class to template completions to define them.
|
* to template completions to define them.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
|
|||||||
@@ -22,16 +22,17 @@ import javax.swing.text.html.HTMLDocument;
|
|||||||
* Static utility methods for homemade tool tips.
|
* Static utility methods for homemade tool tips.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This is blatantly ripped off from RSyntaxTextArea's "FocusableTips" class
|
* This is blatantly ripped off from RSyntaxTextArea's "FocusableTips" class of
|
||||||
* of the same name, but isn't re-used to prevent a hard dependency on the
|
* the same name, but isn't re-used to prevent a hard dependency on the RSTA
|
||||||
* RSTA library.
|
* library.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
class TipUtil {
|
class TipUtil {
|
||||||
|
|
||||||
private TipUtil() {}
|
private TipUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default background color to use for tool tip windows.
|
* Returns the default background color to use for tool tip windows.
|
||||||
@@ -73,17 +74,16 @@ class TipUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a color is a Nimbus DerivedColor, which is troublesome
|
* Returns whether a color is a Nimbus DerivedColor, which is troublesome in
|
||||||
* in that it doesn't use its RGB values (uses HSB instead?) and so
|
* that it doesn't use its RGB values (uses HSB instead?) and so querying them
|
||||||
* querying them is useless.
|
* is useless.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c The color to check.
|
||||||
* The color to check.
|
|
||||||
* @return Whether it is a DerivedColor
|
* @return Whether it is a DerivedColor
|
||||||
*/
|
*/
|
||||||
private static final boolean isDerivedColor(Color c) {
|
private static final boolean isDerivedColor(Color c) {
|
||||||
return c != null
|
return c != null && (c.getClass().getName().endsWith(".DerivedColor")
|
||||||
&& (c.getClass().getName().endsWith(".DerivedColor") || c.getClass().getName().endsWith(".DerivedColor$UIResource"));
|
|| c.getClass().getName().endsWith(".DerivedColor$UIResource"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,12 +96,11 @@ class TipUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tweaks a <code>JEditorPane</code> so it can be used to render the
|
* Tweaks a <code>JEditorPane</code> so it can be used to render the content in
|
||||||
* content in a focusable pseudo-tool tip. It is assumed that the editor
|
* a focusable pseudo-tool tip. It is assumed that the editor pane is using an
|
||||||
* pane is using an <code>HTMLDocument</code>.
|
* <code>HTMLDocument</code>.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The editor pane to tweak.
|
||||||
* The editor pane to tweak.
|
|
||||||
*/
|
*/
|
||||||
public static void tweakTipEditorPane(JEditorPane textArea) {
|
public static void tweakTipEditorPane(JEditorPane textArea) {
|
||||||
// Jump through a few hoops to get things looking nice in Nimbus
|
// Jump through a few hoops to get things looking nice in Nimbus
|
||||||
@@ -134,8 +133,8 @@ class TipUtil {
|
|||||||
font = new Font("SansSerif", Font.PLAIN, 12);
|
font = new Font("SansSerif", Font.PLAIN, 12);
|
||||||
}
|
}
|
||||||
HTMLDocument doc = (HTMLDocument) textArea.getDocument();
|
HTMLDocument doc = (HTMLDocument) textArea.getDocument();
|
||||||
doc.getStyleSheet().addRule("body { font-family: " + font.getFamily() + "; font-size: " + font.getSize() + "pt" + "; color: "
|
doc.getStyleSheet().addRule("body { font-family: " + font.getFamily() + "; font-size: " + font.getSize() + "pt"
|
||||||
+ Util.getHexString(fg) + "; }");
|
+ "; color: " + Util.getHexString(fg) + "; }");
|
||||||
// Always add link foreground rule. Unfortunately these CSS rules
|
// Always add link foreground rule. Unfortunately these CSS rules
|
||||||
// stack each time the LaF is changed (how can we overwrite them
|
// stack each time the LaF is changed (how can we overwrite them
|
||||||
// without clearing out the important "standard" ones?).
|
// without clearing out the important "standard" ones?).
|
||||||
|
|||||||
@@ -30,29 +30,29 @@ import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
|
|||||||
public class Util {
|
public class Util {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a system property is defined with this name and set, ignoring case,
|
* If a system property is defined with this name and set, ignoring case, to
|
||||||
* to <code>true</code>, this library will not attempt to use Substance
|
* <code>true</code>, this library will not attempt to use Substance renderers.
|
||||||
* renderers. Otherwise, if a Substance Look and Feel is installed, we
|
* Otherwise, if a Substance Look and Feel is installed, we will attempt to use
|
||||||
* will attempt to use Substance cell renderers in all of our dropdowns.
|
* Substance cell renderers in all of our dropdowns.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Note that we do not have a build dependency on Substance, so all access
|
* Note that we do not have a build dependency on Substance, so all access to
|
||||||
* to Substance stuff is done via reflection. We will fall back onto
|
* Substance stuff is done via reflection. We will fall back onto default
|
||||||
* default renderers if something goes horribly wrong.
|
* renderers if something goes horribly wrong.
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_DONT_USE_SUBSTANCE_RENDERERS = "org.fife.ui.autocomplete.DontUseSubstanceRenderers";
|
public static final String PROPERTY_DONT_USE_SUBSTANCE_RENDERERS = "org.fife.ui.autocomplete.DontUseSubstanceRenderers";
|
||||||
/**
|
/**
|
||||||
* If this system property is <code>true</code>, then even the "main" two
|
* If this system property is <code>true</code>, then even the "main" two
|
||||||
* auto-complete windows will allow window decorations via
|
* auto-complete windows will allow window decorations via
|
||||||
* {@link PopupWindowDecorator}. If this property is undefined or
|
* {@link PopupWindowDecorator}. If this property is undefined or
|
||||||
* <code>false</code>, they won't honor such decorations. This is due to
|
* <code>false</code>, they won't honor such decorations. This is due to certain
|
||||||
* certain performance issues with translucent windows (used for drop
|
* performance issues with translucent windows (used for drop shadows), even as
|
||||||
* shadows), even as of Java 7u2.
|
* of Java 7u2.
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS = "org.fife.ui.autocomplete.allowDecoratedAutoCompleteWindows";
|
public static final String PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS = "org.fife.ui.autocomplete.allowDecoratedAutoCompleteWindows";
|
||||||
/**
|
/**
|
||||||
* Used for the color of hyperlinks when a LookAndFeel uses light text
|
* Used for the color of hyperlinks when a LookAndFeel uses light text against a
|
||||||
* against a dark background.
|
* dark background.
|
||||||
*/
|
*/
|
||||||
private static final Color LIGHT_HYPERLINK_FG = new Color(0xd8ffff);
|
private static final Color LIGHT_HYPERLINK_FG = new Color(0xd8ffff);
|
||||||
private static final Pattern TAG_PATTERN = Pattern.compile("<[^>]*>");
|
private static final Pattern TAG_PATTERN = Pattern.compile("<[^>]*>");
|
||||||
@@ -64,11 +64,10 @@ public class Util {
|
|||||||
/**
|
/**
|
||||||
* Attempts to open a web browser to the specified URI.
|
* Attempts to open a web browser to the specified URI.
|
||||||
*
|
*
|
||||||
* @param uri
|
* @param uri The URI to open. If this is <code>null</code>, nothing happens and
|
||||||
* The URI to open. If this is <code>null</code>, nothing
|
* this method returns <code>false</code>.
|
||||||
* happens and this method returns <code>false</code>.
|
* @return Whether the operation was successful. This will be <code>false</code>
|
||||||
* @return Whether the operation was successful. This will be
|
* on JRE's older than 1.6.
|
||||||
* <code>false</code> on JRE's older than 1.6.
|
|
||||||
*/
|
*/
|
||||||
public static boolean browse(URI uri) {
|
public static boolean browse(URI uri) {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
@@ -91,8 +90,8 @@ public class Util {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the singleton <code>java.awt.Desktop</code> instance, or
|
* Returns the singleton <code>java.awt.Desktop</code> instance, or
|
||||||
* <code>null</code> if it is unsupported on this platform (or the JRE
|
* <code>null</code> if it is unsupported on this platform (or the JRE is older
|
||||||
* is older than 1.6).
|
* than 1.6).
|
||||||
*
|
*
|
||||||
* @return The desktop, as an {@link Object}.
|
* @return The desktop, as an {@link Object}.
|
||||||
*/
|
*/
|
||||||
@@ -121,10 +120,9 @@ public class Util {
|
|||||||
/**
|
/**
|
||||||
* Returns a hex string for the specified color, suitable for HTML.
|
* Returns a hex string for the specified color, suitable for HTML.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c The color.
|
||||||
* The color.
|
* @return The string representation, in the form "<code>#rrggbb</code>", or
|
||||||
* @return The string representation, in the form "<code>#rrggbb</code>",
|
* <code>null</code> if <code>c</code> is <code>null</code>.
|
||||||
* or <code>null</code> if <code>c</code> is <code>null</code>.
|
|
||||||
*/
|
*/
|
||||||
public static String getHexString(Color c) {
|
public static String getHexString(Color c) {
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
@@ -152,10 +150,10 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color to use for hyperlink-style components. This method
|
* Returns the color to use for hyperlink-style components. This method will
|
||||||
* will return <code>Color.blue</code> unless it appears that the current
|
* return <code>Color.blue</code> unless it appears that the current LookAndFeel
|
||||||
* LookAndFeel uses light text on a dark background, in which case a
|
* uses light text on a dark background, in which case a brighter alternative is
|
||||||
* brighter alternative is returned.
|
* returned.
|
||||||
*
|
*
|
||||||
* @return The color to use for hyperlinks.
|
* @return The color to use for hyperlinks.
|
||||||
*/
|
*/
|
||||||
@@ -170,14 +168,12 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the screen coordinates for the monitor that contains the
|
* Returns the screen coordinates for the monitor that contains the specified
|
||||||
* specified point. This is useful for setups with multiple monitors,
|
* point. This is useful for setups with multiple monitors, to ensure that popup
|
||||||
* to ensure that popup windows are positioned properly.
|
* windows are positioned properly.
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x The x-coordinate, in screen coordinates.
|
||||||
* The x-coordinate, in screen coordinates.
|
* @param y The y-coordinate, in screen coordinates.
|
||||||
* @param y
|
|
||||||
* The y-coordinate, in screen coordinates.
|
|
||||||
* @return The bounds of the monitor that contains the specified point.
|
* @return The bounds of the monitor that contains the specified point.
|
||||||
*/
|
*/
|
||||||
public static Rectangle getScreenBoundsForPoint(int x, int y) {
|
public static Rectangle getScreenBoundsForPoint(int x, int y) {
|
||||||
@@ -195,10 +191,10 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give apps a chance to decorate us with drop shadows, etc. Since very
|
* Give apps a chance to decorate us with drop shadows, etc. Since very scrolly
|
||||||
* scrolly things such as lists (of e.g. completions) are *very* slow when
|
* things such as lists (of e.g. completions) are *very* slow when in per-pixel
|
||||||
* in per-pixel translucent windows, even as of Java 7u2, we force the user
|
* translucent windows, even as of Java 7u2, we force the user to specify an
|
||||||
* to specify an extra option for the two "main" auto-complete windows.
|
* extra option for the two "main" auto-complete windows.
|
||||||
*
|
*
|
||||||
* @return Whether to allow decorating the main auto-complete windows.
|
* @return Whether to allow decorating the main auto-complete windows.
|
||||||
* @see #PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS
|
* @see #PROPERTY_ALLOW_DECORATED_AUTOCOMPLETE_WINDOWS
|
||||||
@@ -212,10 +208,10 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether we should attempt to use Substance cell renderers and
|
* Returns whether we should attempt to use Substance cell renderers and styles
|
||||||
* styles for things such as completion choices, if a Substance Look and
|
* for things such as completion choices, if a Substance Look and Feel is
|
||||||
* Feel is installed. If this is <code>false</code>, we'll use our
|
* installed. If this is <code>false</code>, we'll use our standard rendering
|
||||||
* standard rendering for completions, even when Substance is being used.
|
* for completions, even when Substance is being used.
|
||||||
*
|
*
|
||||||
* @return Whether to use Substance renderers if Substance is installed.
|
* @return Whether to use Substance renderers if Substance is installed.
|
||||||
*/
|
*/
|
||||||
@@ -224,12 +220,11 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the specified color is "light" to use as a foreground.
|
* Returns whether the specified color is "light" to use as a foreground. Colors
|
||||||
* Colors that return <code>true</code> indicate that the current Look and
|
* that return <code>true</code> indicate that the current Look and Feel
|
||||||
* Feel probably uses light text colors on a dark background.
|
* probably uses light text colors on a dark background.
|
||||||
*
|
*
|
||||||
* @param fg
|
* @param fg The foreground color.
|
||||||
* The foreground color.
|
|
||||||
* @return Whether it is a "light" foreground color.
|
* @return Whether it is a "light" foreground color.
|
||||||
*/
|
*/
|
||||||
public static final boolean isLightForeground(Color fg) {
|
public static final boolean isLightForeground(Color fg) {
|
||||||
@@ -237,13 +232,11 @@ public class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a string starts with a specified prefix, ignoring case.
|
* Returns whether a string starts with a specified prefix, ignoring case. This
|
||||||
* This method does not support characters outside of the BMP.
|
* method does not support characters outside of the BMP.
|
||||||
*
|
*
|
||||||
* @param str
|
* @param str The string to check. This cannot be {@code null}.
|
||||||
* The string to check. This cannot be {@code null}.
|
* @param prefix The prefix to check for. This cannot be {@code null}.
|
||||||
* @param prefix
|
|
||||||
* The prefix to check for. This cannot be {@code null}.
|
|
||||||
* @return Whether {@code str} starts with {@code prefix}, ignoring case.
|
* @return Whether {@code str} starts with {@code prefix}, ignoring case.
|
||||||
*/
|
*/
|
||||||
public static boolean startsWithIgnoreCase(String str, String prefix) {
|
public static boolean startsWithIgnoreCase(String str, String prefix) {
|
||||||
@@ -258,8 +251,7 @@ public class Util {
|
|||||||
* Strips any HTML from a string. The string must start with
|
* Strips any HTML from a string. The string must start with
|
||||||
* "<code><html></code>" for markup tags to be stripped.
|
* "<code><html></code>" for markup tags to be stripped.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param text The string.
|
||||||
* The string.
|
|
||||||
* @return The string, with any HTML stripped.
|
* @return The string, with any HTML stripped.
|
||||||
*/
|
*/
|
||||||
public static String stripHtml(String text) {
|
public static String stripHtml(String text) {
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import javax.swing.text.JTextComponent;
|
|||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This completion type uses its <tt>shortDescription</tt> property as part of
|
* This completion type uses its <tt>shortDescription</tt> property as part of
|
||||||
* its summary returned by {@link #getSummary()}; for this reason, it may be
|
* its summary returned by {@link #getSummary()}; for this reason, it may be a
|
||||||
* a little longer (even much longer), if desired, than what is recommended
|
* little longer (even much longer), if desired, than what is recommended for
|
||||||
* for <tt>BasicCompletion</tt>s (where the <tt>shortDescription</tt> is used
|
* <tt>BasicCompletion</tt>s (where the <tt>shortDescription</tt> is used in
|
||||||
* in {@link #toString()} for <tt>ListCellRenderers</tt>).
|
* {@link #toString()} for <tt>ListCellRenderers</tt>).
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -35,12 +35,9 @@ public class VariableCompletion extends BasicCompletion {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The parent provider.
|
||||||
* The parent provider.
|
* @param name The name of this variable.
|
||||||
* @param name
|
* @param type The type of this variable (e.g. "<code>int</code>",
|
||||||
* The name of this variable.
|
|
||||||
* @param type
|
|
||||||
* The type of this variable (e.g. "<code>int</code>",
|
|
||||||
* "<code>String</code>", etc.).
|
* "<code>String</code>", etc.).
|
||||||
*/
|
*/
|
||||||
public VariableCompletion(CompletionProvider provider, String name, String type) {
|
public VariableCompletion(CompletionProvider provider, String name, String type) {
|
||||||
@@ -95,21 +92,17 @@ public class VariableCompletion extends BasicCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tool tip text to display for mouse hovers over this
|
* Returns the tool tip text to display for mouse hovers over this completion.
|
||||||
* completion.
|
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Note that for this functionality to be enabled, a
|
* Note that for this functionality to be enabled, a <tt>JTextComponent</tt>
|
||||||
* <tt>JTextComponent</tt> must be registered with the
|
* must be registered with the <tt>ToolTipManager</tt>, and the text component
|
||||||
* <tt>ToolTipManager</tt>, and the text component must know to search
|
* must know to search for this value. In the case of an
|
||||||
* for this value. In the case of an
|
* <a href="http://fifesoft.com/rsyntaxtextarea">RSyntaxTextArea</a>, this can
|
||||||
* <a href="http://fifesoft.com/rsyntaxtextarea">RSyntaxTextArea</a>, this
|
* be done with a <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> that calls into
|
||||||
* can be done with a <tt>org.fife.ui.rtextarea.ToolTipSupplier</tt> that
|
|
||||||
* calls into
|
|
||||||
* {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}.
|
* {@link CompletionProvider#getCompletionsAt(JTextComponent, java.awt.Point)}.
|
||||||
*
|
*
|
||||||
* @return The tool tip text for this completion, or <code>null</code> if
|
* @return The tool tip text for this completion, or <code>null</code> if none.
|
||||||
* none.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getToolTipText() {
|
public String getToolTipText() {
|
||||||
@@ -126,11 +119,10 @@ public class VariableCompletion extends BasicCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds some HTML describing where this variable is defined, if this
|
* Adds some HTML describing where this variable is defined, if this information
|
||||||
* information is known.
|
* is known.
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
*/
|
*/
|
||||||
protected void possiblyAddDefinedIn(StringBuilder sb) {
|
protected void possiblyAddDefinedIn(StringBuilder sb) {
|
||||||
if (definedIn != null) {
|
if (definedIn != null) {
|
||||||
@@ -140,11 +132,9 @@ public class VariableCompletion extends BasicCompletion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the description text as HTML to a buffer, if a description is
|
* Adds the description text as HTML to a buffer, if a description is defined.
|
||||||
* defined.
|
|
||||||
*
|
*
|
||||||
* @param sb
|
* @param sb The buffer to append to.
|
||||||
* The buffer to append to.
|
|
||||||
* @return Whether there was a description to add.
|
* @return Whether there was a description to add.
|
||||||
*/
|
*/
|
||||||
protected boolean possiblyAddDescription(StringBuilder sb) {
|
protected boolean possiblyAddDescription(StringBuilder sb) {
|
||||||
@@ -160,8 +150,7 @@ public class VariableCompletion extends BasicCompletion {
|
|||||||
/**
|
/**
|
||||||
* Sets where this variable is defined.
|
* Sets where this variable is defined.
|
||||||
*
|
*
|
||||||
* @param definedIn
|
* @param definedIn Where this variable is defined.
|
||||||
* Where this variable is defined.
|
|
||||||
* @see #getDefinedIn()
|
* @see #getDefinedIn()
|
||||||
*/
|
*/
|
||||||
public void setDefinedIn(String definedIn) {
|
public void setDefinedIn(String definedIn) {
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns the action to use when the user inserts a newline.
|
* Creates and returns the action to use when the user inserts a newline. The
|
||||||
* The default implementation intelligently closes multi-line comments.
|
* default implementation intelligently closes multi-line comments. Subclasses
|
||||||
* Subclasses can override.
|
* can override.
|
||||||
*
|
*
|
||||||
* @return The action.
|
* @return The action.
|
||||||
* @see #getInsertBreakAction()
|
* @see #getInsertBreakAction()
|
||||||
@@ -51,8 +51,8 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> always as C-style languages use curly braces
|
* Returns <code>true</code> always as C-style languages use curly braces to
|
||||||
* to denote code blocks.
|
* denote code blocks.
|
||||||
*
|
*
|
||||||
* @return <code>true</code> always.
|
* @return <code>true</code> always.
|
||||||
*/
|
*/
|
||||||
@@ -62,9 +62,8 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an action to handle "insert break" key presses (i.e. Enter).
|
* Returns an action to handle "insert break" key presses (i.e. Enter). An
|
||||||
* An action is returned that handles newlines differently in multi-line
|
* action is returned that handles newlines differently in multi-line comments.
|
||||||
* comments.
|
|
||||||
*
|
*
|
||||||
* @return The action.
|
* @return The action.
|
||||||
*/
|
*/
|
||||||
@@ -94,17 +93,15 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a given token is an internal token type that represents
|
* Returns whether a given token is an internal token type that represents an
|
||||||
* an MLC or documentation comment continuing on to the next line. This is
|
* MLC or documentation comment continuing on to the next line. This is done by
|
||||||
* done by languages such as JavaScript that are a little more verbose
|
* languages such as JavaScript that are a little more verbose than necessary so
|
||||||
* than necessary so that their code can be copy-and-pasted into other
|
* that their code can be copy-and-pasted into other <code>TokenMaker</code>s
|
||||||
* <code>TokenMaker</code>s that use them as nested languages (such as
|
* that use them as nested languages (such as HTML, JSP, etc.).
|
||||||
* HTML, JSP, etc.).
|
|
||||||
*
|
*
|
||||||
* @param t
|
* @param t The token to check. This cannot be <code>null</code>.
|
||||||
* The token to check. This cannot be <code>null</code>.
|
* @return Whether the token is an internal token representing the end of a line
|
||||||
* @return Whether the token is an internal token representing the end of
|
* for an MLC/doc comment continuing on to the next line.
|
||||||
* a line for an MLC/doc comment continuing on to the next line.
|
|
||||||
*/
|
*/
|
||||||
private boolean isInternalEolTokenForMLCs(Token t) {
|
private boolean isInternalEolTokenForMLCs(Token t) {
|
||||||
int type = t.getType();
|
int type = t.getType();
|
||||||
@@ -116,8 +113,8 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that knows how to special-case inserting a newline in a
|
* Action that knows how to special-case inserting a newline in a multi-line
|
||||||
* multi-line comment for languages like C and Java.
|
* comment for languages like C and Java.
|
||||||
*/
|
*/
|
||||||
protected class CStyleInsertBreakAction extends RSyntaxTextAreaEditorKit.InsertBreakAction {
|
protected class CStyleInsertBreakAction extends RSyntaxTextAreaEditorKit.InsertBreakAction {
|
||||||
|
|
||||||
@@ -143,11 +140,10 @@ public abstract class AbstractJFlexCTokenMaker extends AbstractJFlexTokenMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the MLC token containing <code>offs</code> appears
|
* Returns whether the MLC token containing <code>offs</code> appears to have a
|
||||||
* to have a "nested" comment (i.e., contains "<code>/*</code>"
|
* "nested" comment (i.e., contains "<code>/*</code>" somewhere inside of it).
|
||||||
* somewhere inside of it). This implies that it is likely a "new" MLC
|
* This implies that it is likely a "new" MLC and needs to be closed. While not
|
||||||
* and needs to be closed. While not foolproof, this is usually good
|
* foolproof, this is usually good enough of a sign.
|
||||||
* enough of a sign.
|
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea
|
||||||
* @param line
|
* @param line
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import javax.swing.text.Segment;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for JFlex-generated token makers. This class attempts to factor
|
* Base class for JFlex-generated token makers. This class attempts to factor
|
||||||
* out all common code from these classes. Many methods <em>almost</em> could
|
* out all common code from these classes. Many methods <em>almost</em> could be
|
||||||
* be factored out into this class, but cannot because they reference JFlex
|
* factored out into this class, but cannot because they reference JFlex
|
||||||
* variables that we cannot access from this class.
|
* variables that we cannot access from this class.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
@@ -28,18 +28,15 @@ public abstract class AbstractJFlexTokenMaker extends TokenMakerBase {
|
|||||||
/**
|
/**
|
||||||
* Declared here so we can define overloads that refer to this method.
|
* Declared here so we can define overloads that refer to this method.
|
||||||
*
|
*
|
||||||
* @param newState
|
* @param newState The new JFlex state to enter.
|
||||||
* The new JFlex state to enter.
|
|
||||||
*/
|
*/
|
||||||
public abstract void yybegin(int newState);
|
public abstract void yybegin(int newState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a new JFlex state and changes the current language index.
|
* Starts a new JFlex state and changes the current language index.
|
||||||
*
|
*
|
||||||
* @param state
|
* @param state The new JFlex state to enter.
|
||||||
* The new JFlex state to enter.
|
* @param languageIndex The new language index.
|
||||||
* @param languageIndex
|
|
||||||
* The new language index.
|
|
||||||
*/
|
*/
|
||||||
protected void yybegin(int state, int languageIndex) {
|
protected void yybegin(int state, int languageIndex) {
|
||||||
yybegin(state);
|
yybegin(state);
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ package org.fife.ui.rsyntaxtextarea;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract implementation of the
|
* An abstract implementation of the
|
||||||
* {@link org.fife.ui.rsyntaxtextarea.TokenMaker} interface. It should
|
* {@link org.fife.ui.rsyntaxtextarea.TokenMaker} interface. It should be
|
||||||
* be overridden for every language for which you want to provide
|
* overridden for every language for which you want to provide syntax
|
||||||
* syntax highlighting.
|
* highlighting.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @see Token
|
* @see Token
|
||||||
@@ -21,10 +21,9 @@ package org.fife.ui.rsyntaxtextarea;
|
|||||||
public abstract class AbstractTokenMaker extends TokenMakerBase {
|
public abstract class AbstractTokenMaker extends TokenMakerBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash table of words to highlight and what token type they are.
|
* Hash table of words to highlight and what token type they are. The keys are
|
||||||
* The keys are the words to highlight, and their values are the
|
* the words to highlight, and their values are the token types, for example,
|
||||||
* token types, for example, <code>Token.RESERVED_WORD</code> or
|
* <code>Token.RESERVED_WORD</code> or <code>Token.FUNCTION</code>.
|
||||||
* <code>Token.FUNCTION</code>.
|
|
||||||
*/
|
*/
|
||||||
protected TokenMap wordsToHighlight;
|
protected TokenMap wordsToHighlight;
|
||||||
|
|
||||||
@@ -38,15 +37,15 @@ public abstract class AbstractTokenMaker extends TokenMakerBase {
|
|||||||
/**
|
/**
|
||||||
* Returns the words to highlight for this programming language.
|
* Returns the words to highlight for this programming language.
|
||||||
*
|
*
|
||||||
* @return A <code>TokenMap</code> containing the words to highlight for
|
* @return A <code>TokenMap</code> containing the words to highlight for this
|
||||||
* this programming language.
|
* programming language.
|
||||||
*/
|
*/
|
||||||
public abstract TokenMap getWordsToHighlight();
|
public abstract TokenMap getWordsToHighlight();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the token last added from the linked list of tokens. The
|
* Removes the token last added from the linked list of tokens. The programmer
|
||||||
* programmer should never have to call this directly; it can be called
|
* should never have to call this directly; it can be called by subclasses of
|
||||||
* by subclasses of <code>TokenMaker</code> if necessary.
|
* <code>TokenMaker</code> if necessary.
|
||||||
*/
|
*/
|
||||||
public void removeLastToken() {
|
public void removeLastToken() {
|
||||||
if (previousToken == null) {
|
if (previousToken == null) {
|
||||||
|
|||||||
@@ -20,10 +20,9 @@ import java.util.Set;
|
|||||||
public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping from keys to the names of {@link TokenMaker} implementation
|
* A mapping from keys to the names of {@link TokenMaker} implementation class
|
||||||
* class names. When {@link #getTokenMaker(String)} is called with a key
|
* names. When {@link #getTokenMaker(String)} is called with a key defined in
|
||||||
* defined in this map, a <code>TokenMaker</code> of the corresponding type
|
* this map, a <code>TokenMaker</code> of the corresponding type is returned.
|
||||||
* is returned.
|
|
||||||
*/
|
*/
|
||||||
private Map<String, Object> tokenMakerMap;
|
private Map<String, Object> tokenMakerMap;
|
||||||
|
|
||||||
@@ -38,10 +37,9 @@ public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
|||||||
/**
|
/**
|
||||||
* Returns a {@link TokenMaker} for the specified key.
|
* Returns a {@link TokenMaker} for the specified key.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key The key.
|
||||||
* The key.
|
* @return The corresponding <code>TokenMaker</code>, or <code>null</code> if
|
||||||
* @return The corresponding <code>TokenMaker</code>, or <code>null</code>
|
* none matches the specified key.
|
||||||
* if none matches the specified key.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected TokenMaker getTokenMakerImpl(String key) {
|
protected TokenMaker getTokenMakerImpl(String key) {
|
||||||
@@ -60,8 +58,8 @@ public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the mapping from keys to instances of
|
* Populates the mapping from keys to instances of
|
||||||
* <code>TokenMakerCreator</code>s. Subclasses should override this method
|
* <code>TokenMakerCreator</code>s. Subclasses should override this method and
|
||||||
* and call one of the <code>putMapping</code> overloads to register
|
* call one of the <code>putMapping</code> overloads to register
|
||||||
* {@link TokenMaker}s for syntax constants.
|
* {@link TokenMaker}s for syntax constants.
|
||||||
*
|
*
|
||||||
* @see #putMapping(String, String)
|
* @see #putMapping(String, String)
|
||||||
@@ -78,13 +76,11 @@ public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a mapping from a key to a <code>TokenMaker</code> implementation
|
* Adds a mapping from a key to a <code>TokenMaker</code> implementation class
|
||||||
* class name.
|
* name.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key The key.
|
||||||
* The key.
|
* @param className The <code>TokenMaker</code> class name.
|
||||||
* @param className
|
|
||||||
* The <code>TokenMaker</code> class name.
|
|
||||||
* @see #putMapping(String, String, ClassLoader)
|
* @see #putMapping(String, String, ClassLoader)
|
||||||
*/
|
*/
|
||||||
public void putMapping(String key, String className) {
|
public void putMapping(String key, String className) {
|
||||||
@@ -92,15 +88,12 @@ public abstract class AbstractTokenMakerFactory extends TokenMakerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a mapping from a key to a <code>TokenMaker</code> implementation
|
* Adds a mapping from a key to a <code>TokenMaker</code> implementation class
|
||||||
* class name.
|
* name.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key The key.
|
||||||
* The key.
|
* @param className The <code>TokenMaker</code> class name.
|
||||||
* @param className
|
* @param cl The class loader to use when loading the class.
|
||||||
* The <code>TokenMaker</code> class name.
|
|
||||||
* @param cl
|
|
||||||
* The class loader to use when loading the class.
|
|
||||||
* @see #putMapping(String, String)
|
* @see #putMapping(String, String)
|
||||||
*/
|
*/
|
||||||
public void putMapping(String key, String className, ClassLoader cl) {
|
public void putMapping(String key, String className, ClassLoader cl) {
|
||||||
|
|||||||
@@ -24,14 +24,11 @@ public class ActiveLineRangeEvent extends EventObject {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param source
|
* @param source The text area.
|
||||||
* The text area.
|
* @param min The first line in the active line range, or <code>-1</code> if
|
||||||
* @param min
|
* the line range is being cleared.
|
||||||
* The first line in the active line range, or
|
* @param max The last line in the active line range, or <code>-1</code> if
|
||||||
* <code>-1</code> if the line range is being cleared.
|
* the line range is being cleared.
|
||||||
* @param max
|
|
||||||
* The last line in the active line range, or
|
|
||||||
* <code>-1</code> if the line range is being cleared.
|
|
||||||
*/
|
*/
|
||||||
public ActiveLineRangeEvent(RSyntaxTextArea source, int min, int max) {
|
public ActiveLineRangeEvent(RSyntaxTextArea source, int min, int max) {
|
||||||
super(source);
|
super(source);
|
||||||
@@ -42,8 +39,7 @@ public class ActiveLineRangeEvent extends EventObject {
|
|||||||
/**
|
/**
|
||||||
* Returns the last line in the active line range.
|
* Returns the last line in the active line range.
|
||||||
*
|
*
|
||||||
* @return The last line, or <code>-1</code> if the range is being
|
* @return The last line, or <code>-1</code> if the range is being cleared.
|
||||||
* cleared.
|
|
||||||
* @see #getMin()
|
* @see #getMin()
|
||||||
*/
|
*/
|
||||||
public int getMax() {
|
public int getMax() {
|
||||||
@@ -53,8 +49,7 @@ public class ActiveLineRangeEvent extends EventObject {
|
|||||||
/**
|
/**
|
||||||
* Returns the first line in the active line range.
|
* Returns the first line in the active line range.
|
||||||
*
|
*
|
||||||
* @return The first line, or <code>-1</code> if the range is being
|
* @return The first line, or <code>-1</code> if the range is being cleared.
|
||||||
* cleared.
|
|
||||||
* @see #getMax()
|
* @see #getMax()
|
||||||
*/
|
*/
|
||||||
public int getMin() {
|
public int getMin() {
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import java.util.EventListener;
|
|||||||
* Listens for "active line range" events from an <code>RSyntaxTextArea</code>.
|
* Listens for "active line range" events from an <code>RSyntaxTextArea</code>.
|
||||||
* If a text area contains some semantic knowledge of the programming language
|
* If a text area contains some semantic knowledge of the programming language
|
||||||
* being edited, it may broadcast {@link ActiveLineRangeEvent}s whenever the
|
* being edited, it may broadcast {@link ActiveLineRangeEvent}s whenever the
|
||||||
* caret moves into a new "block" of code. Listeners can listen for these
|
* caret moves into a new "block" of code. Listeners can listen for these events
|
||||||
* events and respond accordingly.
|
* and respond accordingly.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* See the <code>RSTALanguageSupport</code> project at
|
* See the <code>RSTALanguageSupport</code> project at
|
||||||
* <a href="http://fifesoft.com">http://fifesoft.com</a> for some
|
* <a href="http://fifesoft.com">http://fifesoft.com</a> for some
|
||||||
* <code>LanguageSupport</code> implementations that may broadcast these
|
* <code>LanguageSupport</code> implementations that may broadcast these events.
|
||||||
* events. Note that if an RSTA/LanguageSupport does not support broadcasting
|
* Note that if an RSTA/LanguageSupport does not support broadcasting these
|
||||||
* these events, the listener will simply never receive any notifications.
|
* events, the listener will simply never receive any notifications.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -31,11 +31,9 @@ public interface ActiveLineRangeListener extends EventListener {
|
|||||||
/**
|
/**
|
||||||
* Called whenever the "active line range" changes.
|
* Called whenever the "active line range" changes.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e Information about the line range change. If there is no longer an
|
||||||
* Information about the line range change. If there is no longer
|
* "active line range," the "minimum" and "maximum" line values should
|
||||||
* an "active line range," the "minimum" and "maximum" line
|
* both be <code>-1</code>.
|
||||||
* values
|
|
||||||
* should both be <code>-1</code>.
|
|
||||||
*/
|
*/
|
||||||
void activeLineRangeChanged(ActiveLineRangeEvent e);
|
void activeLineRangeChanged(ActiveLineRangeEvent e);
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,8 @@ import javax.swing.text.Caret;
|
|||||||
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation of {@link OccurrenceMarker}. It goes through
|
* The default implementation of {@link OccurrenceMarker}. It goes through the
|
||||||
* the document and marks all instances of the specified token.
|
* document and marks all instances of the specified token.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -66,16 +66,13 @@ class DefaultOccurrenceMarker implements OccurrenceMarker {
|
|||||||
* Highlights all instances of tokens identical to <code>t</code> in the
|
* Highlights all instances of tokens identical to <code>t</code> in the
|
||||||
* specified document.
|
* specified document.
|
||||||
*
|
*
|
||||||
* @param doc
|
* @param doc The document.
|
||||||
* The document.
|
* @param t The document whose relevant occurrences should be marked.
|
||||||
* @param t
|
* @param h The highlighter to add the highlights to.
|
||||||
* The document whose relevant occurrences should be marked.
|
* @param p The painter for the highlights.
|
||||||
* @param h
|
|
||||||
* The highlighter to add the highlights to.
|
|
||||||
* @param p
|
|
||||||
* The painter for the highlights.
|
|
||||||
*/
|
*/
|
||||||
public static final void markOccurrencesOfToken(RSyntaxDocument doc, Token t, RSyntaxTextAreaHighlighter h, SmartHighlightPainter p) {
|
public static final void markOccurrencesOfToken(RSyntaxDocument doc, Token t, RSyntaxTextAreaHighlighter h,
|
||||||
|
SmartHighlightPainter p) {
|
||||||
char[] lexeme = t.getLexeme().toCharArray();
|
char[] lexeme = t.getLexeme().toCharArray();
|
||||||
int type = t.getType();
|
int type = t.getType();
|
||||||
int lineCount = doc.getDefaultRootElement().getElementCount();
|
int lineCount = doc.getDefaultRootElement().getElementCount();
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ import javax.swing.text.Segment;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class generates tokens for a {@link TokenMaker}. This class is here
|
* This class generates tokens for a {@link TokenMaker}. This class is here
|
||||||
* because it reuses tokens when they aren't needed anymore to prevent
|
* because it reuses tokens when they aren't needed anymore to prevent This
|
||||||
* This class doesn't actually create new tokens every time
|
* class doesn't actually create new tokens every time <code>createToken</code>
|
||||||
* <code>createToken</code> is called. Instead, it internally keeps a stack of
|
* is called. Instead, it internally keeps a stack of available already-created
|
||||||
* available already-created tokens. When more tokens are needed to properly
|
* tokens. When more tokens are needed to properly display a line, more tokens
|
||||||
* display a line, more tokens are added to the available stack. This saves
|
* are added to the available stack. This saves from needless repetitive memory
|
||||||
* from needless repetitive memory allocation. However, it makes it IMPERATIVE
|
* allocation. However, it makes it IMPERATIVE that users call
|
||||||
* that users call <code>resetTokenList</code> when creating a new token list so
|
* <code>resetTokenList</code> when creating a new token list so that the token
|
||||||
* that the token maker can keep an accurate list of available tokens.
|
* maker can keep an accurate list of available tokens.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* NOTE: This class should only be used by {@link TokenMaker}; nobody else
|
* NOTE: This class should only be used by {@link TokenMaker}; nobody else needs
|
||||||
* needs it!
|
* it!
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 0.1
|
* @version 0.1
|
||||||
@@ -45,11 +45,8 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param size
|
* @param size The initial number of tokens in this factory.
|
||||||
* The initial number of tokens in this factory.
|
* @param increment How many tokens to increment by when the stack gets empty.
|
||||||
* @param increment
|
|
||||||
* How many tokens to increment by when the stack gets
|
|
||||||
* empty.
|
|
||||||
*/
|
*/
|
||||||
DefaultTokenFactory(int size, int increment) {
|
DefaultTokenFactory(int size, int increment) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
@@ -63,8 +60,8 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds tokens to the internal token list. This is called whenever a
|
* Adds tokens to the internal token list. This is called whenever a request is
|
||||||
* request is made and no more tokens are available.
|
* made and no more tokens are available.
|
||||||
*/
|
*/
|
||||||
private void augmentTokenList() {
|
private void augmentTokenList() {
|
||||||
TokenImpl[] temp = new TokenImpl[size + increment];
|
TokenImpl[] temp = new TokenImpl[size + increment];
|
||||||
@@ -83,12 +80,8 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
@Override
|
@Override
|
||||||
public TokenImpl createToken() {
|
public TokenImpl createToken() {
|
||||||
TokenImpl token = tokenList[currentFreeToken];
|
TokenImpl token = tokenList[currentFreeToken];
|
||||||
token.text = null;
|
token.reset();
|
||||||
token.setType(Token.NULL);
|
if (++currentFreeToken == size) {
|
||||||
token.setOffset(-1);
|
|
||||||
token.setNextToken(null);
|
|
||||||
currentFreeToken++;
|
|
||||||
if (currentFreeToken == size) {
|
|
||||||
augmentTokenList();
|
augmentTokenList();
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
@@ -98,7 +91,8 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TokenImpl createToken(final Segment line, final int beg, final int end, final int startOffset, final int type) {
|
public TokenImpl createToken(final Segment line, final int beg, final int end, final int startOffset,
|
||||||
|
final int type) {
|
||||||
return createToken(line.array, beg, end, startOffset, type);
|
return createToken(line.array, beg, end, startOffset, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +100,10 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TokenImpl createToken(final char[] line, final int beg, final int end, final int startOffset, final int type) {
|
public TokenImpl createToken(final char[] line, final int beg, final int end, final int startOffset,
|
||||||
|
final int type) {
|
||||||
|
// if (tokenList.length - 1 > currentFreeToken)
|
||||||
|
// return null;
|
||||||
TokenImpl token = tokenList[currentFreeToken];
|
TokenImpl token = tokenList[currentFreeToken];
|
||||||
token.set(line, beg, end, startOffset, type);
|
token.set(line, beg, end, startOffset, type);
|
||||||
currentFreeToken++;
|
currentFreeToken++;
|
||||||
@@ -117,9 +114,9 @@ class DefaultTokenFactory implements TokenFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the state of this token maker. This method should be called
|
* Resets the state of this token maker. This method should be called by the
|
||||||
* by the <code>TokenMaker</code> every time a token list is generated for
|
* <code>TokenMaker</code> every time a token list is generated for a new line
|
||||||
* a new line so the tokens can be reused.
|
* so the tokens can be reused.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void resetAllTokens() {
|
public void resetAllTokens() {
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
*/
|
*/
|
||||||
private Rectangle2D.Float bgRect;
|
private Rectangle2D.Float bgRect;
|
||||||
/**
|
/**
|
||||||
* Micro-optimization; buffer used to compute tab width. If the width is
|
* Micro-optimization; buffer used to compute tab width. If the width is correct
|
||||||
* correct it's not re-allocated, to prevent lots of very small garbage.
|
* it's not re-allocated, to prevent lots of very small garbage. Only used when
|
||||||
* Only used when painting tab lines.
|
* painting tab lines.
|
||||||
*/
|
*/
|
||||||
private static char[] tabBuf;
|
private static char[] tabBuf;
|
||||||
|
|
||||||
@@ -48,7 +48,8 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float paint(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, float clipStart) {
|
public float paint(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e,
|
||||||
|
float clipStart) {
|
||||||
return paintImpl(token, g, x, y, host, e, clipStart, false, false);
|
return paintImpl(token, g, x, y, host, e, clipStart, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,33 +57,26 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float paint(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, float clipStart, boolean paintBG) {
|
public float paint(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e,
|
||||||
|
float clipStart, boolean paintBG) {
|
||||||
return paintImpl(token, g, x, y, host, e, clipStart, !paintBG, false);
|
return paintImpl(token, g, x, y, host, e, clipStart, !paintBG, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paints the background of a token.
|
* Paints the background of a token.
|
||||||
*
|
*
|
||||||
* @param x
|
* @param x The x-coordinate of the token.
|
||||||
* The x-coordinate of the token.
|
* @param y The y-coordinate of the token.
|
||||||
* @param y
|
* @param width The width of the token (actually, the width of the part of
|
||||||
* The y-coordinate of the token.
|
|
||||||
* @param width
|
|
||||||
* The width of the token (actually, the width of the part of
|
|
||||||
* the token to paint).
|
* the token to paint).
|
||||||
* @param height
|
* @param height The height of the token.
|
||||||
* The height of the token.
|
* @param g The graphics context with which to paint.
|
||||||
* @param g
|
* @param fontAscent The ascent of the token's font.
|
||||||
* The graphics context with which to paint.
|
* @param host The text area.
|
||||||
* @param fontAscent
|
* @param color The color with which to paint.
|
||||||
* The ascent of the token's font.
|
|
||||||
* @param host
|
|
||||||
* The text area.
|
|
||||||
* @param color
|
|
||||||
* The color with which to paint.
|
|
||||||
*/
|
*/
|
||||||
protected void paintBackground(float x, float y, float width, float height, Graphics2D g, int fontAscent, RSyntaxTextArea host,
|
protected void paintBackground(float x, float y, float width, float height, Graphics2D g, int fontAscent,
|
||||||
Color color) {
|
RSyntaxTextArea host, Color color) {
|
||||||
g.setColor(color);
|
g.setColor(color);
|
||||||
bgRect.setRect(x, y - fontAscent, width, height);
|
bgRect.setRect(x, y - fontAscent, width, height);
|
||||||
// g.fill(bgRect);
|
// g.fill(bgRect);
|
||||||
@@ -92,8 +86,8 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
/**
|
/**
|
||||||
* Does the dirty-work of actually painting the token.
|
* Does the dirty-work of actually painting the token.
|
||||||
*/
|
*/
|
||||||
protected float paintImpl(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, float clipStart,
|
protected float paintImpl(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e,
|
||||||
boolean selected, boolean useSTC) {
|
float clipStart, boolean selected, boolean useSTC) {
|
||||||
int origX = (int) x;
|
int origX = (int) x;
|
||||||
int textOffs = token.getTextOffset();
|
int textOffs = token.getTextOffset();
|
||||||
char[] text = token.getTextArray();
|
char[] text = token.getTextArray();
|
||||||
@@ -157,7 +151,8 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float paintSelected(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, boolean useSTC) {
|
public float paintSelected(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e,
|
||||||
|
boolean useSTC) {
|
||||||
return paintSelected(token, g, x, y, host, e, 0, useSTC);
|
return paintSelected(token, g, x, y, host, e, 0, useSTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,35 +160,29 @@ class DefaultTokenPainter implements TokenPainter {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public float paintSelected(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, float clipStart,
|
public float paintSelected(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e,
|
||||||
boolean useSTC) {
|
float clipStart, boolean useSTC) {
|
||||||
return paintImpl(token, g, x, y, host, e, clipStart, true, useSTC);
|
return paintImpl(token, g, x, y, host, e, clipStart, true, useSTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paints dotted "tab" lines; that is, lines that show where your caret
|
* Paints dotted "tab" lines; that is, lines that show where your caret would go
|
||||||
* would go to on the line if you hit "tab". This visual effect is usually
|
* to on the line if you hit "tab". This visual effect is usually done in the
|
||||||
* done in the leading whitespace token(s) of lines.
|
* leading whitespace token(s) of lines.
|
||||||
*
|
*
|
||||||
* @param token
|
* @param token The token to render.
|
||||||
* The token to render.
|
* @param x The starting x-offset of this token. It is assumed that this is
|
||||||
* @param x
|
* the left margin of the text area (may be non-zero due to
|
||||||
* The starting x-offset of this token. It is assumed that this
|
|
||||||
* is the left margin of the text area (may be non-zero due to
|
|
||||||
* insets), since tab lines are only painted for leading
|
* insets), since tab lines are only painted for leading
|
||||||
* whitespace.
|
* whitespace.
|
||||||
* @param y
|
* @param y The baseline where this token was painted.
|
||||||
* The baseline where this token was painted.
|
* @param endX The ending x-offset of this token.
|
||||||
* @param endX
|
* @param g The graphics context.
|
||||||
* The ending x-offset of this token.
|
* @param e Used to expand tabs.
|
||||||
* @param g
|
* @param host The text area.
|
||||||
* The graphics context.
|
|
||||||
* @param e
|
|
||||||
* Used to expand tabs.
|
|
||||||
* @param host
|
|
||||||
* The text area.
|
|
||||||
*/
|
*/
|
||||||
protected void paintTabLines(Token token, int x, int y, int endX, Graphics2D g, TabExpander e, RSyntaxTextArea host) {
|
protected void paintTabLines(Token token, int x, int y, int endX, Graphics2D g, TabExpander e,
|
||||||
|
RSyntaxTextArea host) {
|
||||||
// We allow tab lines to be painted in more than just Token.WHITESPACE,
|
// We allow tab lines to be painted in more than just Token.WHITESPACE,
|
||||||
// i.e. for MLC's and Token.IDENTIFIERS (for TokenMakers that return
|
// i.e. for MLC's and Token.IDENTIFIERS (for TokenMakers that return
|
||||||
// whitespace as identifiers for performance). But we only paint tab
|
// whitespace as identifiers for performance). But we only paint tab
|
||||||
|
|||||||
@@ -20,13 +20,11 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param startOffs
|
* @param startOffs The starting offset in the document, inclusive.
|
||||||
* The starting offset in the document, inclusive.
|
* @param endOffs The ending offset in the document, exclusive.
|
||||||
* @param endOffs
|
* @throws IllegalArgumentException If <code>endOffs</code> is less than
|
||||||
* The ending offset in the document, exclusive.
|
* <code>startOffs</code>, or either argument
|
||||||
* @throws IllegalArgumentException
|
* is less than zero.
|
||||||
* If <code>endOffs</code> is less than
|
|
||||||
* <code>startOffs</code>, or either argument is less than zero.
|
|
||||||
*/
|
*/
|
||||||
public DocumentRange(int startOffs, int endOffs) {
|
public DocumentRange(int startOffs, int endOffs) {
|
||||||
set(startOffs, endOffs);
|
set(startOffs, endOffs);
|
||||||
@@ -35,8 +33,7 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
/**
|
/**
|
||||||
* Compares this document range to another.
|
* Compares this document range to another.
|
||||||
*
|
*
|
||||||
* @param other
|
* @param other Another document range.
|
||||||
* Another document range.
|
|
||||||
* @return How the two should be sorted relative to each other.
|
* @return How the two should be sorted relative to each other.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -54,10 +51,9 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
/**
|
/**
|
||||||
* Returns whether this document range is equal to another one.
|
* Returns whether this document range is equal to another one.
|
||||||
*
|
*
|
||||||
* @param other
|
* @param other Another object, presumably a document range.
|
||||||
* Another object, presumably a document range.
|
* @return Whether <code>other</code> is also a document range, and equal to
|
||||||
* @return Whether <code>other</code> is also a document range, and equal
|
* this one.
|
||||||
* to this one.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
@@ -102,10 +98,9 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this document range has zero length. This can happen,
|
* Returns whether this document range has zero length. This can happen, for
|
||||||
* for example, with regex searches of forms like
|
* example, with regex searches of forms like <code>"foo|"</code>, where the
|
||||||
* <code>"foo|"</code>, where the right-hand sub-expression matches empty
|
* right-hand sub-expression matches empty strings.
|
||||||
* strings.
|
|
||||||
*
|
*
|
||||||
* @return Whether this document range has zero length.
|
* @return Whether this document range has zero length.
|
||||||
*/
|
*/
|
||||||
@@ -116,13 +111,11 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
/**
|
/**
|
||||||
* Sets the document range.
|
* Sets the document range.
|
||||||
*
|
*
|
||||||
* @param start
|
* @param start The new start value, inclusive.
|
||||||
* The new start value, inclusive.
|
* @param end The new end value, exclusive.
|
||||||
* @param end
|
* @throws IllegalArgumentException If <code>end</code> is less than
|
||||||
* The new end value, exclusive.
|
* <code>start</code>, or either argument is
|
||||||
* @throws IllegalArgumentException
|
* less than zero.
|
||||||
* If <code>end</code> is less than
|
|
||||||
* <code>start</code>, or either argument is less than zero.
|
|
||||||
*/
|
*/
|
||||||
public void set(int start, int end) {
|
public void set(int start, int end) {
|
||||||
if (start < 0 || end < 0) {
|
if (start < 0 || end < 0) {
|
||||||
@@ -148,8 +141,7 @@ public class DocumentRange implements Comparable<DocumentRange> {
|
|||||||
/**
|
/**
|
||||||
* Translates this document range by a given amount.
|
* Translates this document range by a given amount.
|
||||||
*
|
*
|
||||||
* @param amount
|
* @param amount The amount to translate this range by.
|
||||||
* The amount to translate this range by.
|
|
||||||
* @return This (modified) range.
|
* @return This (modified) range.
|
||||||
*/
|
*/
|
||||||
public DocumentRange translate(int amount) {
|
public DocumentRange translate(int amount) {
|
||||||
|
|||||||
@@ -39,16 +39,15 @@ import org.fife.ui.rsyntaxtextarea.parser.TaskTagParser.TaskNotice;
|
|||||||
import org.fife.ui.rtextarea.RTextArea;
|
import org.fife.ui.rtextarea.RTextArea;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component to sit alongside an {@link RSyntaxTextArea} that displays
|
* A component to sit alongside an {@link RSyntaxTextArea} that displays colored
|
||||||
* colored markers for locations of interest (parser errors, marked
|
* markers for locations of interest (parser errors, marked occurrences, etc.).
|
||||||
* occurrences, etc.).
|
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* <code>ErrorStrip</code>s display <code>ParserNotice</code>s from
|
* <code>ErrorStrip</code>s display <code>ParserNotice</code>s from
|
||||||
* {@link Parser}s. Currently, the only way to get lines flagged in this
|
* {@link Parser}s. Currently, the only way to get lines flagged in this
|
||||||
* component is to register a <code>Parser</code> on an RSyntaxTextArea and
|
* component is to register a <code>Parser</code> on an RSyntaxTextArea and
|
||||||
* return <code>ParserNotice</code>s for each line to display an icon for.
|
* return <code>ParserNotice</code>s for each line to display an icon for. The
|
||||||
* The severity of each notice must be at least the threshold set by
|
* severity of each notice must be at least the threshold set by
|
||||||
* {@link #setLevelThreshold(org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level)}
|
* {@link #setLevelThreshold(org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level)}
|
||||||
* to be displayed in this error strip. The default threshold is
|
* to be displayed in this error strip. The default threshold is
|
||||||
* {@link org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level#WARNING}.
|
* {@link org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level#WARNING}.
|
||||||
@@ -86,23 +85,23 @@ public class ErrorStrip extends JPanel {
|
|||||||
*/
|
*/
|
||||||
private transient Listener listener;
|
private transient Listener listener;
|
||||||
/**
|
/**
|
||||||
* Whether "marked occurrences" in the text area should be shown in this
|
* Whether "marked occurrences" in the text area should be shown in this error
|
||||||
* error strip.
|
* strip.
|
||||||
*/
|
*/
|
||||||
private boolean showMarkedOccurrences;
|
private boolean showMarkedOccurrences;
|
||||||
/**
|
/**
|
||||||
* Whether markers for "mark all" highlights should be shown in this
|
* Whether markers for "mark all" highlights should be shown in this error
|
||||||
* error strip.
|
* strip.
|
||||||
*/
|
*/
|
||||||
private boolean showMarkAll;
|
private boolean showMarkAll;
|
||||||
/**
|
/**
|
||||||
* Mapping of colors to brighter colors. This is kept to prevent
|
* Mapping of colors to brighter colors. This is kept to prevent unnecessary
|
||||||
* unnecessary creation of the same Colors over and over.
|
* creation of the same Colors over and over.
|
||||||
*/
|
*/
|
||||||
private Map<Color, Color> brighterColors;
|
private Map<Color, Color> brighterColors;
|
||||||
/**
|
/**
|
||||||
* Only notices of this severity (or worse) will be displayed in this
|
* Only notices of this severity (or worse) will be displayed in this error
|
||||||
* error strip.
|
* strip.
|
||||||
*/
|
*/
|
||||||
private ParserNotice.Level levelThreshold;
|
private ParserNotice.Level levelThreshold;
|
||||||
/**
|
/**
|
||||||
@@ -134,8 +133,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area we are examining.
|
||||||
* The text area we are examining.
|
|
||||||
*/
|
*/
|
||||||
public ErrorStrip(RSyntaxTextArea textArea) {
|
public ErrorStrip(RSyntaxTextArea textArea) {
|
||||||
this.textArea = textArea;
|
this.textArea = textArea;
|
||||||
@@ -152,8 +150,8 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden so we only start listening for parser notices when this
|
* Overridden so we only start listening for parser notices when this component
|
||||||
* component (and presumably the text area) are visible.
|
* (and presumably the text area) are visible.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addNotify() {
|
public void addNotify() {
|
||||||
@@ -181,8 +179,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Returns a "brighter" color.
|
* Returns a "brighter" color.
|
||||||
*
|
*
|
||||||
* @param c
|
* @param c The color.
|
||||||
* The color.
|
|
||||||
* @return A brighter color.
|
* @return A brighter color.
|
||||||
*/
|
*/
|
||||||
private Color getBrighterColor(Color c) {
|
private Color getBrighterColor(Color c) {
|
||||||
@@ -232,9 +229,9 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the minimum severity a parser notice must be for it to be
|
* Returns the minimum severity a parser notice must be for it to be displayed
|
||||||
* displayed in this error strip. This will be one of the constants
|
* in this error strip. This will be one of the constants defined in the
|
||||||
* defined in the <code>ParserNotice</code> class.
|
* <code>ParserNotice</code> class.
|
||||||
*
|
*
|
||||||
* @return The minimum severity.
|
* @return The minimum severity.
|
||||||
* @see #setLevelThreshold(org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level)
|
* @see #setLevelThreshold(org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level)
|
||||||
@@ -278,11 +275,10 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the y-offset in this component corresponding to a line in the
|
* Returns the y-offset in this component corresponding to a line in the text
|
||||||
* text component.
|
* component.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The line.
|
||||||
* The line.
|
|
||||||
* @return The y-offset.
|
* @return The y-offset.
|
||||||
* @see #yToLine(int)
|
* @see #yToLine(int)
|
||||||
*/
|
*/
|
||||||
@@ -295,8 +291,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Overridden to (possibly) draw the caret's position.
|
* Overridden to (possibly) draw the caret's position.
|
||||||
*
|
*
|
||||||
* @param g
|
* @param g The graphics context.
|
||||||
* The graphics context.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
@@ -310,8 +305,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Returns a possibly brighter component for a color.
|
* Returns a possibly brighter component for a color.
|
||||||
*
|
*
|
||||||
* @param i
|
* @param i An RGB component for a color (0-255).
|
||||||
* An RGB component for a color (0-255).
|
|
||||||
* @return A possibly brighter value for the component.
|
* @return A possibly brighter value for the component.
|
||||||
*/
|
*/
|
||||||
private static int possiblyBrighter(int i) {
|
private static int possiblyBrighter(int i) {
|
||||||
@@ -358,12 +352,9 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Adds markers for a list of ranges in the document.
|
* Adds markers for a list of ranges in the document.
|
||||||
*
|
*
|
||||||
* @param ranges
|
* @param ranges The list of ranges in the document.
|
||||||
* The list of ranges in the document.
|
* @param markerMap A mapping from line number to <code>Marker</code>.
|
||||||
* @param markerMap
|
* @param color The color to use for the markers.
|
||||||
* A mapping from line number to <code>Marker</code>.
|
|
||||||
* @param color
|
|
||||||
* The color to use for the markers.
|
|
||||||
*/
|
*/
|
||||||
private void addMarkersForRanges(List<DocumentRange> ranges, Map<Integer, Marker> markerMap, Color color) {
|
private void addMarkersForRanges(List<DocumentRange> ranges, Map<Integer, Marker> markerMap, Color color) {
|
||||||
for (DocumentRange range : ranges) {
|
for (DocumentRange range : ranges) {
|
||||||
@@ -405,8 +396,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Sets the color to use when painting the caret marker.
|
* Sets the color to use when painting the caret marker.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The new caret marker color.
|
||||||
* The new caret marker color.
|
|
||||||
* @see #getCaretMarkerColor()
|
* @see #getCaretMarkerColor()
|
||||||
*/
|
*/
|
||||||
public void setCaretMarkerColor(Color color) {
|
public void setCaretMarkerColor(Color color) {
|
||||||
@@ -419,8 +409,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Toggles whether the caret's current location should be drawn.
|
* Toggles whether the caret's current location should be drawn.
|
||||||
*
|
*
|
||||||
* @param follow
|
* @param follow Whether the caret's current location should be followed.
|
||||||
* Whether the caret's current location should be followed.
|
|
||||||
* @see #getFollowCaret()
|
* @see #getFollowCaret()
|
||||||
*/
|
*/
|
||||||
public void setFollowCaret(boolean follow) {
|
public void setFollowCaret(boolean follow) {
|
||||||
@@ -436,13 +425,12 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the minimum severity a parser notice must be for it to be displayed
|
* Sets the minimum severity a parser notice must be for it to be displayed in
|
||||||
* in this error strip. This should be one of the constants defined in
|
* this error strip. This should be one of the constants defined in the
|
||||||
* the <code>ParserNotice</code> class. The default value is
|
* <code>ParserNotice</code> class. The default value is
|
||||||
* {@link org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level#WARNING}.
|
* {@link org.fife.ui.rsyntaxtextarea.parser.ParserNotice.Level#WARNING}.
|
||||||
*
|
*
|
||||||
* @param level
|
* @param level The new severity threshold.
|
||||||
* The new severity threshold.
|
|
||||||
* @see #getLevelThreshold()
|
* @see #getLevelThreshold()
|
||||||
* @see ParserNotice
|
* @see ParserNotice
|
||||||
*/
|
*/
|
||||||
@@ -454,12 +442,11 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the provider of tool tips for markers in this error strip.
|
* Sets the provider of tool tips for markers in this error strip. Applications
|
||||||
* Applications can use this method to control the content and format of
|
* can use this method to control the content and format of the tool tip
|
||||||
* the tool tip descriptions of line markers.
|
* descriptions of line markers.
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider The provider. If this is <code>null</code>, a default
|
||||||
* The provider. If this is <code>null</code>, a default
|
|
||||||
* implementation will be used.
|
* implementation will be used.
|
||||||
*/
|
*/
|
||||||
public void setMarkerToolTipProvider(ErrorStripMarkerToolTipProvider provider) {
|
public void setMarkerToolTipProvider(ErrorStripMarkerToolTipProvider provider) {
|
||||||
@@ -469,8 +456,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Sets whether "mark all" highlights are shown in this error strip.
|
* Sets whether "mark all" highlights are shown in this error strip.
|
||||||
*
|
*
|
||||||
* @param show
|
* @param show Whether to show markers for "mark all" highlights.
|
||||||
* Whether to show markers for "mark all" highlights.
|
|
||||||
* @see #getShowMarkAll()
|
* @see #getShowMarkAll()
|
||||||
*/
|
*/
|
||||||
public void setShowMarkAll(boolean show) {
|
public void setShowMarkAll(boolean show) {
|
||||||
@@ -485,8 +471,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
/**
|
/**
|
||||||
* Sets whether marked occurrences are shown in this error strip.
|
* Sets whether marked occurrences are shown in this error strip.
|
||||||
*
|
*
|
||||||
* @param show
|
* @param show Whether to show marked occurrences.
|
||||||
* Whether to show marked occurrences.
|
|
||||||
* @see #getShowMarkedOccurrences()
|
* @see #getShowMarkedOccurrences()
|
||||||
*/
|
*/
|
||||||
public void setShowMarkedOccurrences(boolean show) {
|
public void setShowMarkedOccurrences(boolean show) {
|
||||||
@@ -502,8 +487,7 @@ public class ErrorStrip extends JPanel {
|
|||||||
* Returns the line in the text area corresponding to a y-offset in this
|
* Returns the line in the text area corresponding to a y-offset in this
|
||||||
* component.
|
* component.
|
||||||
*
|
*
|
||||||
* @param y
|
* @param y The y-offset.
|
||||||
* The y-offset.
|
|
||||||
* @return The line.
|
* @return The line.
|
||||||
* @see #lineToY(int)
|
* @see #lineToY(int)
|
||||||
*/
|
*/
|
||||||
@@ -518,8 +502,8 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation of the provider of tool tips for markers in
|
* The default implementation of the provider of tool tips for markers in an
|
||||||
* an error strip.
|
* error strip.
|
||||||
*
|
*
|
||||||
* @author predi
|
* @author predi
|
||||||
*/
|
*/
|
||||||
@@ -547,21 +531,20 @@ public class ErrorStrip extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns tool tip text for the markers in an {@link ErrorStrip} that
|
* Returns tool tip text for the markers in an {@link ErrorStrip} that denote
|
||||||
* denote one or more parser notices.
|
* one or more parser notices.
|
||||||
*
|
*
|
||||||
* @author predi
|
* @author predi
|
||||||
*/
|
*/
|
||||||
public interface ErrorStripMarkerToolTipProvider {
|
public interface ErrorStripMarkerToolTipProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tool tip text for a marker in an <code>ErrorStrip</code>
|
* Returns the tool tip text for a marker in an <code>ErrorStrip</code> that
|
||||||
* that denotes a given list of parser notices.
|
* denotes a given list of parser notices.
|
||||||
*
|
*
|
||||||
* @param notices
|
* @param notices The list of parser notices.
|
||||||
* The list of parser notices.
|
* @return The tool tip text. This may be HTML. Returning <code>null</code> will
|
||||||
* @return The tool tip text. This may be HTML. Returning
|
* result in no tool tip being displayed.
|
||||||
* <code>null</code> will result in no tool tip being displayed.
|
|
||||||
*/
|
*/
|
||||||
String getToolTipText(List<ParserNotice> notices);
|
String getToolTipText(List<ParserNotice> notices);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ class FileFileLocation extends FileLocation {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param file
|
* @param file The local file.
|
||||||
* The local file.
|
|
||||||
*/
|
*/
|
||||||
FileFileLocation(File file) {
|
FileFileLocation(File file) {
|
||||||
try {
|
try {
|
||||||
@@ -96,8 +95,8 @@ class FileFileLocation extends FileLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Since file locations of this type are guaranteed to be local, this
|
* Since file locations of this type are guaranteed to be local, this method
|
||||||
* method returns whether the file exists.
|
* returns whether the file exists.
|
||||||
*
|
*
|
||||||
* @return Whether this local file actually exists.
|
* @return Whether this local file actually exists.
|
||||||
* @see #isLocal()
|
* @see #isLocal()
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the location of a local or remote file. This provides a common way
|
* Holds the location of a local or remote file. This provides a common way to
|
||||||
* to read, write, and check properties of both local and remote files.
|
* read, write, and check properties of both local and remote files.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -25,12 +25,12 @@ public abstract class FileLocation {
|
|||||||
/**
|
/**
|
||||||
* Creates a {@link FileLocation} instance for the specified local file.
|
* Creates a {@link FileLocation} instance for the specified local file.
|
||||||
*
|
*
|
||||||
* @param fileFullPath
|
* @param fileFullPath The full path to a local file.
|
||||||
* The full path to a local file.
|
|
||||||
* @return The file's location.
|
* @return The file's location.
|
||||||
*/
|
*/
|
||||||
public static FileLocation create(String fileFullPath) {
|
public static FileLocation create(String fileFullPath) {
|
||||||
if (fileFullPath.startsWith("http://") || fileFullPath.startsWith("https://") || fileFullPath.startsWith("ftp://")) {
|
if (fileFullPath.startsWith("http://") || fileFullPath.startsWith("https://")
|
||||||
|
|| fileFullPath.startsWith("ftp://")) {
|
||||||
try {
|
try {
|
||||||
return new URLFileLocation(new URL(fileFullPath));
|
return new URLFileLocation(new URL(fileFullPath));
|
||||||
} catch (MalformedURLException mue) {
|
} catch (MalformedURLException mue) {
|
||||||
@@ -43,8 +43,7 @@ public abstract class FileLocation {
|
|||||||
/**
|
/**
|
||||||
* Creates a {@link FileLocation} instance for the specified local file.
|
* Creates a {@link FileLocation} instance for the specified local file.
|
||||||
*
|
*
|
||||||
* @param file
|
* @param file A local file.
|
||||||
* A local file.
|
|
||||||
* @return The file's location.
|
* @return The file's location.
|
||||||
*/
|
*/
|
||||||
public static FileLocation create(File file) {
|
public static FileLocation create(File file) {
|
||||||
@@ -54,8 +53,7 @@ public abstract class FileLocation {
|
|||||||
/**
|
/**
|
||||||
* Creates a {@link FileLocation} instance for the specified file.
|
* Creates a {@link FileLocation} instance for the specified file.
|
||||||
*
|
*
|
||||||
* @param url
|
* @param url The URL of a file.
|
||||||
* The URL of a file.
|
|
||||||
* @return The file's location.
|
* @return The file's location.
|
||||||
*/
|
*/
|
||||||
public static FileLocation create(URL url) {
|
public static FileLocation create(URL url) {
|
||||||
@@ -67,16 +65,16 @@ public abstract class FileLocation {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last time this file was modified, or
|
* Returns the last time this file was modified, or
|
||||||
* {@link TextEditorPane#LAST_MODIFIED_UNKNOWN} if this value cannot be
|
* {@link TextEditorPane#LAST_MODIFIED_UNKNOWN} if this value cannot be computed
|
||||||
* computed (such as for a remote file).
|
* (such as for a remote file).
|
||||||
*
|
*
|
||||||
* @return The last time this file was modified.
|
* @return The last time this file was modified.
|
||||||
*/
|
*/
|
||||||
protected abstract long getActualLastModified();
|
protected abstract long getActualLastModified();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the full path to the file. This will be stripped of
|
* Returns the full path to the file. This will be stripped of sensitive
|
||||||
* sensitive information such as passwords for remote files.
|
* information such as passwords for remote files.
|
||||||
*
|
*
|
||||||
* @return The full path to the file.
|
* @return The full path to the file.
|
||||||
* @see #getFileName()
|
* @see #getFileName()
|
||||||
@@ -95,8 +93,7 @@ public abstract class FileLocation {
|
|||||||
* Opens an input stream for reading from this file.
|
* Opens an input stream for reading from this file.
|
||||||
*
|
*
|
||||||
* @return The input stream.
|
* @return The input stream.
|
||||||
* @throws IOException
|
* @throws IOException If the file does not exist, or some other IO error
|
||||||
* If the file does not exist, or some other IO error
|
|
||||||
* occurs.
|
* occurs.
|
||||||
*/
|
*/
|
||||||
protected abstract InputStream getInputStream() throws IOException;
|
protected abstract InputStream getInputStream() throws IOException;
|
||||||
@@ -105,8 +102,7 @@ public abstract class FileLocation {
|
|||||||
* Opens an output stream for writing this file.
|
* Opens an output stream for writing this file.
|
||||||
*
|
*
|
||||||
* @return An output stream.
|
* @return An output stream.
|
||||||
* @throws IOException
|
* @throws IOException If an IO error occurs.
|
||||||
* If an IO error occurs.
|
|
||||||
*/
|
*/
|
||||||
protected abstract OutputStream getOutputStream() throws IOException;
|
protected abstract OutputStream getOutputStream() throws IOException;
|
||||||
|
|
||||||
@@ -119,8 +115,7 @@ public abstract class FileLocation {
|
|||||||
public abstract boolean isLocal();
|
public abstract boolean isLocal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this file location is a local file that already
|
* Returns whether this file location is a local file that already exists.
|
||||||
* exists.
|
|
||||||
*
|
*
|
||||||
* @return Whether this file is local and actually exists.
|
* @return Whether this file is local and actually exists.
|
||||||
* @see #isLocal()
|
* @see #isLocal()
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class FoldingAwareIconRowHeader extends IconRowHeader {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The parent text area.
|
||||||
* The parent text area.
|
|
||||||
*/
|
*/
|
||||||
public FoldingAwareIconRowHeader(RSyntaxTextArea textArea) {
|
public FoldingAwareIconRowHeader(RSyntaxTextArea textArea) {
|
||||||
super(textArea);
|
super(textArea);
|
||||||
@@ -162,9 +161,9 @@ public class FoldingAwareIconRowHeader extends IconRowHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paints icons when line wrapping is enabled. Note that this does not
|
* Paints icons when line wrapping is enabled. Note that this does not override
|
||||||
* override the parent class's implementation to avoid this version being
|
* the parent class's implementation to avoid this version being called when
|
||||||
* called when line wrapping is disabled.
|
* line wrapping is disabled.
|
||||||
*/
|
*/
|
||||||
private void paintComponentWrapped(Graphics g) {
|
private void paintComponentWrapped(Graphics g) {
|
||||||
// The variables we use are as follows:
|
// The variables we use are as follows:
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import javax.swing.text.Element;
|
|||||||
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks occurrences of the current token for HTML. Tags that require a
|
* Marks occurrences of the current token for HTML. Tags that require a closing
|
||||||
* closing tag have their "opposite" tag closed.
|
* tag have their "opposite" tag closed.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -33,36 +33,36 @@ public class HtmlOccurrenceMarker implements OccurrenceMarker {
|
|||||||
private static final Set<String> TAGS_REQUIRING_CLOSING = getRequiredClosingTags();
|
private static final Set<String> TAGS_REQUIRING_CLOSING = getRequiredClosingTags();
|
||||||
|
|
||||||
public static final Set<String> getRequiredClosingTags() {
|
public static final Set<String> getRequiredClosingTags() {
|
||||||
final String[] tags = { "html", "head", "title", "style", "script", "noscript", "body", "section", "nav", "article", "aside", "h1",
|
final String[] tags = { "html", "head", "title", "style", "script", "noscript", "body", "section", "nav",
|
||||||
"h2", "h3", "h4", "h5", "h6", "header", "footer", "address", "pre", "dialog", "blockquote", "ol", "ul", "dl", "a", "q",
|
"article", "aside", "h1", "h2", "h3", "h4", "h5", "h6", "header", "footer", "address", "pre", "dialog",
|
||||||
"cite", "em", "strong", "small", "mark", "dfn", "abbr", "time", "progress", "meter", "code", "var", "samp", "kbd", "sub",
|
"blockquote", "ol", "ul", "dl", "a", "q", "cite", "em", "strong", "small", "mark", "dfn", "abbr",
|
||||||
"sup", "span", "i", "b", "bdo", "ruby", "rt", "rp", "ins", "del", "figure", "iframe", "object", "video", "audio", "canvas",
|
"time", "progress", "meter", "code", "var", "samp", "kbd", "sub", "sup", "span", "i", "b", "bdo",
|
||||||
"map", "table", "caption", "form", "fieldset", "label", "button", "select", "datalist", "textarea", "output", "details",
|
"ruby", "rt", "rp", "ins", "del", "figure", "iframe", "object", "video", "audio", "canvas", "map",
|
||||||
"bb", "menu", "legend", "div",
|
"table", "caption", "form", "fieldset", "label", "button", "select", "datalist", "textarea", "output",
|
||||||
|
"details", "bb", "menu", "legend", "div",
|
||||||
// Obsolete elements
|
// Obsolete elements
|
||||||
"acronym", "applet", "big", "blink", "center", "dir", "font", "frame", "frameset", "isindex", "listing", "marquee", "nobr",
|
"acronym", "applet", "big", "blink", "center", "dir", "font", "frame", "frameset", "isindex", "listing",
|
||||||
"noembed", "noframes", "plaintext", "s", "spacer", "strike", "tt", "u", "xmp", };
|
"marquee", "nobr", "noembed", "noframes", "plaintext", "s", "spacer", "strike", "tt", "u", "xmp", };
|
||||||
return new HashSet<String>(Arrays.asList(tags));
|
return new HashSet<String>(Arrays.asList(tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the caret is inside of a tag, this method returns the token
|
* If the caret is inside of a tag, this method returns the token representing
|
||||||
* representing the tag name; otherwise, <code>null</code> is returned.
|
* the tag name; otherwise, <code>null</code> is returned.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Currently, this method only checks for tag names on the same line as
|
* Currently, this method only checks for tag names on the same line as the
|
||||||
* the caret, for simplicity. In the future it could check prior lines
|
* caret, for simplicity. In the future it could check prior lines until the tag
|
||||||
* until the tag name is found.
|
* name is found.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area.
|
||||||
* The text area.
|
* @param occurrenceMarker The occurrence marker.
|
||||||
* @param occurrenceMarker
|
* @return The token to mark occurrences of. Note that, if the specified
|
||||||
* The occurrence marker.
|
* occurrence marker identifies tokens other than tag names, these other
|
||||||
* @return The token to mark occurrences of. Note that, if the
|
* element types may be returned.
|
||||||
* specified occurrence marker identifies tokens other than
|
|
||||||
* tag names, these other element types may be returned.
|
|
||||||
*/
|
*/
|
||||||
public static final Token getTagNameTokenForCaretOffset(RSyntaxTextArea textArea, OccurrenceMarker occurrenceMarker) {
|
public static final Token getTagNameTokenForCaretOffset(RSyntaxTextArea textArea,
|
||||||
|
OccurrenceMarker occurrenceMarker) {
|
||||||
// Get the tag name token.
|
// Get the tag name token.
|
||||||
// For now, we only check for tags on the current line, for simplicity.
|
// For now, we only check for tags on the current line, for simplicity.
|
||||||
int dot = textArea.getCaretPosition();
|
int dot = textArea.getCaretPosition();
|
||||||
|
|||||||
@@ -31,14 +31,11 @@ public interface LinkGenerator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If a region of text under the mouse position should be considered a
|
* If a region of text under the mouse position should be considered a
|
||||||
* hyperlink, a result object is returned. This object describes what
|
* hyperlink, a result object is returned. This object describes what region of
|
||||||
* region of text is the link, and what action to perform if the link is
|
* text is the link, and what action to perform if the link is clicked.
|
||||||
* clicked.
|
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text component.
|
||||||
* The text component.
|
* @param offs The offset in the document under the mouse position.
|
||||||
* @param offs
|
|
||||||
* The offset in the document under the mouse position.
|
|
||||||
* @return The link information, or <code>null</code> if no link is at the
|
* @return The link information, or <code>null</code> if no link is at the
|
||||||
* specified offset.
|
* specified offset.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import javax.swing.event.HyperlinkEvent;
|
|||||||
public interface LinkGeneratorResult {
|
public interface LinkGeneratorResult {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the action associated with this object. If the result is a
|
* Executes the action associated with this object. If the result is a URL to
|
||||||
* URL to open, a standard hyperlink event can be returned. Alternatively,
|
* open, a standard hyperlink event can be returned. Alternatively,
|
||||||
* <code>null</code> can be returned and the action performed in this
|
* <code>null</code> can be returned and the action performed in this method
|
||||||
* method itself.
|
* itself.
|
||||||
*
|
*
|
||||||
* @return The hyperlink event to broadcast from the text area, or
|
* @return The hyperlink event to broadcast from the text area, or
|
||||||
* <code>null</code> if the action's behavior occurs in this method
|
* <code>null</code> if the action's behavior occurs in this method
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import javax.swing.text.Caret;
|
|||||||
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
import org.fife.ui.rtextarea.SmartHighlightPainter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks all occurrences of the token at the current caret position, if it is
|
* Marks all occurrences of the token at the current caret position, if it is an
|
||||||
* an identifier.
|
* identifier.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -50,10 +50,9 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param delay
|
* @param delay The delay between when the caret last moves and when the text
|
||||||
* The delay between when the caret last moves and when the
|
* should be scanned for matching occurrences. This should be in
|
||||||
* text should be scanned for matching occurrences. This should
|
* milliseconds.
|
||||||
* be in milliseconds.
|
|
||||||
*/
|
*/
|
||||||
MarkOccurrencesSupport(int delay) {
|
MarkOccurrencesSupport(int delay) {
|
||||||
this(delay, DEFAULT_COLOR);
|
this(delay, DEFAULT_COLOR);
|
||||||
@@ -62,12 +61,10 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param delay
|
* @param delay The delay between when the caret last moves and when the text
|
||||||
* The delay between when the caret last moves and when the
|
* should be scanned for matching occurrences. This should be in
|
||||||
* text should be scanned for matching occurrences. This should
|
* milliseconds.
|
||||||
* be in milliseconds.
|
* @param color The color to use to mark the occurrences. This cannot be
|
||||||
* @param color
|
|
||||||
* The color to use to mark the occurrences. This cannot be
|
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
MarkOccurrencesSupport(int delay, Color color) {
|
MarkOccurrencesSupport(int delay, Color color) {
|
||||||
@@ -78,16 +75,15 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after the caret has been moved and a fixed time delay has
|
* Called after the caret has been moved and a fixed time delay has elapsed.
|
||||||
* elapsed. This locates and highlights all occurrences of the identifier
|
* This locates and highlights all occurrences of the identifier at the caret
|
||||||
* at the caret position, if any.
|
* position, if any.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Callers should not call this method directly, but should rather prefer
|
* Callers should not call this method directly, but should rather prefer
|
||||||
* {@link #doMarkOccurrences()} to mark occurrences.
|
* {@link #doMarkOccurrences()} to mark occurrences.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
* @see #doMarkOccurrences()
|
* @see #doMarkOccurrences()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -128,8 +124,7 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
/**
|
/**
|
||||||
* Called when the caret moves in the text area.
|
* Called when the caret moves in the text area.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void caretUpdate(CaretEvent e) {
|
public void caretUpdate(CaretEvent e) {
|
||||||
@@ -147,8 +142,7 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immediately marks all occurrences of the token at the current caret
|
* Immediately marks all occurrences of the token at the current caret position.
|
||||||
* position.
|
|
||||||
*/
|
*/
|
||||||
public void doMarkOccurrences() {
|
public void doMarkOccurrences() {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
@@ -187,11 +181,10 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs this listener on a text area. If it is already installed on
|
* Installs this listener on a text area. If it is already installed on another
|
||||||
* another text area, it is uninstalled first.
|
* text area, it is uninstalled first.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area to install on.
|
||||||
* The text area to install on.
|
|
||||||
*/
|
*/
|
||||||
public void install(RSyntaxTextArea textArea) {
|
public void install(RSyntaxTextArea textArea) {
|
||||||
if (this.textArea != null) {
|
if (this.textArea != null) {
|
||||||
@@ -207,8 +200,7 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
/**
|
/**
|
||||||
* Sets the color to use when marking occurrences.
|
* Sets the color to use when marking occurrences.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color The color to use.
|
||||||
* The color to use.
|
|
||||||
* @see #getColor()
|
* @see #getColor()
|
||||||
* @see #setPaintBorder(boolean)
|
* @see #setPaintBorder(boolean)
|
||||||
*/
|
*/
|
||||||
@@ -221,12 +213,11 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the delay between the last caret position change and when the
|
* Sets the delay between the last caret position change and when the text is
|
||||||
* text is scanned for matching identifiers. A delay is needed to prevent
|
* scanned for matching identifiers. A delay is needed to prevent repeated
|
||||||
* repeated scanning while the user is typing.
|
* scanning while the user is typing.
|
||||||
*
|
*
|
||||||
* @param delay
|
* @param delay The new delay.
|
||||||
* The new delay.
|
|
||||||
* @see #getDelay()
|
* @see #getDelay()
|
||||||
*/
|
*/
|
||||||
public void setDelay(int delay) {
|
public void setDelay(int delay) {
|
||||||
@@ -236,8 +227,7 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
/**
|
/**
|
||||||
* Toggles whether a border is painted around marked highlights.
|
* Toggles whether a border is painted around marked highlights.
|
||||||
*
|
*
|
||||||
* @param paint
|
* @param paint Whether to paint a border.
|
||||||
* Whether to paint a border.
|
|
||||||
* @see #getPaintBorder()
|
* @see #getPaintBorder()
|
||||||
* @see #setColor(Color)
|
* @see #setColor(Color)
|
||||||
*/
|
*/
|
||||||
@@ -251,8 +241,8 @@ class MarkOccurrencesSupport implements CaretListener, ActionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninstalls this listener from the current text area. Does nothing if
|
* Uninstalls this listener from the current text area. Does nothing if it not
|
||||||
* it not currently installed on any text area.
|
* currently installed on any text area.
|
||||||
*
|
*
|
||||||
* @see #install(RSyntaxTextArea)
|
* @see #install(RSyntaxTextArea)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ class MatchedBracketPopup extends JWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Positions this popup to be in the top right-hand corner of the parent
|
* Positions this popup to be in the top right-hand corner of the parent editor.
|
||||||
* editor.
|
|
||||||
*/
|
*/
|
||||||
private void setLocation() {
|
private void setLocation() {
|
||||||
Point topLeft = textArea.getVisibleRect().getLocation();
|
Point topLeft = textArea.getVisibleRect().getLocation();
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import org.fife.ui.rtextarea.SmartHighlightPainter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An <code>OccurrenceMarker</code> is called when the caret stops moving after
|
* An <code>OccurrenceMarker</code> is called when the caret stops moving after
|
||||||
* a short period. If the current {@link TokenMaker} returns an instance of
|
* a short period. If the current {@link TokenMaker} returns an instance of this
|
||||||
* this class, it is told to mark all occurrences of the identifier at the
|
* class, it is told to mark all occurrences of the identifier at the caret
|
||||||
* caret position.
|
* position.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -20,27 +20,23 @@ import org.fife.ui.rtextarea.SmartHighlightPainter;
|
|||||||
public interface OccurrenceMarker {
|
public interface OccurrenceMarker {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the token to mark occurrences, of, provided it matches the
|
* Returns the token to mark occurrences, of, provided it matches the criteria
|
||||||
* criteria put forth by {@link #isValidType(RSyntaxTextArea, Token)}.
|
* put forth by {@link #isValidType(RSyntaxTextArea, Token)}. For most
|
||||||
* For most languages, this method should return the token at the caret
|
* languages, this method should return the token at the caret position.
|
||||||
* position.
|
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area.
|
||||||
* The text area.
|
* @return The token to (possibly) mark occurrences of, or <code>null</code> if
|
||||||
* @return The token to (possibly) mark occurrences of, or
|
* none.
|
||||||
* <code>null</code> if none.
|
|
||||||
*/
|
*/
|
||||||
Token getTokenToMark(RSyntaxTextArea textArea);
|
Token getTokenToMark(RSyntaxTextArea textArea);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the specified token is a type that we can do a
|
* Returns whether the specified token is a type that we can do a "mark
|
||||||
* "mark occurrences" of. Typically, this will delegate to
|
* occurrences" of. Typically, this will delegate to
|
||||||
* {@link RSyntaxTextArea#getMarkOccurrencesOfTokenType(int)}.
|
* {@link RSyntaxTextArea#getMarkOccurrencesOfTokenType(int)}.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area.
|
||||||
* The text area.
|
* @param t The token.
|
||||||
* @param t
|
|
||||||
* The token.
|
|
||||||
* @return Whether we should mark all occurrences of this token.
|
* @return Whether we should mark all occurrences of this token.
|
||||||
*/
|
*/
|
||||||
boolean isValidType(RSyntaxTextArea textArea, Token t);
|
boolean isValidType(RSyntaxTextArea textArea, Token t);
|
||||||
@@ -48,14 +44,10 @@ public interface OccurrenceMarker {
|
|||||||
/**
|
/**
|
||||||
* Called when occurrences of a token should be marked.
|
* Called when occurrences of a token should be marked.
|
||||||
*
|
*
|
||||||
* @param doc
|
* @param doc The document.
|
||||||
* The document.
|
* @param t The document whose relevant occurrences should be marked.
|
||||||
* @param t
|
* @param h The highlighter to add the highlights to.
|
||||||
* The document whose relevant occurrences should be marked.
|
* @param p The painter for the highlights.
|
||||||
* @param h
|
|
||||||
* The highlighter to add the highlights to.
|
|
||||||
* @param p
|
|
||||||
* The painter for the highlights.
|
|
||||||
*/
|
*/
|
||||||
void markOccurrences(RSyntaxDocument doc, Token t, RSyntaxTextAreaHighlighter h, SmartHighlightPainter p);
|
void markOccurrences(RSyntaxDocument doc, Token t, RSyntaxTextAreaHighlighter h, SmartHighlightPainter p);
|
||||||
}
|
}
|
||||||
@@ -55,20 +55,21 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
private Position firstOffsetModded;
|
private Position firstOffsetModded;
|
||||||
private Position lastOffsetModded;
|
private Position lastOffsetModded;
|
||||||
/**
|
/**
|
||||||
* Mapping of notices to their highlights in the editor. Can't use a Map
|
* Mapping of notices to their highlights in the editor. Can't use a Map since
|
||||||
* since parsers could return two <code>ParserNotice</code>s that compare
|
* parsers could return two <code>ParserNotice</code>s that compare equally via
|
||||||
* equally via <code>equals()</code>. Real-world example: The Perl
|
* <code>equals()</code>. Real-world example: The Perl compiler will return 2+
|
||||||
* compiler will return 2+ identical error messages if the same error is
|
* identical error messages if the same error is committed in a single line more
|
||||||
* committed in a single line more than once.
|
* than once.
|
||||||
*/
|
*/
|
||||||
private List<NoticeHighlightPair> noticeHighlightPairs;
|
private List<NoticeHighlightPair> noticeHighlightPairs;
|
||||||
/**
|
/**
|
||||||
* Painter used to underline errors.
|
* Painter used to underline errors.
|
||||||
*/
|
*/
|
||||||
private SquiggleUnderlineHighlightPainter parserErrorHighlightPainter = new SquiggleUnderlineHighlightPainter(Color.RED);
|
private SquiggleUnderlineHighlightPainter parserErrorHighlightPainter = new SquiggleUnderlineHighlightPainter(
|
||||||
|
Color.RED);
|
||||||
/**
|
/**
|
||||||
* If this system property is set to <code>true</code>, debug messages
|
* If this system property is set to <code>true</code>, debug messages will be
|
||||||
* will be printed to stdout to help diagnose parsing issues.
|
* printed to stdout to help diagnose parsing issues.
|
||||||
*/
|
*/
|
||||||
private static final String PROPERTY_DEBUG_PARSING = "rsta.debugParsing";
|
private static final String PROPERTY_DEBUG_PARSING = "rsta.debugParsing";
|
||||||
/**
|
/**
|
||||||
@@ -76,17 +77,15 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
*/
|
*/
|
||||||
private static final boolean DEBUG_PARSING;
|
private static final boolean DEBUG_PARSING;
|
||||||
/**
|
/**
|
||||||
* The default delay between the last key press and when the document
|
* The default delay between the last key press and when the document is parsed,
|
||||||
* is parsed, in milliseconds.
|
* in milliseconds.
|
||||||
*/
|
*/
|
||||||
private static final int DEFAULT_DELAY_MS = 1250;
|
private static final int DEFAULT_DELAY_MS = 1250;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param textArea
|
* @param textArea The text area whose document the parser will be parsing.
|
||||||
* The text area whose document the parser will be
|
|
||||||
* parsing.
|
|
||||||
*/
|
*/
|
||||||
ParserManager(RSyntaxTextArea textArea) {
|
ParserManager(RSyntaxTextArea textArea) {
|
||||||
this(DEFAULT_DELAY_MS, textArea);
|
this(DEFAULT_DELAY_MS, textArea);
|
||||||
@@ -95,12 +94,9 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param delay
|
* @param delay The delay between the last key press and when the document is
|
||||||
* The delay between the last key press and when the document
|
* parsed.
|
||||||
* is parsed.
|
* @param textArea The text area whose document the parser will be parsing.
|
||||||
* @param textArea
|
|
||||||
* The text area whose document the parser will be
|
|
||||||
* parsing.
|
|
||||||
*/
|
*/
|
||||||
ParserManager(int delay, RSyntaxTextArea textArea) {
|
ParserManager(int delay, RSyntaxTextArea textArea) {
|
||||||
this.textArea = textArea;
|
this.textArea = textArea;
|
||||||
@@ -115,8 +111,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when the timer fires (e.g. it's time to parse the document).
|
* Called when the timer fires (e.g. it's time to parse the document).
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
@@ -132,7 +127,8 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument();
|
RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument();
|
||||||
Element root = doc.getDefaultRootElement();
|
Element root = doc.getDefaultRootElement();
|
||||||
int firstLine = firstOffsetModded == null ? 0 : root.getElementIndex(firstOffsetModded.getOffset());
|
int firstLine = firstOffsetModded == null ? 0 : root.getElementIndex(firstOffsetModded.getOffset());
|
||||||
int lastLine = lastOffsetModded == null ? root.getElementCount() - 1 : root.getElementIndex(lastOffsetModded.getOffset());
|
int lastLine = lastOffsetModded == null ? root.getElementCount() - 1
|
||||||
|
: root.getElementIndex(lastOffsetModded.getOffset());
|
||||||
firstOffsetModded = lastOffsetModded = null;
|
firstOffsetModded = lastOffsetModded = null;
|
||||||
if (DEBUG_PARSING) {
|
if (DEBUG_PARSING) {
|
||||||
System.out.println("[DEBUG]: Minimum lines to parse: " + firstLine + "-" + lastLine);
|
System.out.println("[DEBUG]: Minimum lines to parse: " + firstLine + "-" + lastLine);
|
||||||
@@ -162,9 +158,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Adds a parser for the text area.
|
* Adds a parser for the text area.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The new parser. If this is <code>null</code>, nothing happens.
|
||||||
* The new parser. If this is <code>null</code>, nothing
|
|
||||||
* happens.
|
|
||||||
* @see #getParser(int)
|
* @see #getParser(int)
|
||||||
* @see #removeParser(Parser)
|
* @see #removeParser(Parser)
|
||||||
*/
|
*/
|
||||||
@@ -185,11 +179,10 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds highlights for a list of parser notices. Any current notices
|
* Adds highlights for a list of parser notices. Any current notices from the
|
||||||
* from the same Parser, in the same parsed range, are removed.
|
* same Parser, in the same parsed range, are removed.
|
||||||
*
|
*
|
||||||
* @param res
|
* @param res The result of a parsing.
|
||||||
* The result of a parsing.
|
|
||||||
* @see #clearParserNoticeHighlights()
|
* @see #clearParserNoticeHighlights()
|
||||||
*/
|
*/
|
||||||
private void addParserNoticeHighlights(ParseResult res) {
|
private void addParserNoticeHighlights(ParseResult res) {
|
||||||
@@ -231,11 +224,11 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when the document is modified.
|
* Called when the document is modified.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The document event.
|
||||||
* The document event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void changedUpdate(DocumentEvent e) {}
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
private void clearParserNoticeHighlights() {
|
private void clearParserNoticeHighlights() {
|
||||||
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) textArea.getHighlighter();
|
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) textArea.getHighlighter();
|
||||||
@@ -250,8 +243,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Removes all parser notice highlights for a specific parser.
|
* Removes all parser notice highlights for a specific parser.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The parser whose highlights to remove.
|
||||||
* The parser whose highlights to remove.
|
|
||||||
*/
|
*/
|
||||||
private void clearParserNoticeHighlights(Parser parser) {
|
private void clearParserNoticeHighlights(Parser parser) {
|
||||||
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) textArea.getHighlighter();
|
RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) textArea.getHighlighter();
|
||||||
@@ -282,18 +274,16 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces the given {@link Parser} to re-parse the content of this text
|
* Forces the given {@link Parser} to re-parse the content of this text area.
|
||||||
* area.
|
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This method can be useful when a <code>Parser</code> can be configured
|
* This method can be useful when a <code>Parser</code> can be configured as to
|
||||||
* as to what notices it returns. For example, if a Java language parser
|
* what notices it returns. For example, if a Java language parser can be
|
||||||
* can be configured to set whether no serialVersionUID is a warning,
|
* configured to set whether no serialVersionUID is a warning, error, or
|
||||||
* error, or ignored, this method can be called after changing the expected
|
* ignored, this method can be called after changing the expected notice type to
|
||||||
* notice type to have the document re-parsed.
|
* have the document re-parsed.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The index of the <code>Parser</code> to re-run.
|
||||||
* The index of the <code>Parser</code> to re-run.
|
|
||||||
* @see #getParser(int)
|
* @see #getParser(int)
|
||||||
*/
|
*/
|
||||||
public void forceReparsing(int parser) {
|
public void forceReparsing(int parser) {
|
||||||
@@ -315,8 +305,8 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the delay between the last "concurrent" edit and when the
|
* Returns the delay between the last "concurrent" edit and when the document is
|
||||||
* document is re-parsed.
|
* re-parsed.
|
||||||
*
|
*
|
||||||
* @return The delay, in milliseconds.
|
* @return The delay, in milliseconds.
|
||||||
* @see #setDelay(int)
|
* @see #setDelay(int)
|
||||||
@@ -328,8 +318,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Returns the specified parser.
|
* Returns the specified parser.
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index The index of the parser.
|
||||||
* The index of the parser.
|
|
||||||
* @return The parser.
|
* @return The parser.
|
||||||
* @see #getParserCount()
|
* @see #getParserCount()
|
||||||
* @see #addParser(Parser)
|
* @see #addParser(Parser)
|
||||||
@@ -349,12 +338,10 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of the current parser notices for this text area.
|
* Returns a list of the current parser notices for this text area. This method
|
||||||
* This method (like most Swing methods) should only be called on the
|
* (like most Swing methods) should only be called on the EDT.
|
||||||
* EDT.
|
|
||||||
*
|
*
|
||||||
* @return The list of notices. This will be an empty list if there are
|
* @return The list of notices. This will be an empty list if there are none.
|
||||||
* none.
|
|
||||||
*/
|
*/
|
||||||
public List<ParserNotice> getParserNotices() {
|
public List<ParserNotice> getParserNotices() {
|
||||||
List<ParserNotice> notices = new ArrayList<ParserNotice>();
|
List<ParserNotice> notices = new ArrayList<ParserNotice>();
|
||||||
@@ -367,13 +354,11 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tool tip to display for a mouse event at the given
|
* Returns the tool tip to display for a mouse event at the given location. This
|
||||||
* location. This method is overridden to give a registered parser a
|
* method is overridden to give a registered parser a chance to display a tool
|
||||||
* chance to display a tool tip (such as an error description when the
|
* tip (such as an error description when the mouse is over an error highlight).
|
||||||
* mouse is over an error highlight).
|
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The mouse event.
|
||||||
* The mouse event.
|
|
||||||
* @return The tool tip to display, and possibly a hyperlink event handler.
|
* @return The tool tip to display, and possibly a hyperlink event handler.
|
||||||
*/
|
*/
|
||||||
public ToolTipInfo getToolTipText(MouseEvent e) {
|
public ToolTipInfo getToolTipText(MouseEvent e) {
|
||||||
@@ -385,19 +370,12 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
int pos = textArea.viewToModel(p);
|
int pos = textArea.viewToModel(p);
|
||||||
/*
|
/*
|
||||||
* Highlighter.Highlight[] highlights = textArea.getHighlighter().
|
* Highlighter.Highlight[] highlights = textArea.getHighlighter().
|
||||||
* getHighlights();
|
* getHighlights(); for (int i=0; i<highlights.length; i++) {
|
||||||
* for (int i=0; i<highlights.length; i++) {
|
* Highlighter.Highlight h = highlights[i]; //if (h instanceof
|
||||||
* Highlighter.Highlight h = highlights[i];
|
* ParserNoticeHighlight) { // ParserNoticeHighlight pnh =
|
||||||
* //if (h instanceof ParserNoticeHighlight) {
|
* (ParserNoticeHighlight)h; int start = h.getStartOffset(); int end =
|
||||||
* // ParserNoticeHighlight pnh = (ParserNoticeHighlight)h;
|
* h.getEndOffset(); if (start<=pos && end>=pos) { //return pnh.getMessage();
|
||||||
* int start = h.getStartOffset();
|
* return textArea.getText(start, end-start); } //} }
|
||||||
* int end = h.getEndOffset();
|
|
||||||
* if (start<=pos && end>=pos) {
|
|
||||||
* //return pnh.getMessage();
|
|
||||||
* return textArea.getText(start, end-start);
|
|
||||||
* }
|
|
||||||
* //}
|
|
||||||
* }
|
|
||||||
*/
|
*/
|
||||||
if (noticeHighlightPairs != null) {
|
if (noticeHighlightPairs != null) {
|
||||||
for (NoticeHighlightPair pair : noticeHighlightPairs) {
|
for (NoticeHighlightPair pair : noticeHighlightPairs) {
|
||||||
@@ -422,8 +400,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when the document is modified.
|
* Called when the document is modified.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The document event.
|
||||||
* The document event.
|
|
||||||
*/
|
*/
|
||||||
public void handleDocumentEvent(DocumentEvent e) {
|
public void handleDocumentEvent(DocumentEvent e) {
|
||||||
if (running && parsers.size() > 0) {
|
if (running && parsers.size() > 0) {
|
||||||
@@ -435,8 +412,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
* Called when the user clicks a hyperlink in a
|
* Called when the user clicks a hyperlink in a
|
||||||
* {@link org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip}.
|
* {@link org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip}.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The event.
|
||||||
* The event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||||
@@ -448,8 +424,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when the document is modified.
|
* Called when the document is modified.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The document event.
|
||||||
* The document event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void insertUpdate(DocumentEvent e) {
|
public void insertUpdate(DocumentEvent e) {
|
||||||
@@ -473,10 +448,8 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Returns whether a parser notice contains the specified offset.
|
* Returns whether a parser notice contains the specified offset.
|
||||||
*
|
*
|
||||||
* @param notice
|
* @param notice The notice.
|
||||||
* The notice.
|
* @param offs The offset.
|
||||||
* @param offs
|
|
||||||
* The offset.
|
|
||||||
* @return Whether the notice contains the offset.
|
* @return Whether the notice contains the offset.
|
||||||
*/
|
*/
|
||||||
private boolean noticeContainsPosition(ParserNotice notice, int offs) {
|
private boolean noticeContainsPosition(ParserNotice notice, int offs) {
|
||||||
@@ -494,18 +467,16 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Since <code>viewToModel()</code> returns the <em>closest</em> model
|
* Since <code>viewToModel()</code> returns the <em>closest</em> model position,
|
||||||
* position, and the position doesn't <em>necessarily</em> contain the
|
* and the position doesn't <em>necessarily</em> contain the point passed in as
|
||||||
* point passed in as an argument, this method checks whether the point is
|
* an argument, this method checks whether the point is indeed contained in the
|
||||||
* indeed contained in the view rectangle for the specified offset.
|
* view rectangle for the specified offset.
|
||||||
*
|
*
|
||||||
* @param notice
|
* @param notice The parser notice.
|
||||||
* The parser notice.
|
* @param p The point possibly contained in the view range of the parser
|
||||||
* @param p
|
* notice.
|
||||||
* The point possibly contained in the view range of the
|
* @return Whether the parser notice actually contains the specified point in
|
||||||
* parser notice.
|
* the view.
|
||||||
* @return Whether the parser notice actually contains the specified point
|
|
||||||
* in the view.
|
|
||||||
*/
|
*/
|
||||||
private boolean noticeContainsPointInView(ParserNotice notice, Point p) {
|
private boolean noticeContainsPointInView(ParserNotice notice, Point p) {
|
||||||
try {
|
try {
|
||||||
@@ -547,8 +518,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when a property we're interested in changes.
|
* Called when a property we're interested in changes.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The property change event.
|
||||||
* The property change event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent e) {
|
public void propertyChange(PropertyChangeEvent e) {
|
||||||
@@ -569,8 +539,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Removes a parser.
|
* Removes a parser.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The parser to remove.
|
||||||
* The parser to remove.
|
|
||||||
* @return Whether the parser was found.
|
* @return Whether the parser was found.
|
||||||
* @see #addParser(Parser)
|
* @see #addParser(Parser)
|
||||||
* @see #getParser(int)
|
* @see #getParser(int)
|
||||||
@@ -585,11 +554,10 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all parser notices (and clears highlights in the editor) from
|
* Removes all parser notices (and clears highlights in the editor) from a
|
||||||
* a particular parser.
|
* particular parser.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The parser.
|
||||||
* The parser.
|
|
||||||
*/
|
*/
|
||||||
private void removeParserNotices(Parser parser) {
|
private void removeParserNotices(Parser parser) {
|
||||||
if (noticeHighlightPairs != null) {
|
if (noticeHighlightPairs != null) {
|
||||||
@@ -605,12 +573,11 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any currently stored notices (and the corresponding highlights
|
* Removes any currently stored notices (and the corresponding highlights from
|
||||||
* from the editor) from the same Parser, and in the given line range,
|
* the editor) from the same Parser, and in the given line range, as in the
|
||||||
* as in the results.
|
* results.
|
||||||
*
|
*
|
||||||
* @param res
|
* @param res The results.
|
||||||
* The results.
|
|
||||||
*/
|
*/
|
||||||
private void removeParserNotices(ParseResult res) {
|
private void removeParserNotices(ParseResult res) {
|
||||||
if (noticeHighlightPairs != null) {
|
if (noticeHighlightPairs != null) {
|
||||||
@@ -636,8 +603,7 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
/**
|
/**
|
||||||
* Called when the document is modified.
|
* Called when the document is modified.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The document event.
|
||||||
* The document event.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void removeUpdate(DocumentEvent e) {
|
public void removeUpdate(DocumentEvent e) {
|
||||||
@@ -670,12 +636,11 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the delay between the last "concurrent" edit and when the document
|
* Sets the delay between the last "concurrent" edit and when the document is
|
||||||
* is re-parsed.
|
* re-parsed.
|
||||||
*
|
*
|
||||||
* @param millis
|
* @param millis The new delay, in milliseconds. This must be greater than
|
||||||
* The new delay, in milliseconds. This must be greater
|
* <code>0</code>.
|
||||||
* than <code>0</code>.
|
|
||||||
* @see #getDelay()
|
* @see #getDelay()
|
||||||
*/
|
*/
|
||||||
public void setDelay(int millis) {
|
public void setDelay(int millis) {
|
||||||
@@ -690,18 +655,16 @@ class ParserManager implements DocumentListener, ActionListener, HyperlinkListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a parser notice should be removed, based on a parse
|
* Returns whether a parser notice should be removed, based on a parse result.
|
||||||
* result.
|
|
||||||
*
|
*
|
||||||
* @param notice
|
* @param notice The notice in question.
|
||||||
* The notice in question.
|
* @param res The result.
|
||||||
* @param res
|
|
||||||
* The result.
|
|
||||||
* @return Whether the notice should be removed.
|
* @return Whether the notice should be removed.
|
||||||
*/
|
*/
|
||||||
private boolean shouldRemoveNotice(ParserNotice notice, ParseResult res) {
|
private boolean shouldRemoveNotice(ParserNotice notice, ParseResult res) {
|
||||||
if (DEBUG_PARSING) {
|
if (DEBUG_PARSING) {
|
||||||
System.out.println("[DEBUG]: ... ... shouldRemoveNotice " + notice + ": " + (notice.getParser() == res.getParser()));
|
System.out.println(
|
||||||
|
"[DEBUG]: ... ... shouldRemoveNotice " + notice + ": " + (notice.getParser() == res.getParser()));
|
||||||
}
|
}
|
||||||
// NOTE: We must currently remove all notices for the parser. Parser
|
// NOTE: We must currently remove all notices for the parser. Parser
|
||||||
// implementors are required to parse the entire document each parsing
|
// implementors are required to parse the entire document each parsing
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import javax.swing.JWindow;
|
|||||||
/**
|
/**
|
||||||
* A hook allowing hosting applications to decorate JWindows created by the
|
* A hook allowing hosting applications to decorate JWindows created by the
|
||||||
* AutoComplete library. For example, you could use the
|
* AutoComplete library. For example, you could use the
|
||||||
* <a href="http://jgoodies.com/">JGoodies</a> library to add drop shadows
|
* <a href="http://jgoodies.com/">JGoodies</a> library to add drop shadows to
|
||||||
* to the windows.
|
* the windows.
|
||||||
*
|
*
|
||||||
* @author Robert Futrell
|
* @author Robert Futrell
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -27,20 +27,18 @@ public abstract class PopupWindowDecorator {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback called whenever an appropriate JWindow is created by the
|
* Callback called whenever an appropriate JWindow is created by the
|
||||||
* AutoComplete library. Implementations can decorate the window however
|
* AutoComplete library. Implementations can decorate the window however they
|
||||||
* they see fit.
|
* see fit.
|
||||||
*
|
*
|
||||||
* @param window
|
* @param window The newly-created window.
|
||||||
* The newly-created window.
|
|
||||||
*/
|
*/
|
||||||
public abstract void decorate(JWindow window);
|
public abstract void decorate(JWindow window);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the singleton instance of this class. This should only be
|
* Returns the singleton instance of this class. This should only be called on
|
||||||
* called on the EDT.
|
* the EDT.
|
||||||
*
|
*
|
||||||
* @return The singleton instance of this class, or <code>null</code>
|
* @return The singleton instance of this class, or <code>null</code> for none.
|
||||||
* for none.
|
|
||||||
* @see #set(PopupWindowDecorator)
|
* @see #set(PopupWindowDecorator)
|
||||||
*/
|
*/
|
||||||
public static PopupWindowDecorator get() {
|
public static PopupWindowDecorator get() {
|
||||||
@@ -48,11 +46,10 @@ public abstract class PopupWindowDecorator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the singleton instance of this class. This should only be called
|
* Sets the singleton instance of this class. This should only be called on the
|
||||||
* on the EDT.
|
* EDT.
|
||||||
*
|
*
|
||||||
* @param decorator
|
* @param decorator The new instance of this class. This may be
|
||||||
* The new instance of this class. This may be
|
|
||||||
* <code>null</code>.
|
* <code>null</code>.
|
||||||
* @see #get()
|
* @see #get()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,20 +22,16 @@ interface RSTAView {
|
|||||||
* Returns the y-coordinate of the specified line.
|
* Returns the y-coordinate of the specified line.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This method is quicker than using traditional
|
* This method is quicker than using traditional <code>modelToView(int)</code>
|
||||||
* <code>modelToView(int)</code> calls, as the entire bounding box isn't
|
* calls, as the entire bounding box isn't computed.
|
||||||
* computed.
|
|
||||||
*
|
*
|
||||||
* @param alloc
|
* @param alloc The area the text area can render into.
|
||||||
* The area the text area can render into.
|
* @param line The line number.
|
||||||
* @param line
|
* @return The y-coordinate of the top of the line, or <code>-1</code> if this
|
||||||
* The line number.
|
* text area doesn't yet have a positive size or the line is hidden
|
||||||
* @return The y-coordinate of the top of the line, or <code>-1</code> if
|
* (i.e. from folding).
|
||||||
* this text area doesn't yet have a positive size or the line is
|
* @throws BadLocationException If <code>line</code> isn't a valid line number
|
||||||
* hidden (i.e. from folding).
|
* for this document.
|
||||||
* @throws BadLocationException
|
|
||||||
* If <code>line</code> isn't a valid line
|
|
||||||
* number for this document.
|
|
||||||
*/
|
*/
|
||||||
int yForLine(Rectangle alloc, int line) throws BadLocationException;
|
int yForLine(Rectangle alloc, int line) throws BadLocationException;
|
||||||
|
|
||||||
@@ -43,20 +39,16 @@ interface RSTAView {
|
|||||||
* Returns the y-coordinate of the line containing a specified offset.
|
* Returns the y-coordinate of the line containing a specified offset.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* This method is quicker than using traditional
|
* This method is quicker than using traditional <code>modelToView(int)</code>
|
||||||
* <code>modelToView(int)</code> calls, as the entire bounding box isn't
|
* calls, as the entire bounding box isn't computed.
|
||||||
* computed.
|
|
||||||
*
|
*
|
||||||
* @param alloc
|
* @param alloc The area the text area can render into.
|
||||||
* The area the text area can render into.
|
* @param offs The offset info the document.
|
||||||
* @param offs
|
* @return The y-coordinate of the top of the offset, or <code>-1</code> if this
|
||||||
* The offset info the document.
|
* text area doesn't yet have a positive size or the line is hidden
|
||||||
* @return The y-coordinate of the top of the offset, or <code>-1</code> if
|
* (i.e. from folding).
|
||||||
* this text area doesn't yet have a positive size or the line is
|
* @throws BadLocationException If <code>offs</code> isn't a valid offset into
|
||||||
* hidden (i.e. from folding).
|
* the document.
|
||||||
* @throws BadLocationException
|
|
||||||
* If <code>offs</code> isn't a valid offset
|
|
||||||
* into the document.
|
|
||||||
*/
|
*/
|
||||||
int yForLineContaining(Rectangle alloc, int offs) throws BadLocationException;
|
int yForLineContaining(Rectangle alloc, int offs) throws BadLocationException;
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,7 @@ import me.ByteEdit.edit.JavaAssemblyTokenMaker;
|
|||||||
public class RSyntaxDocument extends RDocument implements Iterable<Token>, SyntaxConstants {
|
public class RSyntaxDocument extends RDocument implements Iterable<Token>, SyntaxConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link TokenMaker} appropriate for a given programming
|
* Creates a {@link TokenMaker} appropriate for a given programming language.
|
||||||
* language.
|
|
||||||
*/
|
*/
|
||||||
private transient TokenMakerFactory tokenMakerFactory;
|
private transient TokenMakerFactory tokenMakerFactory;
|
||||||
/**
|
/**
|
||||||
@@ -64,8 +63,7 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
*/
|
*/
|
||||||
private String syntaxStyle;
|
private String syntaxStyle;
|
||||||
/**
|
/**
|
||||||
* Array of values representing the "last token type" on each line. This is
|
* Array of values representing the "last token type" on each line. This is used
|
||||||
* used
|
|
||||||
* in cases such as multi-line comments: if the previous line ended with an
|
* in cases such as multi-line comments: if the previous line ended with an
|
||||||
* (unclosed) multi-line comment, we can use this knowledge and start the
|
* (unclosed) multi-line comment, we can use this knowledge and start the
|
||||||
* current line's syntax highlighting in multi-line comment state.
|
* current line's syntax highlighting in multi-line comment state.
|
||||||
@@ -77,35 +75,28 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
private transient int tokenRetrievalCount = 0;
|
private transient int tokenRetrievalCount = 0;
|
||||||
private transient Segment s;
|
private transient Segment s;
|
||||||
/**
|
/**
|
||||||
* If this is set to <code>true</code>, debug information about how much
|
* If this is set to <code>true</code>, debug information about how much token
|
||||||
* token
|
|
||||||
* caching is helping is printed to stdout.
|
* caching is helping is printed to stdout.
|
||||||
*/
|
*/
|
||||||
private static final boolean DEBUG_TOKEN_CACHING = false;
|
private static final boolean DEBUG_TOKEN_CACHING = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a plain text document. A default root element is created, and
|
* Constructs a plain text document. A default root element is created, and the
|
||||||
* the
|
|
||||||
* tab size set to 5.
|
* tab size set to 5.
|
||||||
*
|
*
|
||||||
* @param syntaxStyle
|
* @param syntaxStyle The syntax highlighting scheme to use.
|
||||||
* The syntax highlighting scheme to use.
|
|
||||||
*/
|
*/
|
||||||
public RSyntaxDocument(String syntaxStyle) {
|
public RSyntaxDocument(String syntaxStyle) {
|
||||||
this(null, syntaxStyle);
|
this(null, syntaxStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a plain text document. A default root element is created, and
|
* Constructs a plain text document. A default root element is created, and the
|
||||||
* the
|
|
||||||
* tab size set to 5.
|
* tab size set to 5.
|
||||||
*
|
*
|
||||||
* @param tmf
|
* @param tmf The <code>TokenMakerFactory</code> for this document. If
|
||||||
* The <code>TokenMakerFactory</code> for this document. If this
|
* this is <code>null</code>, a default factory is used.
|
||||||
* is
|
* @param syntaxStyle The syntax highlighting scheme to use.
|
||||||
* <code>null</code>, a default factory is used.
|
|
||||||
* @param syntaxStyle
|
|
||||||
* The syntax highlighting scheme to use.
|
|
||||||
*/
|
*/
|
||||||
public RSyntaxDocument(TokenMakerFactory tmf, String syntaxStyle) {
|
public RSyntaxDocument(TokenMakerFactory tmf, String syntaxStyle) {
|
||||||
putProperty(tabSizeAttribute, Integer.valueOf(5));
|
putProperty(tabSizeAttribute, Integer.valueOf(5));
|
||||||
@@ -117,25 +108,21 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alerts all listeners to this document of an insertion. This is overridden
|
* Alerts all listeners to this document of an insertion. This is overridden so
|
||||||
* so
|
|
||||||
* we can update our syntax highlighting stuff.
|
* we can update our syntax highlighting stuff.
|
||||||
* <p>
|
* <p>
|
||||||
* The syntax highlighting stuff has to be here instead of in
|
* The syntax highlighting stuff has to be here instead of in
|
||||||
* <code>insertUpdate</code> because <code>insertUpdate</code> is not called
|
* <code>insertUpdate</code> because <code>insertUpdate</code> is not called by
|
||||||
* by
|
|
||||||
* the undo/redo actions, but this method is.
|
* the undo/redo actions, but this method is.
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e The change.
|
||||||
* The change.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void fireInsertUpdate(DocumentEvent e) {
|
protected void fireInsertUpdate(DocumentEvent e) {
|
||||||
cachedTokenList = null;
|
cachedTokenList = null;
|
||||||
/*
|
/*
|
||||||
* Now that the text is actually inserted into the content and element
|
* Now that the text is actually inserted into the content and element
|
||||||
* structure, we can update our token elements and
|
* structure, we can update our token elements and "last tokens on lines"
|
||||||
* "last tokens on lines"
|
|
||||||
* structure.
|
* structure.
|
||||||
*/
|
*/
|
||||||
Element lineMap = getDefaultRootElement();
|
Element lineMap = getDefaultRootElement();
|
||||||
@@ -176,21 +163,18 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called AFTER the content has been inserted into the
|
* This method is called AFTER the content has been inserted into the document
|
||||||
* document
|
|
||||||
* and the element structure has been updated.
|
* and the element structure has been updated.
|
||||||
* <p>
|
* <p>
|
||||||
* The syntax-highlighting updates need to be done here (as opposed to an
|
* The syntax-highlighting updates need to be done here (as opposed to an
|
||||||
* override of <code>postRemoveUpdate</code>) as this method is called in
|
* override of <code>postRemoveUpdate</code>) as this method is called in
|
||||||
* response to undo/redo events, whereas <code>postRemoveUpdate</code> is
|
* response to undo/redo events, whereas <code>postRemoveUpdate</code> is not.
|
||||||
* not.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Now that the text is actually inserted into the content and element
|
* Now that the text is actually inserted into the content and element
|
||||||
* structure, we can update our token elements and "last tokens on lines"
|
* structure, we can update our token elements and "last tokens on lines"
|
||||||
* structure.
|
* structure.
|
||||||
*
|
*
|
||||||
* @param chng
|
* @param chng The change that occurred.
|
||||||
* The change that occurred.
|
|
||||||
* @see #removeUpdate
|
* @see #removeUpdate
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -245,10 +229,8 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
* Returns the closest {@link TokenTypes "standard" token type} for a given
|
* Returns the closest {@link TokenTypes "standard" token type} for a given
|
||||||
* "internal" token type (e.g. one whose value is <code>< 0</code>).
|
* "internal" token type (e.g. one whose value is <code>< 0</code>).
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type The token type.
|
||||||
* The token type.
|
* @return The closest "standard" token type. If a mapping is not defined for
|
||||||
* @return The closest "standard" token type. If a mapping is not defined
|
|
||||||
* for
|
|
||||||
* this language, then <code>type</code> is returned.
|
* this language, then <code>type</code> is returned.
|
||||||
*/
|
*/
|
||||||
public int getClosestStandardTokenTypeForInternalType(int type) {
|
public int getClosestStandardTokenTypeForInternalType(int type) {
|
||||||
@@ -256,10 +238,8 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether closing markup tags should be automatically completed.
|
* Returns whether closing markup tags should be automatically completed. This
|
||||||
* This
|
* method only returns <code>true</code> if {@link #getLanguageIsMarkup()} also
|
||||||
* method only returns <code>true</code> if {@link #getLanguageIsMarkup()}
|
|
||||||
* also
|
|
||||||
* returns <code>true</code>.
|
* returns <code>true</code>.
|
||||||
*
|
*
|
||||||
* @return Whether markup closing tags should be automatically completed.
|
* @return Whether markup closing tags should be automatically completed.
|
||||||
@@ -274,12 +254,11 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
* Returns whether the current programming language uses curly braces
|
* Returns whether the current programming language uses curly braces
|
||||||
* ('<code>{</code>' and '<code>}</code>') to denote code blocks.
|
* ('<code>{</code>' and '<code>}</code>') to denote code blocks.
|
||||||
*
|
*
|
||||||
* @param languageIndex
|
* @param languageIndex The language index at the offset in question. Since some
|
||||||
* The language index at the offset in question. Since some
|
* <code>TokenMaker</code>s effectively have nested
|
||||||
* <code>TokenMaker</code>s effectively have nested languages
|
* languages (such as JavaScript in HTML), this parameter
|
||||||
* (such
|
* tells the <code>TokenMaker</code> what sub-language to
|
||||||
* as JavaScript in HTML), this parameter tells the
|
* look at.
|
||||||
* <code>TokenMaker</code> what sub-language to look at.
|
|
||||||
* @return Whether curly braces denote code blocks.
|
* @return Whether curly braces denote code blocks.
|
||||||
*/
|
*/
|
||||||
public boolean getCurlyBracesDenoteCodeBlocks(int languageIndex) {
|
public boolean getCurlyBracesDenoteCodeBlocks(int languageIndex) {
|
||||||
@@ -287,8 +266,7 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the current language is a markup language, such as HTML,
|
* Returns whether the current language is a markup language, such as HTML, XML
|
||||||
* XML
|
|
||||||
* or PHP.
|
* or PHP.
|
||||||
*
|
*
|
||||||
* @return Whether the current language is a markup language.
|
* @return Whether the current language is a markup language.
|
||||||
@@ -300,10 +278,8 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
/**
|
/**
|
||||||
* Returns the token type of the last token on the given line.
|
* Returns the token type of the last token on the given line.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The line to inspect.
|
||||||
* The line to inspect.
|
* @return The token type of the last token on the specified line. If the line
|
||||||
* @return The token type of the last token on the specified line. If the
|
|
||||||
* line
|
|
||||||
* is invalid, an exception is thrown.
|
* is invalid, an exception is thrown.
|
||||||
*/
|
*/
|
||||||
public int getLastTokenTypeOnLine(int line) {
|
public int getLastTokenTypeOnLine(int line) {
|
||||||
@@ -311,15 +287,12 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text to place at the beginning and end of a line to "comment"
|
* Returns the text to place at the beginning and end of a line to "comment" it
|
||||||
* it
|
|
||||||
* in this programming language.
|
* in this programming language.
|
||||||
*
|
*
|
||||||
* @return The start and end strings to add to a line to "comment" it out. A
|
* @return The start and end strings to add to a line to "comment" it out. A
|
||||||
* <code>null</code> value for either means there is no string to
|
* <code>null</code> value for either means there is no string to add
|
||||||
* add
|
* for that part. A value of <code>null</code> for the array means this
|
||||||
* for that part. A value of <code>null</code> for the array means
|
|
||||||
* this
|
|
||||||
* language does not support commenting/uncommenting lines.
|
* language does not support commenting/uncommenting lines.
|
||||||
*/
|
*/
|
||||||
public String[] getLineCommentStartAndEnd(int languageIndex) {
|
public String[] getLineCommentStartAndEnd(int languageIndex) {
|
||||||
@@ -327,14 +300,11 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether tokens of the specified type should have "mark
|
* Returns whether tokens of the specified type should have "mark occurrences"
|
||||||
* occurrences"
|
|
||||||
* enabled for the current programming language.
|
* enabled for the current programming language.
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type The token type.
|
||||||
* The token type.
|
* @return Whether tokens of this type should have "mark occurrences" enabled.
|
||||||
* @return Whether tokens of this type should have "mark occurrences"
|
|
||||||
* enabled.
|
|
||||||
*/
|
*/
|
||||||
boolean getMarkOccurrencesOfTokenType(int type) {
|
boolean getMarkOccurrencesOfTokenType(int type) {
|
||||||
return tokenMaker.getMarkOccurrencesOfTokenType(type);
|
return tokenMaker.getMarkOccurrencesOfTokenType(type);
|
||||||
@@ -353,8 +323,7 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
* This method returns whether auto indentation should be done if Enter is
|
* This method returns whether auto indentation should be done if Enter is
|
||||||
* pressed at the end of the specified line.
|
* pressed at the end of the specified line.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The line to check.
|
||||||
* The line to check.
|
|
||||||
* @return Whether an extra indentation should be done.
|
* @return Whether an extra indentation should be done.
|
||||||
*/
|
*/
|
||||||
public boolean getShouldIndentNextLine(int line) {
|
public boolean getShouldIndentNextLine(int line) {
|
||||||
@@ -376,12 +345,10 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
/**
|
/**
|
||||||
* Returns a token list for the specified segment of text representing the
|
* Returns a token list for the specified segment of text representing the
|
||||||
* specified line number. This method is basically a wrapper for
|
* specified line number. This method is basically a wrapper for
|
||||||
* <code>tokenMaker.getTokenList</code> that takes into account the last
|
* <code>tokenMaker.getTokenList</code> that takes into account the last token
|
||||||
* token
|
|
||||||
* on the previous line to assure token accuracy.
|
* on the previous line to assure token accuracy.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The line number of <code>text</code> in the document, >= 0.
|
||||||
* The line number of <code>text</code> in the document, >= 0.
|
|
||||||
* @return A token list representing the specified line.
|
* @return A token list representing the specified line.
|
||||||
*/
|
*/
|
||||||
public final Token getTokenListForLine(int line) {
|
public final Token getTokenListForLine(int line) {
|
||||||
@@ -424,14 +391,11 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a character could be part of an "identifier" token in a
|
* Returns whether a character could be part of an "identifier" token in a
|
||||||
* specific language. This is used to identify such things as the bounds of
|
* specific language. This is used to identify such things as the bounds of the
|
||||||
* the
|
|
||||||
* "word" to select on double-clicking.
|
* "word" to select on double-clicking.
|
||||||
*
|
*
|
||||||
* @param languageIndex
|
* @param languageIndex The language index the character was found in.
|
||||||
* The language index the character was found in.
|
* @param ch The character.
|
||||||
* @param ch
|
|
||||||
* The character.
|
|
||||||
* @return Whether the character could be part of an "identifier" token.
|
* @return Whether the character could be part of an "identifier" token.
|
||||||
*/
|
*/
|
||||||
public boolean isIdentifierChar(int languageIndex, char ch) {
|
public boolean isIdentifierChar(int languageIndex, char ch) {
|
||||||
@@ -439,10 +403,8 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator over the paintable tokens in this document. Results
|
* Returns an iterator over the paintable tokens in this document. Results are
|
||||||
* are
|
* undefined if this document is modified while the iterator is being iterated
|
||||||
* undefined if this document is modified while the iterator is being
|
|
||||||
* iterated
|
|
||||||
* through, so this should only be used on the EDT.
|
* through, so this should only be used on the EDT.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
@@ -459,8 +421,7 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
/**
|
/**
|
||||||
* Deserializes a document.
|
* Deserializes a document.
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in The stream to read from.
|
||||||
* The stream to read from.
|
|
||||||
* @throws ClassNotFoundException
|
* @throws ClassNotFoundException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@@ -478,14 +439,11 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes our private <code>Segment s</code> point to the text in our
|
* Makes our private <code>Segment s</code> point to the text in our document
|
||||||
* document
|
* referenced by the specified element. Note that <code>line</code> MUST be a
|
||||||
* referenced by the specified element. Note that <code>line</code> MUST be
|
|
||||||
* a
|
|
||||||
* valid line number in the document.
|
* valid line number in the document.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The line number you want to get.
|
||||||
* The line number you want to get.
|
|
||||||
*/
|
*/
|
||||||
private void setSharedSegment(int line) {
|
private void setSharedSegment(int line) {
|
||||||
Element map = getDefaultRootElement();
|
Element map = getDefaultRootElement();
|
||||||
@@ -506,17 +464,14 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the syntax style being used for syntax highlighting in this
|
* Sets the syntax style being used for syntax highlighting in this document.
|
||||||
* document.
|
|
||||||
* What styles are supported by a document is determined by its
|
* What styles are supported by a document is determined by its
|
||||||
* {@link TokenMakerFactory}. By default, all <code>RSyntaxDocument</code>s
|
* {@link TokenMakerFactory}. By default, all <code>RSyntaxDocument</code>s
|
||||||
* support all languages built into <code>RSyntaxTextArea</code>.
|
* support all languages built into <code>RSyntaxTextArea</code>.
|
||||||
*
|
*
|
||||||
* @param styleKey
|
* @param styleKey The new style to use, such as
|
||||||
* The new style to use, such as
|
|
||||||
* {@link SyntaxConstants#SYNTAX_STYLE_JAVA}. If this style is
|
* {@link SyntaxConstants#SYNTAX_STYLE_JAVA}. If this style is
|
||||||
* not
|
* not known or supported by this document, then
|
||||||
* known or supported by this document, then
|
|
||||||
* {@link SyntaxConstants#SYNTAX_STYLE_NONE} is used.
|
* {@link SyntaxConstants#SYNTAX_STYLE_NONE} is used.
|
||||||
* @see #setSyntaxStyle(TokenMaker)
|
* @see #setSyntaxStyle(TokenMaker)
|
||||||
* @see #getSyntaxStyle()
|
* @see #getSyntaxStyle()
|
||||||
@@ -532,13 +487,11 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the syntax style being used for syntax highlighting in this
|
* Sets the syntax style being used for syntax highlighting in this document.
|
||||||
* document.
|
|
||||||
* You should call this method if you've created a custom token maker for a
|
* You should call this method if you've created a custom token maker for a
|
||||||
* language not normally supported by <code>RSyntaxTextArea</code>.
|
* language not normally supported by <code>RSyntaxTextArea</code>.
|
||||||
*
|
*
|
||||||
* @param tokenMaker
|
* @param tokenMaker The new token maker to use.
|
||||||
* The new token maker to use.
|
|
||||||
* @see #setSyntaxStyle(String)
|
* @see #setSyntaxStyle(String)
|
||||||
*/
|
*/
|
||||||
public void setSyntaxStyle(TokenMaker tokenMaker) {
|
public void setSyntaxStyle(TokenMaker tokenMaker) {
|
||||||
@@ -550,9 +503,7 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
/**
|
/**
|
||||||
* Sets the token maker factory used by this document.
|
* Sets the token maker factory used by this document.
|
||||||
*
|
*
|
||||||
* @param tmf
|
* @param tmf The <code>TokenMakerFactory</code> for this document. If this is
|
||||||
* The <code>TokenMakerFactory</code> for this document. If this
|
|
||||||
* is
|
|
||||||
* <code>null</code>, a default factory is used.
|
* <code>null</code>, a default factory is used.
|
||||||
*/
|
*/
|
||||||
public void setTokenMakerFactory(TokenMakerFactory tmf) {
|
public void setTokenMakerFactory(TokenMakerFactory tmf) {
|
||||||
@@ -560,20 +511,15 @@ public class RSyntaxDocument extends RDocument implements Iterable<Token>, Synta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loops through the last-tokens-on-lines array from a specified point
|
* Loops through the last-tokens-on-lines array from a specified point onward,
|
||||||
* onward,
|
* updating last-token values until they stop changing. This should be called
|
||||||
* updating last-token values until they stop changing. This should be
|
* when lines are updated/inserted/removed, as doing so may cause lines below to
|
||||||
* called
|
|
||||||
* when lines are updated/inserted/removed, as doing so may cause lines
|
|
||||||
* below to
|
|
||||||
* change color.
|
* change color.
|
||||||
*
|
*
|
||||||
* @param line
|
* @param line The first line to check for a change in last-token
|
||||||
* The first line to check for a change in last-token value.
|
* value.
|
||||||
* @param numLines
|
* @param numLines The number of lines in the document.
|
||||||
* The number of lines in the document.
|
* @param previousTokenType The last-token value of the line just before
|
||||||
* @param previousTokenType
|
|
||||||
* The last-token value of the line just before
|
|
||||||
* <code>line</code>.
|
* <code>line</code>.
|
||||||
* @return The last line that needs repainting.
|
* @return The last line that needs repainting.
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -27,8 +27,8 @@ import org.fife.ui.rtextarea.SmartHighlightPainter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The highlighter implementation used by {@link RSyntaxTextArea}s. It knows to
|
* The highlighter implementation used by {@link RSyntaxTextArea}s. It knows to
|
||||||
* always paint "marked occurrences" highlights below selection highlights,
|
* always paint "marked occurrences" highlights below selection highlights, and
|
||||||
* and squiggle underline highlights above all other highlights.
|
* squiggle underline highlights above all other highlights.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* Most of this code is copied from javax.swing.text.DefaultHighlighter;
|
* Most of this code is copied from javax.swing.text.DefaultHighlighter;
|
||||||
@@ -40,13 +40,13 @@ import org.fife.ui.rtextarea.SmartHighlightPainter;
|
|||||||
public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marked occurrences in the document (to be painted separately from
|
* Marked occurrences in the document (to be painted separately from other
|
||||||
* other highlights).
|
* highlights).
|
||||||
*/
|
*/
|
||||||
private List<SyntaxLayeredHighlightInfoImpl> markedOccurrences;
|
private List<SyntaxLayeredHighlightInfoImpl> markedOccurrences;
|
||||||
/**
|
/**
|
||||||
* Highlights from document parsers. These should be painted "on top of"
|
* Highlights from document parsers. These should be painted "on top of" all
|
||||||
* all other highlights to ensure they are always above the selection.
|
* other highlights to ensure they are always above the selection.
|
||||||
*/
|
*/
|
||||||
private List<SyntaxLayeredHighlightInfoImpl> parserHighlights;
|
private List<SyntaxLayeredHighlightInfoImpl> parserHighlights;
|
||||||
/**
|
/**
|
||||||
@@ -92,8 +92,7 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
/**
|
/**
|
||||||
* Adds a highlight from a parser.
|
* Adds a highlight from a parser.
|
||||||
*
|
*
|
||||||
* @param notice
|
* @param notice The notice from a {@link Parser}.
|
||||||
* The notice from a {@link Parser}.
|
|
||||||
* @return A tag with which to reference the highlight.
|
* @return A tag with which to reference the highlight.
|
||||||
* @throws BadLocationException
|
* @throws BadLocationException
|
||||||
* @see #clearParserHighlights()
|
* @see #clearParserHighlights()
|
||||||
@@ -161,8 +160,7 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
/**
|
/**
|
||||||
* Removes all of the highlights for a specific parser.
|
* Removes all of the highlights for a specific parser.
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser The parser.
|
||||||
* The parser.
|
|
||||||
*/
|
*/
|
||||||
public void clearParserHighlights(Parser parser) {
|
public void clearParserHighlights(Parser parser) {
|
||||||
Iterator<SyntaxLayeredHighlightInfoImpl> i = parserHighlights.iterator();
|
Iterator<SyntaxLayeredHighlightInfoImpl> i = parserHighlights.iterator();
|
||||||
@@ -188,8 +186,8 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of "marked occurrences" in the text area. If there are
|
* Returns a list of "marked occurrences" in the text area. If there are no
|
||||||
* no marked occurrences, this will be an empty list.
|
* marked occurrences, this will be an empty list.
|
||||||
*
|
*
|
||||||
* @return The list of marked occurrences, or an empty list if none. The
|
* @return The list of marked occurrences, or an empty list if none. The
|
||||||
* contents of this list will be of type {@link DocumentRange}.
|
* contents of this list will be of type {@link DocumentRange}.
|
||||||
@@ -212,7 +210,8 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor, View view) {
|
public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd, Shape viewBounds, JTextComponent editor,
|
||||||
|
View view) {
|
||||||
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markedOccurrences);
|
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, markedOccurrences);
|
||||||
super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
|
super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor, view);
|
||||||
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, parserHighlights);
|
paintListLayered(g, lineStart, lineEnd, viewBounds, editor, view, parserHighlights);
|
||||||
@@ -221,8 +220,7 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
/**
|
/**
|
||||||
* Removes a parser highlight from this view.
|
* Removes a parser highlight from this view.
|
||||||
*
|
*
|
||||||
* @param tag
|
* @param tag The reference to the highlight.
|
||||||
* The reference to the highlight.
|
|
||||||
* @see #addParserHighlight(ParserNotice,
|
* @see #addParserHighlight(ParserNotice,
|
||||||
* javax.swing.text.Highlighter.HighlightPainter)
|
* javax.swing.text.Highlighter.HighlightPainter)
|
||||||
*/
|
*/
|
||||||
@@ -232,8 +230,7 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Highlight info implementation used for parser notices and marked
|
* Highlight info implementation used for parser notices and marked occurrences.
|
||||||
* occurrences.
|
|
||||||
*/
|
*/
|
||||||
private static class SyntaxLayeredHighlightInfoImpl extends LayeredHighlightInfoImpl {
|
private static class SyntaxLayeredHighlightInfoImpl extends LayeredHighlightInfoImpl {
|
||||||
|
|
||||||
@@ -255,8 +252,8 @@ public class RSyntaxTextAreaHighlighter extends RTextAreaHighlighter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[SyntaxLayeredHighlightInfoImpl: " + "startOffs=" + getStartOffset() + ", endOffs=" + getEndOffset() + ", color="
|
return "[SyntaxLayeredHighlightInfoImpl: " + "startOffs=" + getStartOffset() + ", endOffs=" + getEndOffset()
|
||||||
+ getColor() + "]";
|
+ ", color=" + getColor() + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loaded 100 of 274 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user