blob: 5d406e87d510cbb168f09b14b2ad056ee389ce1b [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.codeInsight.stdlib;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiNamedElement;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.documentation.PythonDocumentationLinkProvider;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.sdk.PythonSdkType;
import java.util.List;
/**
* @author yole
*/
public class PyStdlibDocumentationLinkProvider implements PythonDocumentationLinkProvider {
// use tools/stdlib-modindex.py to regenerate the map when new Python versions are released
private static List<String> py2LibraryModules = ImmutableList.of(
"abc",
"aepack",
"aetools",
"aetypes",
"aifc",
"al",
"anydbm",
"argparse",
"array",
"asynchat",
"asyncore",
"atexit",
"audioop",
"autoGIL",
"base64",
"BaseHTTPServer",
"Bastion",
"bdb",
"binascii",
"binhex",
"bisect",
"bsddb",
"bz2",
"calendar",
"cd",
"cgi",
"CGIHTTPServer",
"cgitb",
"chunk",
"cmath",
"cmd",
"code",
"codecs",
"codeop",
"collections",
"ColorPicker",
"colorsys",
"commands",
"compileall",
"ConfigParser",
"contextlib",
"Cookie",
"cookielib",
"copy",
"copy_reg",
"crypt",
"csv",
"ctypes",
"curses.ascii",
"curses.panel",
"curses",
"datetime",
"dbhash",
"dbm",
"decimal",
"difflib",
"dircache",
"dis",
"distutils",
"dl",
"doctest",
"DocXMLRPCServer",
"dumbdbm",
"dummy_thread",
"dummy_threading",
"EasyDialogs",
"email.charset",
"email.encoders",
"email.errors",
"email.generator",
"email.header",
"email.iterators",
"email.message",
"email.mime",
"email.parser",
"email",
"email.utils",
"errno",
"fcntl",
"filecmp",
"fileinput",
"fl",
"fm",
"fnmatch",
"formatter",
"fpectl",
"fpformat",
"fractions",
"FrameWork",
"ftplib",
"functools",
"future_builtins",
"gc",
"gdbm",
"gensuitemodule",
"getopt",
"getpass",
"gettext",
"gl",
"glob",
"grp",
"gzip",
"hashlib",
"heapq",
"hmac",
"hotshot",
"htmllib",
"HTMLParser",
"httplib",
"ic",
"imageop",
"imaplib",
"imgfile",
"imghdr",
"imp",
"importlib",
"imputil",
"inspect",
"io",
"itertools",
"jpeg",
"json",
"keyword",
"linecache",
"locale",
"logging",
"MacOS",
"macostools",
"macpath",
"mailbox",
"mailcap",
"marshal",
"math",
"md5",
"mhlib",
"mimetools",
"mimetypes",
"MimeWriter",
"mimify",
"MiniAEFrame",
"mmap",
"modulefinder",
"msilib",
"msvcrt",
"multifile",
"multiprocessing",
"mutex",
"netrc",
"new",
"nis",
"nntplib",
"numbers",
"operator",
"optparse",
"os.path",
"os",
"ossaudiodev",
"parser",
"pickle",
"pickletools",
"pipes",
"pkgutil",
"platform",
"plistlib",
"popen2",
"poplib",
"posix",
"posixfile",
"pprint",
"pty",
"pwd",
"pyclbr",
"pydoc",
"xml.parsers.expat",
"py_compile",
"Queue",
"quopri",
"random",
"re",
"readline",
"repr",
"resource",
"rexec",
"rfc822",
"rlcompleter",
"robotparser",
"runpy",
"sched",
"ScrolledText",
"select",
"sets",
"sgmllib",
"sha",
"shelve",
"shlex",
"shutil",
"signal",
"SimpleHTTPServer",
"SimpleXMLRPCServer",
"site",
"smtpd",
"smtplib",
"sndhdr",
"socket",
"SocketServer",
"spwd",
"sqlite3",
"ssl",
"stat",
"statvfs",
"string",
"StringIO",
"stringprep",
"struct",
"subprocess",
"sunau",
"sunaudiodev",
"symbol",
"symtable",
"sys",
"sysconfig",
"syslog",
"tabnanny",
"telnetlib",
"tempfile",
"termios",
"test",
"textwrap",
"thread",
"threading",
"time",
"timeit",
"Tix",
"Tkinter",
"token",
"tokenize",
"trace",
"traceback",
"ttk",
"tty",
"types",
"unicodedata",
"unittest",
"urllib",
"urllib2",
"urlparse",
"user",
"UserDict",
"uu",
"uuid",
"warnings",
"wave",
"weakref",
"webbrowser",
"whichdb",
"winsound",
"wsgiref",
"xdrlib",
"xml.dom.minidom",
"xml.dom.pulldom",
"xml.dom",
"xml.etree.ElementTree",
"xml.sax.handler",
"xml.sax.xmlreader",
"xml.sax",
"xml.sax.saxutils",
"xmllib",
"xmlrpclib",
"zipfile",
"zipimport",
"zlib",
"_winreg",
"__builtin__",
"__future__"
);
private static List<String> py3LibraryModules = ImmutableList.of(
"abc",
"aifc",
"argparse",
"array",
"ast",
"asynchat",
"asyncore",
"atexit",
"audioop",
"base64",
"bdb",
"binascii",
"binhex",
"bisect",
"builtins",
"bz2",
"calendar",
"cgi",
"cgitb",
"chunk",
"cmath",
"cmd",
"code",
"codecs",
"codeop",
"collections",
"colorsys",
"compileall",
"concurrent.futures",
"configparser",
"contextlib",
"copy",
"copyreg",
"crypt",
"csv",
"ctypes",
"curses.ascii",
"curses.panel",
"curses",
"datetime",
"dbm",
"decimal",
"difflib",
"dis",
"distutils",
"doctest",
"dummy_threading",
"email.charset",
"email.encoders",
"email.errors",
"email.generator",
"email.header",
"email.iterators",
"email.message",
"email.mime",
"email.parser",
"email",
"email.utils",
"errno",
"fcntl",
"filecmp",
"fileinput",
"fnmatch",
"formatter",
"fpectl",
"fractions",
"ftplib",
"functools",
"gc",
"getopt",
"getpass",
"gettext",
"glob",
"grp",
"gzip",
"hashlib",
"heapq",
"hmac",
"html.entities",
"html.parser",
"html",
"http.client",
"http.cookiejar",
"http.cookies",
"http.server",
"imaplib",
"imghdr",
"imp",
"importlib",
"inspect",
"io",
"itertools",
"json",
"keyword",
"linecache",
"locale",
"logging.config",
"logging.handlers",
"logging",
"macpath",
"mailbox",
"mailcap",
"marshal",
"math",
"mimetypes",
"mmap",
"modulefinder",
"msilib",
"msvcrt",
"multiprocessing",
"netrc",
"nis",
"nntplib",
"numbers",
"operator",
"optparse",
"os.path",
"os",
"ossaudiodev",
"parser",
"pickle",
"pickletools",
"pipes",
"pkgutil",
"platform",
"plistlib",
"poplib",
"posix",
"pprint",
"pty",
"pwd",
"pyclbr",
"pydoc",
"xml.parsers.expat",
"py_compile",
"queue",
"quopri",
"random",
"re",
"readline",
"reprlib",
"resource",
"rlcompleter",
"runpy",
"sched",
"select",
"shelve",
"shlex",
"shutil",
"signal",
"site",
"smtpd",
"smtplib",
"sndhdr",
"socket",
"socketserver",
"spwd",
"sqlite3",
"ssl",
"stat",
"string",
"stringprep",
"struct",
"subprocess",
"sunau",
"symbol",
"symtable",
"sys",
"sysconfig",
"syslog",
"tabnanny",
"tarfile",
"telnetlib",
"tempfile",
"termios",
"test",
"textwrap",
"threading",
"time",
"timeit",
"tkinter",
"tkinter.scrolledtext",
"tkinter.tix",
"tkinter.ttk",
"token",
"tokenize",
"trace",
"traceback",
"tty",
"types",
"unicodedata",
"unittest",
"urllib.error",
"urllib.parse",
"urllib.request",
"urllib.robotparser",
"uu",
"uuid",
"warnings",
"wave",
"weakref",
"webbrowser",
"winreg",
"winsound",
"wsgiref",
"xdrlib",
"xml.dom.minidom",
"xml.dom.pulldom",
"xml.dom",
"xml.etree.ElementTree",
"xml.sax.handler",
"xml.sax.xmlreader",
"xml.sax",
"xml.sax.saxutils",
"xmlrpc.client",
"xmlrpc.server",
"zipfile",
"zipimport",
"zlib",
"_dummy_thread",
"_thread",
"__future__"
);
@Override
public String getExternalDocumentationUrl(PsiElement element, PsiElement originalElement) {
PsiFileSystemItem file = element instanceof PsiFileSystemItem ? (PsiFileSystemItem) element : element.getContainingFile();
if (PyNames.INIT_DOT_PY.equals(file.getName())) {
file = file.getParent();
assert file != null;
}
Sdk sdk = PyBuiltinCache.findSdkForFile(file);
VirtualFile vFile = file.getVirtualFile();
if (vFile != null && sdk != null && PythonSdkType.isStdLib(vFile, sdk)) {
QualifiedName qName = QualifiedNameFinder.findCanonicalImportPath(element, originalElement);
return getStdlibUrlFor(element, qName, sdk);
}
return null;
}
@Override
public String getExternalDocumentationRoot(Sdk sdk) {
final String versionString = sdk.getVersionString();
if (versionString != null && StringUtil.startsWithIgnoreCase(versionString, "jython")) {
return "http://jython.org/docs/library/";
}
final String pyVersion = PythonDocumentationProvider.pyVersion(versionString);
StringBuilder urlBuilder = new StringBuilder("http://docs.python.org/");
if (pyVersion != null) {
urlBuilder.append(pyVersion).append("/");
}
if (pyVersion != null && (pyVersion.startsWith("2.4") || pyVersion.startsWith("2.5"))) {
urlBuilder.append("lib/");
}
else {
urlBuilder.append("library/");
}
return urlBuilder.toString();
}
private String getStdlibUrlFor(PsiElement element, QualifiedName moduleName, Sdk sdk) {
StringBuilder urlBuilder = new StringBuilder(getExternalDocumentationRoot(sdk));
String qnameString = moduleName.toString();
if (qnameString.equals("ntpath") || qnameString.equals("posixpath")) {
qnameString = "os.path";
}
else if (qnameString.equals("nt")) {
qnameString = "os";
}
else if (qnameString.equals("cPickle")) {
qnameString = "pickle";
}
else if (qnameString.equals("pyexpat")) {
qnameString = "xml.parsers.expat";
}
final String pyVersion = PythonDocumentationProvider.pyVersion(sdk.getVersionString());
List<String> modules = pyVersion != null && pyVersion.startsWith("3") ? py3LibraryModules : py2LibraryModules;
boolean foundModule = false;
for (String module : modules) {
if (qnameString.startsWith(module)) {
urlBuilder.append(module.toLowerCase());
urlBuilder.append(".html");
foundModule = true;
break;
}
}
if (foundModule && element instanceof PsiNamedElement && !(element instanceof PyFile)) {
urlBuilder.append('#').append(moduleName).append(".");
if (element instanceof PyFunction) {
final PyClass containingClass = ((PyFunction)element).getContainingClass();
if (containingClass != null) {
urlBuilder.append(containingClass.getName()).append('.');
}
}
urlBuilder.append(((PsiNamedElement)element).getName());
}
return urlBuilder.toString();
}
}