blob: 3b11333aa9a63b9dcb7c8c45c99b53a58e75534a [file] [log] [blame]
package com.jetbrains.python.debugger;
import com.jetbrains.python.console.pydev.AbstractPyCodeCompletion;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import org.jetbrains.annotations.Nullable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Translate XML protocol responses into Py structures.
*
*/
public class PydevXmlUtils {
static SAXParserFactory parserFactory = SAXParserFactory.newInstance();
private PydevXmlUtils() {
}
static SAXParser getSAXParser() throws Exception {
SAXParser parser = null;
synchronized (parserFactory) {
parser = parserFactory.newSAXParser();
}
return parser;
}
@Nullable
private static String decode(String value) {
if (value != null) {
try {
return URLDecoder.decode(value, "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return null;
}
public static List<PydevCompletionVariant> decodeCompletions(Object fromServer, String actTok) {
final List<PydevCompletionVariant> ret = new ArrayList<PydevCompletionVariant>();
List completionList = objectToList(fromServer);
for (Object o : completionList) {
List comp = objectToList(o);
//name, doc, args, type
final int type = extractInt(comp.get(3));
final String args = AbstractPyCodeCompletion.getArgs((String)comp.get(2), type,
AbstractPyCodeCompletion.LOOKING_FOR_INSTANCED_VARIABLE);
String name = (String)comp.get(0);
if (name.contains(".") && name.startsWith(actTok)) {
name = name.substring(actTok.length());
}
ret.add(new PydevCompletionVariant(name, (String)comp.get(1), args, type));
}
return ret;
}
public static List objectToList(Object object) {
List list;
if (object instanceof Collection) {
list = new ArrayList((Collection)object);
}
else if (object instanceof Object[]) {
list = Arrays.asList((Object[])object);
}
else {
throw new IllegalStateException("cant handle type of " + object);
}
return list;
}
/**
* Extracts an int from an object
*
* @param objToGetInt the object that should be gotten as an int
* @return int with the int the object represents
*/
public static int extractInt(Object objToGetInt) {
if (objToGetInt instanceof Integer) {
return (Integer)objToGetInt;
}
return Integer.parseInt(objToGetInt.toString());
}
/**
* Processes CMD_GET_COMPLETIONS return
*/
static class XMLToCompletionsInfo extends DefaultHandler {
private List<Object[]> completions;
public XMLToCompletionsInfo() {
completions = new ArrayList<Object[]>();
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// <comp p0="%s" p1="%s" p2="%s" p3="%s"/>
if (qName.equals("comp")) {
Object[] comp = new Object[]{
decode(attributes.getValue("p0")),
decode(attributes.getValue("p1")),
decode(attributes.getValue("p2")),
decode(attributes.getValue("p3")),
};
completions.add(comp);
}
}
public List<Object[]> getCompletions() {
return completions;
}
}
public static List<PydevCompletionVariant> xmlToCompletions(String payload, String actionToken) throws Exception {
SAXParser parser = getSAXParser();
XMLToCompletionsInfo info = new XMLToCompletionsInfo();
parser.parse(new ByteArrayInputStream(payload.getBytes()), info);
return decodeCompletions(info.getCompletions(), actionToken);
}
}