From 7b12c18fffc1ec64bfc33c2936f78fddd8ba6976 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 02:43:44 +0200 Subject: [PATCH 01/69] Fix test. --- python/helpers/pydev/pydevd_frame.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 5d1e78458391..a379b966e20d 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -48,6 +48,7 @@ class PyDBFrame: #args = mainDebugger, filename, base, info, t, frame #yeap, much faster than putting in self and then getting it from self later on self._args = args[:-1] + self._cached_is_django_render_call = None def setSuspend(self, *args, **kwargs): self._args[0].setSuspend(*args, **kwargs) @@ -56,15 +57,14 @@ class PyDBFrame: self._args[0].doWaitSuspend(*args, **kwargs) def _is_django_render_call(self, frame): - try: - return self._cached_is_django_render_call - except: + if self._cached_is_django_render_call is None: # Calculate lazily: note that a PyDBFrame always deals with the same # frame over and over, so, we can cache this. # -- although we can't cache things which change over time (such as # the breakpoints for the file). - ret = self._cached_is_django_render_call = is_django_render_call(frame) - return ret + self._cached_is_django_render_call = is_django_render_call(frame) + + return self._cached_is_django_render_call def trace_exception(self, frame, event, arg): if event == 'exception': @@ -505,7 +505,7 @@ class PyDBFrame: stop = False if django_stop: - frame = suspend_django(self, main_debugger, thread, frame) + frame = suspend_django(self, main_debugger, thread, frame, step_cmd) if frame: self.doWaitSuspend(thread, frame, event, arg) elif stop: From 2de62bccda1150a1e0c60504eb7bfd42b094882a Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 09:06:57 +0200 Subject: [PATCH 02/69] Exit on stop from debug reader. --- .../jetbrains/python/debugger/pydev/RemoteDebugger.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 8048a7b62a54..8577b13b8d03 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -453,7 +453,6 @@ public class RemoteDebugger implements ProcessDebugger { } private class DebuggerReader extends BaseOutputReader { - private boolean myClosing = false; private Reader myReader; private DebuggerReader(final Reader reader) throws IOException { @@ -467,7 +466,7 @@ public class RemoteDebugger implements ProcessDebugger { while (true) { boolean read = readAvailable(); - if (myClosing) { + if (isStopped) { break; } @@ -478,7 +477,7 @@ public class RemoteDebugger implements ProcessDebugger { fireCommunicationError(); } finally { - closeReader(myReader); + close(); fireExitEvent(); } } @@ -593,7 +592,7 @@ public class RemoteDebugger implements ProcessDebugger { } public void close() { - myClosing = true; + closeReader(myReader); } @Override From 1f63b465a4cfbcff6b34903c2108321869ae443b Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 09:06:57 +0200 Subject: [PATCH 03/69] Call stop instead of close. --- .../com/jetbrains/python/debugger/pydev/RemoteDebugger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 8577b13b8d03..b30db9963715 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -368,7 +368,7 @@ public class RemoteDebugger implements ProcessDebugger { } } if (myDebuggerReader != null) { - myDebuggerReader.close(); + myDebuggerReader.stop(); } fireCloseEvent(); } From 8e6b371bc9d3609f6c64ad4fb96471a974220766 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 09:06:57 +0200 Subject: [PATCH 04/69] Close on stop. --- .../com/jetbrains/python/debugger/pydev/RemoteDebugger.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index b30db9963715..0ea5abed9d4a 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -595,6 +595,12 @@ public class RemoteDebugger implements ProcessDebugger { closeReader(myReader); } + @Override + public void stop() { + super.stop(); + close(); + } + @Override protected void onTextAvailable(@NotNull String text) { processResponse(text); From b4870f4ab82ddaa023aa123bfa26e33fc5d0b180 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 20:26:05 +0200 Subject: [PATCH 05/69] Merged in template debugging refactoring and Jinja2 templates (@author elizaveta.shashkova). --- python/helpers/pydev/pkgutil_old.py | 591 ++++++++++++++++++ python/helpers/pydev/pluginbase.py | 453 ++++++++++++++ python/helpers/pydev/pydevd.py | 209 +++++-- python/helpers/pydev/pydevd_constants.py | 1 + python/helpers/pydev/pydevd_frame.py | 222 +++---- python/helpers/pydev/pydevd_frame_utils.py | 6 +- .../helpers/pydev/pydevd_plugins/__init__.py | 0 .../pydev/pydevd_plugins/django_debug.py | 375 +++++++++++ .../pydev/pydevd_plugins/jinja2_debug.py | 347 ++++++++++ python/helpers/pydev/test_debug.py | 4 +- .../helpers/pydev/tests/check_pydevconsole.py | 110 ++++ .../pydev/tests/test_pydev_ipython_010.py | 80 +++ python/helpers/pydev/uuid_old.py | 541 ++++++++++++++++ 13 files changed, 2752 insertions(+), 187 deletions(-) create mode 100644 python/helpers/pydev/pkgutil_old.py create mode 100644 python/helpers/pydev/pluginbase.py create mode 100644 python/helpers/pydev/pydevd_plugins/__init__.py create mode 100644 python/helpers/pydev/pydevd_plugins/django_debug.py create mode 100644 python/helpers/pydev/pydevd_plugins/jinja2_debug.py create mode 100644 python/helpers/pydev/tests/check_pydevconsole.py create mode 100644 python/helpers/pydev/tests/test_pydev_ipython_010.py create mode 100644 python/helpers/pydev/uuid_old.py diff --git a/python/helpers/pydev/pkgutil_old.py b/python/helpers/pydev/pkgutil_old.py new file mode 100644 index 000000000000..ce072ec9ef75 --- /dev/null +++ b/python/helpers/pydev/pkgutil_old.py @@ -0,0 +1,591 @@ +"""Utilities to support packages.""" + +# NOTE: This module must remain compatible with Python 2.3, as it is shared +# by setuptools for distribution with Python 2.3 and up. + +import os +import sys +import imp +import os.path +from types import ModuleType + +__all__ = [ + 'get_importer', 'iter_importers', 'get_loader', 'find_loader', + 'walk_packages', 'iter_modules', 'get_data', + 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path', +] + +def read_code(stream): + # This helper is needed in order for the PEP 302 emulation to + # correctly handle compiled files + import marshal + + magic = stream.read(4) + if magic != imp.get_magic(): + return None + + stream.read(4) # Skip timestamp + return marshal.load(stream) + + +def simplegeneric(func): + """Make a trivial single-dispatch generic function""" + registry = {} + def wrapper(*args, **kw): + ob = args[0] + try: + cls = ob.__class__ + except AttributeError: + cls = type(ob) + try: + mro = cls.__mro__ + except AttributeError: + try: + class cls(cls, object): + pass + mro = cls.__mro__[1:] + except TypeError: + mro = object, # must be an ExtensionClass or some such :( + for t in mro: + if t in registry: + return registry[t](*args, **kw) + else: + return func(*args, **kw) + try: + wrapper.__name__ = func.__name__ + except (TypeError, AttributeError): + pass # Python 2.3 doesn't allow functions to be renamed + + def register(typ, func=None): + if func is None: + return lambda f: register(typ, f) + registry[typ] = func + return func + + wrapper.__dict__ = func.__dict__ + wrapper.__doc__ = func.__doc__ + wrapper.register = register + return wrapper + + +def walk_packages(path=None, prefix='', onerror=None): + """Yields (module_loader, name, ispkg) for all modules recursively + on path, or, if path is None, all accessible modules. + + 'path' should be either None or a list of paths to look for + modules in. + + 'prefix' is a string to output on the front of every module name + on output. + + Note that this function must import all *packages* (NOT all + modules!) on the given path, in order to access the __path__ + attribute to find submodules. + + 'onerror' is a function which gets called with one argument (the + name of the package which was being imported) if any exception + occurs while trying to import a package. If no onerror function is + supplied, ImportErrors are caught and ignored, while all other + exceptions are propagated, terminating the search. + + Examples: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__+'.') + """ + + def seen(p, m={}): + if p in m: + return True + m[p] = True + + for importer, name, ispkg in iter_modules(path, prefix): + yield importer, name, ispkg + + if ispkg: + try: + __import__(name) + except ImportError: + if onerror is not None: + onerror(name) + except Exception: + if onerror is not None: + onerror(name) + else: + raise + else: + path = getattr(sys.modules[name], '__path__', None) or [] + + # don't traverse path items we've seen before + path = [p for p in path if not seen(p)] + + for item in walk_packages(path, name+'.', onerror): + yield item + + +def iter_modules(path=None, prefix=''): + """Yields (module_loader, name, ispkg) for all submodules on path, + or, if path is None, all top-level modules on sys.path. + + 'path' should be either None or a list of paths to look for + modules in. + + 'prefix' is a string to output on the front of every module name + on output. + """ + + if path is None: + importers = iter_importers() + else: + importers = map(get_importer, path) + + yielded = {} + for i in importers: + for name, ispkg in iter_importer_modules(i, prefix): + if name not in yielded: + yielded[name] = 1 + yield i, name, ispkg + + +#@simplegeneric +def iter_importer_modules(importer, prefix=''): + if not hasattr(importer, 'iter_modules'): + return [] + return importer.iter_modules(prefix) + +iter_importer_modules = simplegeneric(iter_importer_modules) + + +class ImpImporter: + """PEP 302 Importer that wraps Python's "classic" import algorithm + + ImpImporter(dirname) produces a PEP 302 importer that searches that + directory. ImpImporter(None) produces a PEP 302 importer that searches + the current sys.path, plus any modules that are frozen or built-in. + + Note that ImpImporter does not currently support being used by placement + on sys.meta_path. + """ + + def __init__(self, path=None): + self.path = path + + def find_module(self, fullname, path=None): + # Note: we ignore 'path' argument since it is only used via meta_path + subname = fullname.split(".")[-1] + if subname != fullname and self.path is None: + return None + if self.path is None: + path = None + else: + path = [os.path.realpath(self.path)] + try: + file, filename, etc = imp.find_module(subname, path) + except ImportError: + return None + return ImpLoader(fullname, file, filename, etc) + + def iter_modules(self, prefix=''): + if self.path is None or not os.path.isdir(self.path): + return + + yielded = {} + import inspect + try: + filenames = os.listdir(self.path) + except OSError: + # ignore unreadable directories like import does + filenames = [] + filenames.sort() # handle packages before same-named modules + + for fn in filenames: + modname = inspect.getmodulename(fn) + if modname=='__init__' or modname in yielded: + continue + + path = os.path.join(self.path, fn) + ispkg = False + + if not modname and os.path.isdir(path) and '.' not in fn: + modname = fn + try: + dircontents = os.listdir(path) + except OSError: + # ignore unreadable directories like import does + dircontents = [] + for fn in dircontents: + subname = inspect.getmodulename(fn) + if subname=='__init__': + ispkg = True + break + else: + continue # not a package + + if modname and '.' not in modname: + yielded[modname] = 1 + yield prefix + modname, ispkg + + +class ImpLoader: + """PEP 302 Loader that wraps Python's "classic" import algorithm + """ + code = source = None + + def __init__(self, fullname, file, filename, etc): + self.file = file + self.filename = filename + self.fullname = fullname + self.etc = etc + + def load_module(self, fullname): + self._reopen() + try: + mod = imp.load_module(fullname, self.file, self.filename, self.etc) + finally: + if self.file: + self.file.close() + # Note: we don't set __loader__ because we want the module to look + # normal; i.e. this is just a wrapper for standard import machinery + return mod + + def get_data(self, pathname): + return open(pathname, "rb").read() + + def _reopen(self): + if self.file and self.file.closed: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + self.file = open(self.filename, 'rU') + elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION): + self.file = open(self.filename, 'rb') + + def _fix_name(self, fullname): + if fullname is None: + fullname = self.fullname + elif fullname != self.fullname: + raise ImportError("Loader for module %s cannot handle " + "module %s" % (self.fullname, fullname)) + return fullname + + def is_package(self, fullname): + fullname = self._fix_name(fullname) + return self.etc[2]==imp.PKG_DIRECTORY + + def get_code(self, fullname=None): + fullname = self._fix_name(fullname) + if self.code is None: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + source = self.get_source(fullname) + self.code = compile(source, self.filename, 'exec') + elif mod_type==imp.PY_COMPILED: + self._reopen() + try: + self.code = read_code(self.file) + finally: + self.file.close() + elif mod_type==imp.PKG_DIRECTORY: + self.code = self._get_delegate().get_code() + return self.code + + def get_source(self, fullname=None): + fullname = self._fix_name(fullname) + if self.source is None: + mod_type = self.etc[2] + if mod_type==imp.PY_SOURCE: + self._reopen() + try: + self.source = self.file.read() + finally: + self.file.close() + elif mod_type==imp.PY_COMPILED: + if os.path.exists(self.filename[:-1]): + f = open(self.filename[:-1], 'rU') + self.source = f.read() + f.close() + elif mod_type==imp.PKG_DIRECTORY: + self.source = self._get_delegate().get_source() + return self.source + + + def _get_delegate(self): + return ImpImporter(self.filename).find_module('__init__') + + def get_filename(self, fullname=None): + fullname = self._fix_name(fullname) + mod_type = self.etc[2] + if self.etc[2]==imp.PKG_DIRECTORY: + return self._get_delegate().get_filename() + elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + return self.filename + return None + + +try: + import zipimport + from zipimport import zipimporter + + def iter_zipimport_modules(importer, prefix=''): + dirlist = zipimport._zip_directory_cache[importer.archive].keys() + dirlist.sort() + _prefix = importer.prefix + plen = len(_prefix) + yielded = {} + import inspect + for fn in dirlist: + if not fn.startswith(_prefix): + continue + + fn = fn[plen:].split(os.sep) + + if len(fn)==2 and fn[1].startswith('__init__.py'): + if fn[0] not in yielded: + yielded[fn[0]] = 1 + yield fn[0], True + + if len(fn)!=1: + continue + + modname = inspect.getmodulename(fn[0]) + if modname=='__init__': + continue + + if modname and '.' not in modname and modname not in yielded: + yielded[modname] = 1 + yield prefix + modname, False + + iter_importer_modules.register(zipimporter, iter_zipimport_modules) + +except ImportError: + pass + + +def get_importer(path_item): + """Retrieve a PEP 302 importer for the given path item + + The returned importer is cached in sys.path_importer_cache + if it was newly created by a path hook. + + If there is no importer, a wrapper around the basic import + machinery is returned. This wrapper is never inserted into + the importer cache (None is inserted instead). + + The cache (or part of it) can be cleared manually if a + rescan of sys.path_hooks is necessary. + """ + try: + importer = sys.path_importer_cache[path_item] + except KeyError: + for path_hook in sys.path_hooks: + try: + importer = path_hook(path_item) + break + except ImportError: + pass + else: + importer = None + sys.path_importer_cache.setdefault(path_item, importer) + + if importer is None: + try: + importer = ImpImporter(path_item) + except ImportError: + importer = None + return importer + + +def iter_importers(fullname=""): + """Yield PEP 302 importers for the given module name + + If fullname contains a '.', the importers will be for the package + containing fullname, otherwise they will be importers for sys.meta_path, + sys.path, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side + effect of invoking this function. + + Non PEP 302 mechanisms (e.g. the Windows registry) used by the + standard import machinery to find files in alternative locations + are partially supported, but are searched AFTER sys.path. Normally, + these locations are searched BEFORE sys.path, preventing sys.path + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must + be a module or package name that is accessible via both sys.path + and one of the non PEP 302 file system mechanisms. In this case, + the emulation will find the former version, while the builtin + import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY + """ + if fullname.startswith('.'): + raise ImportError("Relative module names not supported") + if '.' in fullname: + # Get the containing package's __path__ + pkg = '.'.join(fullname.split('.')[:-1]) + if pkg not in sys.modules: + __import__(pkg) + path = getattr(sys.modules[pkg], '__path__', None) or [] + else: + for importer in sys.meta_path: + yield importer + path = sys.path + for item in path: + yield get_importer(item) + if '.' not in fullname: + yield ImpImporter() + +def get_loader(module_or_name): + """Get a PEP 302 "loader" object for module_or_name + + If the module or package is accessible via the normal import + mechanism, a wrapper around the relevant part of that machinery + is returned. Returns None if the module cannot be found or imported. + If the named module is not already imported, its containing package + (if any) is imported, in order to establish the package __path__. + + This function uses iter_importers(), and is thus subject to the same + limitations regarding platform-specific special import locations such + as the Windows registry. + """ + if module_or_name in sys.modules: + module_or_name = sys.modules[module_or_name] + if isinstance(module_or_name, ModuleType): + module = module_or_name + loader = getattr(module, '__loader__', None) + if loader is not None: + return loader + fullname = module.__name__ + else: + fullname = module_or_name + return find_loader(fullname) + +def find_loader(fullname): + """Find a PEP 302 "loader" object for fullname + + If fullname contains dots, path must be the containing package's __path__. + Returns None if the module cannot be found or imported. This function uses + iter_importers(), and is thus subject to the same limitations regarding + platform-specific special import locations such as the Windows registry. + """ + for importer in iter_importers(fullname): + loader = importer.find_module(fullname) + if loader is not None: + return loader + + return None + + +def extend_path(path, name): + """Extend a package's path. + + Intended use is to place the following code in a package's __init__.py: + + from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) + + This will add to the package's __path__ all subdirectories of + directories on sys.path named after the package. This is useful + if one wants to distribute different parts of a single logical + package as multiple directories. + + It also looks for *.pkg files beginning where * matches the name + argument. This feature is similar to *.pth files (see site.py), + except that it doesn't special-case lines starting with 'import'. + A *.pkg file is trusted at face value: apart from checking for + duplicates, all entries found in a *.pkg file are added to the + path, regardless of whether they are exist the filesystem. (This + is a feature.) + + If the input path is not a list (as is the case for frozen + packages) it is returned unchanged. The input path is not + modified; an extended copy is returned. Items are only appended + to the copy at the end. + + It is assumed that sys.path is a sequence. Items of sys.path that + are not (unicode or 8-bit) strings referring to existing + directories are ignored. Unicode items of sys.path that cause + errors when used as filenames may cause this function to raise an + exception (in line with os.path.isdir() behavior). + """ + + if not isinstance(path, list): + # This could happen e.g. when this is called from inside a + # frozen package. Return the path unchanged in that case. + return path + + pname = os.path.join(*name.split('.')) # Reconstitute as relative path + # Just in case os.extsep != '.' + sname = os.extsep.join(name.split('.')) + sname_pkg = sname + os.extsep + "pkg" + init_py = "__init__" + os.extsep + "py" + + path = path[:] # Start with a copy of the existing path + + for dir in sys.path: + if not isinstance(dir, basestring) or not os.path.isdir(dir): + continue + subdir = os.path.join(dir, pname) + # XXX This may still add duplicate entries to path on + # case-insensitive filesystems + initfile = os.path.join(subdir, init_py) + if subdir not in path and os.path.isfile(initfile): + path.append(subdir) + # XXX Is this the right thing for subpackages like zope.app? + # It looks for a file named "zope.app.pkg" + pkgfile = os.path.join(dir, sname_pkg) + if os.path.isfile(pkgfile): + try: + f = open(pkgfile) + except IOError, msg: + sys.stderr.write("Can't open %s: %s\n" % + (pkgfile, msg)) + else: + for line in f: + line = line.rstrip('\n') + if not line or line.startswith('#'): + continue + path.append(line) # Don't check for existence! + f.close() + + return path + +def get_data(package, resource): + """Get a resource from a package. + + This is a wrapper round the PEP 302 loader get_data API. The package + argument should be the name of a package, in standard module format + (foo.bar). The resource argument should be in the form of a relative + filename, using '/' as the path separator. The parent directory name '..' + is not allowed, and nor is a rooted name (starting with a '/'). + + The function returns a binary string, which is the contents of the + specified resource. + + For packages located in the filesystem, which have already been imported, + this is the rough equivalent of + + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() + + If the package cannot be located or loaded, or it uses a PEP 302 loader + which does not support get_data(), then None is returned. + """ + + loader = get_loader(package) + if loader is None or not hasattr(loader, 'get_data'): + return None + mod = sys.modules.get(package) or loader.load_module(package) + if mod is None or not hasattr(mod, '__file__'): + return None + + # Modify the resource name to be compatible with the loader.get_data + # signature - an os.path format "filename" starting with the dirname of + # the package's __file__ + parts = resource.split('/') + parts.insert(0, os.path.dirname(mod.__file__)) + resource_name = os.path.join(*parts) + return loader.get_data(resource_name) diff --git a/python/helpers/pydev/pluginbase.py b/python/helpers/pydev/pluginbase.py new file mode 100644 index 000000000000..b80d3e124414 --- /dev/null +++ b/python/helpers/pydev/pluginbase.py @@ -0,0 +1,453 @@ +# -*- coding: utf-8 -*- +""" + pluginbase + ~~~~~~~~~~ + + Pluginbase is a module for Python that provides a system for building + plugin based applications. + + :copyright: (c) Copyright 2014 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import os +import sys + +from pydevd_constants import IS_PY24, IS_PY27, IS_PY3K + +if IS_PY24: + from uuid_old import uuid4 +else: + from uuid import uuid4 + +if IS_PY3K: + import pkgutil +else: + import pkgutil_old as pkgutil + +import errno +try: + from hashlib import md5 +except ImportError: + from md5 import md5 +import threading + +from types import ModuleType +from weakref import ref as weakref + + +PY2 = sys.version_info[0] == 2 +if PY2: + text_type = unicode + string_types = (unicode, str) + from cStringIO import StringIO as NativeBytesIO +else: + text_type = str + string_types = (str,) + from io import BytesIO as NativeBytesIO + + +_local = threading.local() + +_internalspace = ModuleType(__name__ + '._internalspace') +_internalspace.__path__ = [] +sys.modules[_internalspace.__name__] = _internalspace + + +def get_plugin_source(module=None, stacklevel=None): + """Returns the :class:`PluginSource` for the current module or the given + module. The module can be provided by name (in which case an import + will be attempted) or as a module object. + + If no plugin source can be discovered, the return value from this method + is `None`. + + This function can be very useful if additional data has been attached + to the plugin source. For instance this could allow plugins to get + access to a back reference to the application that created them. + + :param module: optionally the module to locate the plugin source of. + :param stacklevel: defines how many levels up the module should search + for before it discovers the plugin frame. The + default is 0. This can be useful for writing wrappers + around this function. + """ + if module is None: + frm = sys._getframe((stacklevel or 0) + 1) + name = frm.f_globals['__name__'] + glob = frm.f_globals + elif isinstance(module, string_types): + frm = sys._getframe(1) + name = module + glob = __import__(module, frm.f_globals, + frm.f_locals, ['__dict__']).__dict__ + else: + name = module.__name__ + glob = module.__dict__ + return _discover_space(name, glob) + + +def _discover_space(name, globals): + try: + return _local.space_stack[-1] + except (AttributeError, IndexError): + pass + + if '__pluginbase_state__' in globals: + return globals['__pluginbase_state__'].source + + mod_name = globals.get('__name__') + if mod_name is not None and \ + mod_name.startswith(_internalspace.__name__ + '.'): + end = mod_name.find('.', len(_internalspace.__name__) + 1) + space = sys.modules.get(mod_name[:end]) + if space is not None: + return space.__pluginbase_state__.source + + +def _shutdown_module(mod): + members = list(mod.__dict__.items()) + for key, value in members: + if key[:1] != '_': + setattr(mod, key, None) + for key, value in members: + setattr(mod, key, None) + + +def _to_bytes(s): + if isinstance(s, text_type): + return s.encode('utf-8') + return s + + +class _IntentionallyEmptyModule(ModuleType): + + def __getattr__(self, name): + try: + return ModuleType.__getattr__(self, name) + except AttributeError: + if name[:2] == '__': + raise + raise RuntimeError( + 'Attempted to import from a plugin base module (%s) without ' + 'having a plugin source activated. To solve this error ' + 'you have to move the import into a "with" block of the ' + 'associated plugin source.' % self.__name__) + + +class _PluginSourceModule(ModuleType): + + def __init__(self, source): + modname = '%s.%s' % (_internalspace.__name__, source.spaceid) + ModuleType.__init__(self, modname) + self.__pluginbase_state__ = PluginBaseState(source) + + @property + def __path__(self): + try: + ps = self.__pluginbase_state__.source + except AttributeError: + return [] + return ps.searchpath + ps.base.searchpath + + +def _setup_base_package(module_name): + try: + mod = __import__(module_name, None, None, ['__name__']) + except ImportError: + mod = None + if '.' in module_name: + parent_mod = __import__(module_name.rsplit('.', 1)[0], + None, None, ['__name__']) + else: + parent_mod = None + + if mod is None: + mod = _IntentionallyEmptyModule(module_name) + if parent_mod is not None: + setattr(parent_mod, module_name.rsplit('.', 1)[-1], mod) + sys.modules[module_name] = mod + + +class PluginBase(object): + """The plugin base acts as a control object around a dummy Python + package that acts as a container for plugins. Usually each + application creates exactly one base object for all plugins. + + :param package: the name of the package that acts as the plugin base. + Usually this module does not exist. Unless you know + what you are doing you should not create this module + on the file system. + :param searchpath: optionally a shared search path for modules that + will be used by all plugin sources registered. + """ + + def __init__(self, package, searchpath=None): + #: the name of the dummy package. + self.package = package + if searchpath is None: + searchpath = [] + #: the default search path shared by all plugins as list. + self.searchpath = searchpath + _setup_base_package(package) + + def make_plugin_source(self, *args, **kwargs): + """Creats a plugin source for this plugin base and returns it. + All parameters are forwarded to :class:`PluginSource`. + """ + return PluginSource(self, *args, **kwargs) + + +class PluginSource(object): + """The plugin source is what ultimately decides where plugins are + loaded from. Plugin bases can have multiple plugin sources which act + as isolation layer. While this is not a security system it generally + is not possible for plugins from different sources to accidentally + cross talk. + + Once a plugin source has been created it can be used in a ``with`` + statement to change the behavior of the ``import`` statement in the + block to define which source to load the plugins from:: + + plugin_source = plugin_base.make_plugin_source( + searchpath=['./path/to/plugins', './path/to/more/plugins']) + + with plugin_source: + from myapplication.plugins import my_plugin + + :param base: the base this plugin source belongs to. + :param identifier: optionally a stable identifier. If it's not defined + a random identifier is picked. It's useful to set this + to a stable value to have consistent tracebacks + between restarts and to support pickle. + :param searchpath: a list of paths where plugins are looked for. + :param persist: optionally this can be set to `True` and the plugins + will not be cleaned up when the plugin source gets + garbage collected. + """ + # Set these here to false by default so that a completely failing + # constructor does not fuck up the destructor. + persist = False + mod = None + + def __init__(self, base, identifier=None, searchpath=None, + persist=False): + #: indicates if this plugin source persists or not. + self.persist = persist + if identifier is None: + identifier = str(uuid4()) + #: the identifier for this source. + self.identifier = identifier + #: A reference to the plugin base that created this source. + self.base = base + #: a list of paths where plugins are searched in. + self.searchpath = searchpath + #: The internal module name of the plugin source as it appears + #: in the :mod:`pluginsource._internalspace`. + div = None + self.spaceid = '_sp' + md5( + _to_bytes(self.base.package) + _to_bytes('|') + + _to_bytes(self.identifier) + ).hexdigest() + #: a reference to the module on the internal + #: :mod:`pluginsource._internalspace`. + self.mod = _PluginSourceModule(self) + + if hasattr(_internalspace, self.spaceid): + raise RuntimeError('This plugin source already exists.') + sys.modules[self.mod.__name__] = self.mod + setattr(_internalspace, self.spaceid, self.mod) + + def __del__(self): + if not self.persist: + self.cleanup() + + def list_plugins(self): + """Returns a sorted list of all plugins that are available in this + plugin source. This can be useful to automatically discover plugins + that are available and is usually used together with + :meth:`load_plugin`. + """ + rv = [] + for _, modname, ispkg in pkgutil.iter_modules(self.mod.__path__): + rv.append(modname) + return sorted(rv) + + def load_plugin(self, name): + """This automatically loads a plugin by the given name from the + current source and returns the module. This is a convenient + alternative to the import statement and saves you from invoking + ``__import__`` or a similar function yourself. + + :param name: the name of the plugin to load. + """ + if '.' in name: + raise ImportError('Plugin names cannot contain dots.') + + #with self: + # return __import__(self.base.package + '.' + name, + # globals(), {}, ['__name__']) + + self.__assert_not_cleaned_up() + _local.__dict__.setdefault('space_stack', []).append(self) + try: + res = __import__(self.base.package + '.' + name, + globals(), {}, ['__name__']) + return res + finally: + try: + _local.space_stack.pop() + except (AttributeError, IndexError): + pass + + def open_resource(self, plugin, filename): + """This function locates a resource inside the plugin and returns + a byte stream to the contents of it. If the resource cannot be + loaded an :exc:`IOError` will be raised. Only plugins that are + real Python packages can contain resources. Plain old Python + modules do not allow this for obvious reasons. + + .. versionadded:: 0.3 + + :param plugin: the name of the plugin to open the resource of. + :param filename: the name of the file within the plugin to open. + """ + mod = self.load_plugin(plugin) + fn = getattr(mod, '__file__', None) + if fn is not None: + if fn.endswith(('.pyc', '.pyo')): + fn = fn[:-1] + if os.path.isfile(fn): + return open(os.path.join(os.path.dirname(fn), filename), 'rb') + buf = pkgutil.get_data(self.mod.__name__ + '.' + plugin, filename) + if buf is None: + raise IOError(errno.ENOEXITS, 'Could not find resource') + return NativeBytesIO(buf) + + def cleanup(self): + """Cleans up all loaded plugins manually. This is necessary to + call only if :attr:`persist` is enabled. Otherwise this happens + automatically when the source gets garbage collected. + """ + self.__cleanup() + + def __cleanup(self, _sys=sys, _shutdown_module=_shutdown_module): + # The default parameters are necessary because this can be fired + # from the destructor and so late when the interpreter shuts down + # that these functions and modules might be gone. + if self.mod is None: + return + modname = self.mod.__name__ + self.mod.__pluginbase_state__ = None + self.mod = None + try: + delattr(_internalspace, self.spaceid) + except AttributeError: + pass + prefix = modname + '.' + _sys.modules.pop(modname) + for key, value in list(_sys.modules.items()): + if not key.startswith(prefix): + continue + mod = _sys.modules.pop(key, None) + if mod is None: + continue + _shutdown_module(mod) + + def __assert_not_cleaned_up(self): + if self.mod is None: + raise RuntimeError('The plugin source was already cleaned up.') + + def __enter__(self): + self.__assert_not_cleaned_up() + _local.__dict__.setdefault('space_stack', []).append(self) + return self + + def __exit__(self, exc_type, exc_value, tb): + try: + _local.space_stack.pop() + except (AttributeError, IndexError): + pass + + def _rewrite_module_path(self, modname): + self.__assert_not_cleaned_up() + if modname == self.base.package: + return self.mod.__name__ + elif modname.startswith(self.base.package + '.'): + pieces = modname.split('.') + return self.mod.__name__ + '.' + '.'.join( + pieces[self.base.package.count('.') + 1:]) + + +class PluginBaseState(object): + __slots__ = ('_source',) + + def __init__(self, source): + if source.persist: + self._source = lambda: source + else: + self._source = weakref(source) + + @property + def source(self): + rv = self._source() + if rv is None: + raise AttributeError('Plugin source went away') + return rv + + +class _ImportHook(ModuleType): + + def __init__(self, name, system_import): + ModuleType.__init__(self, name) + self._system_import = system_import + self.enabled = True + + def enable(self): + """Enables the import hook which drives the plugin base system. + This is the default. + """ + self.enabled = True + + def disable(self): + """Disables the import hook and restores the default import system + behavior. This effectively breaks pluginbase but can be useful + for testing purposes. + """ + self.enabled = False + + def plugin_import(self, name, globals=None, locals=None, + fromlist=None, level=-2): + import_name = name + if self.enabled: + ref_globals = globals + if ref_globals is None: + ref_globals = sys._getframe(1).f_globals + space = _discover_space(name, ref_globals) + if space is not None: + actual_name = space._rewrite_module_path(name) + if actual_name is not None: + import_name = actual_name + if level == -2: + # fake impossible value; default value depends on version + if IS_PY24: + # the level parameter was added in version 2.5 + return self._system_import(import_name, globals, locals, fromlist) + elif IS_PY3K: + # default value for level parameter in python 3 + level = 0 + else: + # default value for level parameter in other versions + level = -1 + return self._system_import(import_name, globals, locals, + fromlist, level) + + +try: + import __builtin__ as builtins +except ImportError: + import builtins + +import_hook = _ImportHook(__name__ + '.import_hook', builtins.__import__) +builtins.__import__ = import_hook.plugin_import +sys.modules[import_hook.__name__] = import_hook +del builtins diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index b238c652c18b..2b9b4ee94a1c 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -9,7 +9,7 @@ pydev_monkey_qt.patch_qt() import traceback -from django_debug import DjangoLineBreakpoint +from pluginbase import PluginBase from pydevd_frame import add_exception_to_frame import pydev_imports from pydevd_breakpoints import * #@UnusedWildImport @@ -303,10 +303,10 @@ class PyDB: self._cmd_queue = {} # the hash of Queues. Key is thread id, value is thread self.breakpoints = {} - self.django_breakpoints = {} + #self.django_breakpoints = {} self.file_to_id_to_line_breakpoint = {} - self.file_to_id_to_django_breakpoint = {} + self.file_to_id_to_plugin_breakpoint = {} # Note: breakpoints dict should not be mutated: a copy should be created # and later it should be assigned back (to prevent concurrency issues). @@ -346,6 +346,15 @@ class PyDB: # This attribute holds the file-> lines which have an @IgnoreException. self.filename_to_lines_where_exceptions_are_ignored = {} + #working with plugins + self.usable_plugin = None + self.plugins = [] + #we call this functions very often, so we need cache them + self.can_not_skip_cache = None + self.has_exception_breaks_cache = None + + self.load_plugins() + def haveAliveThreads(self): for t in threadingEnumerate(): @@ -845,15 +854,19 @@ class PyDB: if len(expression) <= 0 or expression is None or expression == "None": expression = None + supported_type = False if type == 'python-line': breakpoint = LineBreakpoint(line, condition, func_name, expression) breakpoints = self.breakpoints file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint - elif type == 'django-line': - breakpoint = DjangoLineBreakpoint(file, line, condition, func_name, expression) - breakpoints = self.django_breakpoints - file_to_id_to_breakpoint = self.file_to_id_to_django_breakpoint + supported_type = True else: + supported_type, result = self.add_plugin_breakpoint('add_line_breakpoint', type, file, line, condition, expression, func_name) + if supported_type: + breakpoint, breakpoints = result + file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint + + if not supported_type: raise NameError(type) if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: @@ -886,27 +899,31 @@ class PyDB: pydev_log.error('Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id,)) else: + file_to_id_to_breakpoint = None if breakpoint_type == 'python-line': breakpoints = self.breakpoints file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint - elif breakpoint_type == 'django-line': - breakpoints = self.django_breakpoints - file_to_id_to_breakpoint = self.file_to_id_to_django_breakpoint else: - raise NameError(breakpoint_type) + supported_type, result = self.plugin_func_with_result('get_breakpoints', breakpoint_type) + if supported_type: + file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint + breakpoints = result - try: - id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {}) - if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: - existing = id_to_pybreakpoint[breakpoint_id] - sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % ( - file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id)) + if file_to_id_to_breakpoint is None: + pydev_log.error('Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type) + else: + try: + id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {}) + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: + existing = id_to_pybreakpoint[breakpoint_id] + sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % ( + file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id)) - del id_to_pybreakpoint[breakpoint_id] - self.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) - except KeyError: - pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % ( - file, breakpoint_id, DictKeys(id_to_pybreakpoint))) + del id_to_pybreakpoint[breakpoint_id] + self.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints) + except KeyError: + pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % ( + file, breakpoint_id, DictKeys(id_to_pybreakpoint))) elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION: @@ -1022,28 +1039,53 @@ class PyDB: elif cmd_id == CMD_ADD_EXCEPTION_BREAK: exception, notify_always, notify_on_terminate = text.split('\t', 2) - exception_breakpoint = self.add_break_on_exception( - exception, - notify_always=int(notify_always) > 0, - notify_on_terminate = int(notify_on_terminate) == 1, - notify_on_first_raise_only=int(notify_always) == 2 - ) - if exception_breakpoint is not None: - self.update_after_exceptions_added([exception_breakpoint]) + if exception.find('-') != -1: + type, exception = exception.split('-') + else: + type = 'python' + + if type == 'python': + exception_breakpoint = self.add_break_on_exception( + exception, + notify_always=int(notify_always) > 0, + notify_on_terminate = int(notify_on_terminate) == 1, + notify_on_first_raise_only=int(notify_always) == 2 + ) + + if exception_breakpoint is not None: + self.update_after_exceptions_added([exception_breakpoint]) + else: + supported_type = self.add_plugin_breakpoint('add_exception_breakpoint', type, exception) + + if not supported_type: + raise NameError(type) + + elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK: exception = text - try: - cp = self.break_on_uncaught_exceptions.copy() - DictPop(cp, exception, None) - self.break_on_uncaught_exceptions = cp + if exception.find('-') != -1: + type, exception = exception.split('-') + else: + type = 'python' - cp = self.break_on_caught_exceptions.copy() - DictPop(cp, exception, None) - self.break_on_caught_exceptions = cp - except: - pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]); - update_exception_hook(self) + if type == 'python': + try: + cp = self.break_on_uncaught_exceptions.copy() + DictPop(cp, exception, None) + self.break_on_uncaught_exceptions = cp + + cp = self.break_on_caught_exceptions.copy() + DictPop(cp, exception, None) + self.break_on_caught_exceptions = cp + except: + pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]) + update_exception_hook(self) + else: + supported_type = self.plugin_function('remove_exception_breakpoint', type, exception) + + if not supported_type: + raise NameError(type) elif cmd_id == CMD_LOAD_SOURCE: path = text @@ -1057,16 +1099,13 @@ class PyDB: elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK: exception = text - self.django_exception_break[exception] = True - self.setTracingForUntracedContexts() + self.add_plugin_breakpoint('add_exception_breakpoint', 'django', exception) + elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text - try: - del self.django_exception_break[exception] - except : - pass + self.plugin_function('remove_exception_breakpoint', 'django', exception) elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication @@ -1547,6 +1586,84 @@ class PyDB: cmd = self.cmdFactory.makeExitMessage() self.writer.addCommand(cmd) + def load_plugins(self): + plugin_base = PluginBase(package='pydevd_plugins') + self.plugin_source = plugin_base.make_plugin_source(searchpath=[os.path.dirname(os.path.realpath(__file__)) + '/pydevd_plugins']) + for plugin in self.plugin_source.list_plugins(): + loaded_plugin = None + try: + loaded_plugin = self.plugin_source.load_plugin(plugin) + except: + pydev_log.error("Failed to load plugin %s" % plugin) + if loaded_plugin: + self.plugins.append(loaded_plugin) + + def add_plugin_breakpoint(self, func_name, *args, **kwargs): + #add breakpoint from plugin and remember usable plugin + for loaded_plugin in self.plugins: + if hasattr(loaded_plugin, func_name): + func = getattr(loaded_plugin, func_name) + result_exist, result = func(self, *args, **kwargs) + if result_exist: + self.usable_plugin = loaded_plugin + return result_exist, result + return False, None + + def can_not_skip_from_plugin(self, *args, **kwargs): + if not self.usable_plugin: + return False + if not self.can_not_skip_cache: + loaded_plugin = self.usable_plugin + can_not_skip_fun = getattr(loaded_plugin, 'can_not_skip', None) + if can_not_skip_fun: + self.can_not_skip_cache = can_not_skip_fun + else: + pydev_log.error("Implementation for function 'can_not_skip' is necessary in plugin %s" % loaded_plugin) + return False + func = self.can_not_skip_cache + if func(self, *args, **kwargs): + return True + return False + + def has_exception_breaks_from_plugin(self, *args, **kwargs): + if not self.usable_plugin: + return False + if not self.has_exception_breaks_cache: + loaded_plugin = self.usable_plugin + has_exc_b_fun = getattr(loaded_plugin, 'has_exception_breaks', None) + if has_exc_b_fun: + self.has_exception_breaks_cache = has_exc_b_fun + else: + pydev_log.error("Implementation for function 'has_exception_breaks' is necessary in plugin %s" % loaded_plugin) + return False + func = self.has_exception_breaks_cache + if func(self, *args, **kwargs): + return True + return False + + def plugin_function(self, func_name, *args, **kwargs): + #call function from plugin + if not self.usable_plugin: + return False + loaded_plugin = self.usable_plugin + if hasattr(loaded_plugin, func_name): + func = getattr(loaded_plugin, func_name) + if func(self, *args, **kwargs): + return True + return False + + def plugin_func_with_result(self, func_name, *args, **kwargs): + #call function from plugin and return its result + if not self.usable_plugin: + return False, None + loaded_plugin = self.usable_plugin + if hasattr(loaded_plugin, func_name): + func = getattr(loaded_plugin, func_name) + result_exist, result = func(self, *args, **kwargs) + if result_exist: + return result_exist, result + return False, None + def wait_for_commands(self, globals): thread = threading.currentThread() import pydevd_frame_utils diff --git a/python/helpers/pydev/pydevd_constants.py b/python/helpers/pydev/pydevd_constants.py index e878d3b48ead..a4b15d85acd5 100644 --- a/python/helpers/pydev/pydevd_constants.py +++ b/python/helpers/pydev/pydevd_constants.py @@ -6,6 +6,7 @@ STATE_SUSPEND = 2 PYTHON_SUSPEND = 1 DJANGO_SUSPEND = 2 +JINJA2_SUSPEND = 3 try: __setFalse = False diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index a379b966e20d..8b40f49697d1 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -48,7 +48,6 @@ class PyDBFrame: #args = mainDebugger, filename, base, info, t, frame #yeap, much faster than putting in self and then getting it from self later on self._args = args[:-1] - self._cached_is_django_render_call = None def setSuspend(self, *args, **kwargs): self._args[0].setSuspend(*args, **kwargs) @@ -57,14 +56,15 @@ class PyDBFrame: self._args[0].doWaitSuspend(*args, **kwargs) def _is_django_render_call(self, frame): - if self._cached_is_django_render_call is None: + try: + return self._cached_is_django_render_call + except: # Calculate lazily: note that a PyDBFrame always deals with the same # frame over and over, so, we can cache this. # -- although we can't cache things which change over time (such as # the breakpoints for the file). - self._cached_is_django_render_call = is_django_render_call(frame) - - return self._cached_is_django_render_call + ret = self._cached_is_django_render_call = is_django_render_call(frame) + return ret def trace_exception(self, frame, event, arg): if event == 'exception': @@ -97,22 +97,11 @@ class PyDBFrame: flag = False else: try: - if mainDebugger.django_exception_break and get_exception_name(exception) in [ - 'VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] \ - and just_raised(trace) and is_django_exception_break_context(frame): + exist_result, result = mainDebugger.plugin_func_with_result('exception_break', self, frame, event, self._args, arg) + if exist_result: + (flag, frame) = result - render_frame = find_django_render_frame(frame) - if render_frame: - suspend_frame = suspend_django( - self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK) - - if suspend_frame: - add_exception_to_frame(suspend_frame, (exception, value, trace)) - flag = True - thread.additionalInfo.message = 'VariableDoesNotExist' - suspend_frame.f_back = frame - frame = suspend_frame - except : + except: flag = False return flag, frame @@ -253,7 +242,8 @@ class PyDBFrame: sendSignatureCallTrace(main_debugger, frame, filename) is_exception_event = event == 'exception' - has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.django_exception_break + has_exception_breakpoints = main_debugger.break_on_caught_exceptions \ + or main_debugger.has_exception_breaks_from_plugin() if is_exception_event: if has_exception_breakpoints: @@ -293,9 +283,8 @@ class PyDBFrame: can_skip = (step_cmd is None and stop_frame is None)\ or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) - check_stop_on_django_render_call = main_debugger.django_breakpoints and self._is_django_render_call(frame) - if check_stop_on_django_render_call: - can_skip = False + if can_skip: + can_skip = not main_debugger.can_not_skip_from_plugin(frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace @@ -334,79 +323,55 @@ class PyDBFrame: try: line = frame.f_lineno - - flag = False - if event == 'call' and info.pydev_state != STATE_SUSPEND and check_stop_on_django_render_call: - flag, frame = self.should_stop_on_django_breakpoint(frame, event, arg) - #return is not taken into account for breakpoint hit because we'd have a double-hit in this case #(one for the line and the other for the return). - if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None\ - and DictContains(breakpoints_for_file, line): + stop_info = {} + breakpoint = None + exist_result = False + stop_info['stop'] = False + if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None \ + and DictContains(breakpoints_for_file, line): + breakpoint = breakpoints_for_file[line] + stop_info['stop'] = True + new_frame = frame + if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'): + stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) + else: + exist_result, result = main_debugger.plugin_func_with_result('get_breakpoint', frame, event, self._args) + if exist_result: + (flag, breakpoint, new_frame) = result + + if breakpoint: #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint # lets do the conditional stuff here - breakpoint = breakpoints_for_file[line] - - stop = True - if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ('line', 'return'): - stop = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) - else: - condition = breakpoint.condition - if condition is not None: + if stop_info['stop'] or exist_result: + if breakpoint.condition is not None: try: - val = eval(condition, frame.f_globals, frame.f_locals) + val = eval(breakpoint.condition, new_frame.f_globals, new_frame.f_locals) if not val: return self.trace_dispatch except: - if type(condition) != type(''): - if hasattr(condition, 'encode'): - condition = condition.encode('utf-8') - - msg = 'Error while evaluating expression: %s\n' % (condition,) - sys.stderr.write(msg) - traceback.print_exc() - if not main_debugger.suspend_on_breakpoint_exception: - return self.trace_dispatch - else: - stop = True - try: - additional_info = None - try: - additional_info = thread.additionalInfo - except AttributeError: - pass #that's ok, no info currently set - - if additional_info is not None: - # add exception_type and stacktrace into thread additional info - etype, value, tb = sys.exc_info() - try: - error = ''.join(traceback.format_exception_only(etype, value)) - stack = traceback.extract_stack(f=tb.tb_frame.f_back) - - # On self.setSuspend(thread, CMD_SET_BREAK) this info will be - # sent to the client. - additional_info.conditional_breakpoint_exception = \ - ('Condition:\n' + condition + '\n\nError:\n' + error, stack) - finally: - etype, value, tb = None, None, None - except: - traceback.print_exc() + pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1])) + return self.trace_dispatch if breakpoint.expression is not None: try: try: - val = eval(breakpoint.expression, frame.f_globals, frame.f_locals) + val = eval(breakpoint.expression, new_frame.f_globals, new_frame.f_locals) except: val = sys.exc_info()[1] finally: if val is not None: thread.additionalInfo.message = val - - if stop: - self.setSuspend(thread, CMD_SET_BREAK) + if stop_info['stop']: + self.setSuspend(thread, CMD_SET_BREAK) + elif flag: + exist_result, result = main_debugger.plugin_func_with_result('suspend', self, thread, frame) + if exist_result: + frame = result # if thread has a suspend flag, we suspend with a busy wait if info.pydev_state == STATE_SUSPEND: @@ -419,7 +384,7 @@ class PyDBFrame: #step handling. We stop when we hit the right frame try: - django_stop = False + stop_info['django_stop'] = False should_skip = False if pydevd_dont_trace.should_trace_hook is not None: @@ -432,34 +397,18 @@ class PyDBFrame: should_skip = self.should_skip if should_skip: - stop = False + stop_info['stop'] = False elif step_cmd == CMD_STEP_INTO: - stop = event in ('line', 'return') - - if is_django_suspended(thread): - #django_stop = event == 'call' and is_django_render_call(frame) - stop = stop and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame) - if stop: - info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame + stop_info['stop'] = event in ('line', 'return') + main_debugger.plugin_function('cmd_step_into', frame, event, self._args, stop_info) elif step_cmd == CMD_STEP_OVER: - if is_django_suspended(thread): - django_stop = event == 'call' and self._is_django_render_call(frame) - - stop = False - else: - if event == 'return' and info.pydev_django_resolve_frame is not None and is_django_resolve_call(frame.f_back): - #we return to Django suspend mode and should not stop before django rendering frame - stop_frame = info.pydev_step_stop = info.pydev_django_resolve_frame - info.pydev_django_resolve_frame = None - thread.additionalInfo.suspend_type = DJANGO_SUSPEND - - - stop = stop_frame is frame and event in ('line', 'return') + stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return') + main_debugger.plugin_function('cmd_step_over', frame, event, self._args, stop_info) elif step_cmd == CMD_SMART_STEP_INTO: - stop = False + stop_info['stop'] = False if info.pydev_smart_step_stop is frame: info.pydev_func_name = None info.pydev_smart_step_stop = None @@ -472,13 +421,13 @@ class PyDBFrame: curr_func_name = '' if curr_func_name == info.pydev_func_name: - stop = True + stop_info['stop'] = True elif step_cmd == CMD_STEP_RETURN: - stop = event == 'return' and stop_frame is frame + stop_info['stop'] = event == 'return' and stop_frame is frame elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT: - stop = False + stop_info['stop'] = False if event == 'line' or event == 'exception': #Yes, we can only act on line events (weird hum?) @@ -493,50 +442,47 @@ class PyDBFrame: if curr_func_name == info.pydev_func_name: line = info.pydev_next_line if frame.f_lineno == line: - stop = True + stop_info['stop'] = True else: if frame.f_trace is None: frame.f_trace = self.trace_dispatch frame.f_lineno = line frame.f_trace = None - stop = True + stop_info['stop'] = True else: - stop = False + stop_info['stop'] = False - if django_stop: - frame = suspend_django(self, main_debugger, thread, frame, step_cmd) - if frame: - self.doWaitSuspend(thread, frame, event, arg) - elif stop: - #event is always == line or return at this point - if event == 'line': - self.setSuspend(thread, step_cmd) - self.doWaitSuspend(thread, frame, event, arg) - else: #return event - back = frame.f_back - if back is not None: - #When we get to the pydevd run function, the debugging has actually finished for the main thread - #(note that it can still go on for other threads, but for this one, we just make it finish) - #So, just setting it to None should be OK - base = basename(back.f_code.co_filename) - if base == 'pydevd.py' and back.f_code.co_name == 'run': - back = None - - elif base == 'pydevd_traceproperty.py': - # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) - #if we're in a return, we want it to appear to the user in the previous frame! - return None - - if back is not None: - #if we're in a return, we want it to appear to the user in the previous frame! + if True in stop_info.values(): + stopped_on_plugin = main_debugger.plugin_function('stop', frame, event, self._args, stop_info, arg) + if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin: + if event == 'line': self.setSuspend(thread, step_cmd) - self.doWaitSuspend(thread, back, event, arg) - else: - #in jython we may not have a back frame - info.pydev_step_stop = None - info.pydev_step_cmd = None - info.pydev_state = STATE_RUN + self.doWaitSuspend(thread, frame, event, arg) + else: #return event + back = frame.f_back + if back is not None: + #When we get to the pydevd run function, the debugging has actually finished for the main thread + #(note that it can still go on for other threads, but for this one, we just make it finish) + #So, just setting it to None should be OK + base = basename(back.f_code.co_filename) + if base == 'pydevd.py' and back.f_code.co_name == 'run': + back = None + + elif base == 'pydevd_traceproperty.py': + # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging) + #if we're in a return, we want it to appear to the user in the previous frame! + return None + + if back is not None: + #if we're in a return, we want it to appear to the user in the previous frame! + self.setSuspend(thread, step_cmd) + self.doWaitSuspend(thread, back, event, arg) + else: + #in jython we may not have a back frame + info.pydev_step_stop = None + info.pydev_step_cmd = None + info.pydev_state = STATE_RUN except: diff --git a/python/helpers/pydev/pydevd_frame_utils.py b/python/helpers/pydev/pydevd_frame_utils.py index 23becca0570d..be9ada35883a 100644 --- a/python/helpers/pydev/pydevd_frame_utils.py +++ b/python/helpers/pydev/pydevd_frame_utils.py @@ -5,7 +5,7 @@ class Frame: f_fileno, f_code, f_locals, - f_globals={}, + f_globals=None, f_trace=None): self.f_back = f_back self.f_lineno = f_fileno @@ -14,8 +14,10 @@ class Frame: self.f_globals = f_globals self.f_trace = f_trace + if self.f_globals is None: + self.f_globals = {} class FCode: def __init__(self, name, filename): self.co_name = name - self.co_filename = filename \ No newline at end of file + self.co_filename = filename diff --git a/python/helpers/pydev/pydevd_plugins/__init__.py b/python/helpers/pydev/pydevd_plugins/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py new file mode 100644 index 000000000000..3f0143da419d --- /dev/null +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -0,0 +1,375 @@ +from pydevd_comm import CMD_SET_BREAK, CMD_ADD_EXCEPTION_BREAK +import inspect +from pydevd_constants import DJANGO_SUSPEND, STATE_SUSPEND, GetThreadId, DictContains +from pydevd_file_utils import NormFileToServer, GetFileNameAndBaseFromFile +from pydevd_breakpoints import LineBreakpoint, get_exception_name +import pydevd_vars +import traceback +import pydev_log +from pydevd_frame import add_exception_to_frame + + +class DjangoLineBreakpoint(LineBreakpoint): + def __init__(self, file, line, condition, func_name, expression): + self.file = file + LineBreakpoint.__init__(self, line, condition, func_name, expression) + + def is_triggered(self, template_frame_file, template_frame_line): + return self.file == template_frame_file and self.line == template_frame_line + + def __str__(self): + return "DjangoLineBreakpoint: %s-%d" %(self.file, self.line) + + +def add_line_breakpoint(pydb, type, file, line, condition, expression, func_name): + result = None + if type == 'django-line': + breakpoint = DjangoLineBreakpoint(file, line, condition, func_name, expression) + if not hasattr(pydb, 'django_breakpoints'): + pydb.django_breakpoints = {} + result = breakpoint, pydb.django_breakpoints + return True, result + return False, result + +def add_exception_breakpoint(pydb, type, exception): + if type == 'django': + if not hasattr(pydb, 'django_exception_break'): + pydb.django_exception_break = {} + pydb.django_exception_break[exception] = True + pydb.setTracingForUntracedContexts() + return True, None + return False, None + + +def remove_exception_breakpoint(pydb, type, exception): + if type == 'django': + try: + del pydb.django_exception_break[exception] + return True + except: + pass + return False + +def get_breakpoints(pydb): + if type == 'django-line': + return True, pydb.django_breakpoints + return False, None + +def inherits(cls, *names): + if cls.__name__ in names: + return True + inherits_node = False + for base in inspect.getmro(cls): + if base.__name__ in names: + inherits_node = True + break + return inherits_node + + +def is_django_render_call(frame): + try: + name = frame.f_code.co_name + if name != 'render': + return False + + if not DictContains(frame.f_locals, 'self'): + return False + + cls = frame.f_locals['self'].__class__ + + inherits_node = inherits(cls, 'Node') + + if not inherits_node: + return False + + clsname = cls.__name__ + return clsname != 'TextNode' and clsname != 'NodeList' + except: + traceback.print_exc() + return False + + +def is_django_context_get_call(frame): + try: + if not DictContains(frame.f_locals, 'self'): + return False + + cls = frame.f_locals['self'].__class__ + + return inherits(cls, 'BaseContext') + except: + traceback.print_exc() + return False + + +def is_django_resolve_call(frame): + try: + name = frame.f_code.co_name + if name != '_resolve_lookup': + return False + + if not DictContains(frame.f_locals, 'self'): + return False + + cls = frame.f_locals['self'].__class__ + + clsname = cls.__name__ + return clsname == 'Variable' + except: + traceback.print_exc() + return False + + +def is_django_suspended(thread): + return thread.additionalInfo.suspend_type == DJANGO_SUSPEND + + +def suspend_django(py_db_frame, mainDebugger, thread, frame, cmd=CMD_SET_BREAK): + frame = DjangoTemplateFrame(frame) + + if frame.f_lineno is None: + return None + + #try: + # if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno: + # return None # don't stay twice on the same line + #except AttributeError: + # pass + + pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame}) + + py_db_frame.setSuspend(thread, cmd) + thread.additionalInfo.suspend_type = DJANGO_SUSPEND + + thread.additionalInfo.filename = frame.f_code.co_filename + thread.additionalInfo.line = frame.f_lineno + + return frame + + +def find_django_render_frame(frame): + while frame is not None and not is_django_render_call(frame): + frame = frame.f_back + + return frame + +#======================================================================================================================= +# Django Frame +#======================================================================================================================= + +def read_file(filename): + f = open(filename, "r") + s = f.read() + f.close() + return s + + +def offset_to_line_number(text, offset): + curLine = 1 + curOffset = 0 + while curOffset < offset: + if curOffset == len(text): + return -1 + c = text[curOffset] + if c == '\n': + curLine += 1 + elif c == '\r': + curLine += 1 + if curOffset < len(text) and text[curOffset + 1] == '\n': + curOffset += 1 + + curOffset += 1 + + return curLine + + +def get_source(frame): + try: + node = frame.f_locals['self'] + if hasattr(node, 'source'): + return node.source + else: + pydev_log.error_once("WARNING: Template path is not available. Please set TEMPLATE_DEBUG=True in your settings.py to make " + " django template breakpoints working") + return None + + except: + pydev_log.debug(traceback.format_exc()) + return None + + +def get_template_file_name(frame): + try: + source = get_source(frame) + if source is None: + pydev_log.debug("Source is None\n") + return None + fname = source[0].name + + if fname == '': + pydev_log.debug("Source name is %s\n" % fname) + return None + else: + filename, base = GetFileNameAndBaseFromFile(fname) + return filename + except: + pydev_log.debug(traceback.format_exc()) + return None + + +def get_template_line(frame): + source = get_source(frame) + file_name = get_template_file_name(frame) + try: + return offset_to_line_number(read_file(file_name), source[1][0]) + except: + return None + + +class DjangoTemplateFrame: + def __init__(self, frame): + file_name = get_template_file_name(frame) + self.back_context = frame.f_locals['context'] + self.f_code = FCode('Django Template', file_name) + self.f_lineno = get_template_line(frame) + self.f_back = frame + self.f_globals = {} + self.f_locals = self.collect_context(self.back_context) + self.f_trace = None + + def collect_context(self, context): + res = {} + try: + for d in context.dicts: + for k, v in d.items(): + res[k] = v + except AttributeError: + pass + return res + + def changeVariable(self, name, value): + for d in self.back_context.dicts: + for k, v in d.items(): + if k == name: + d[k] = value + + +class FCode: + def __init__(self, name, filename): + self.co_name = name + self.co_filename = filename + + +def is_django_exception_break_context(frame): + try: + name = frame.f_code.co_name + except: + name = None + return name in ['_resolve_lookup', 'find_template'] + + +def just_raised(trace): + if trace is None: + return False + return trace.tb_next is None + + +#======================================================================================================================= +# Django Step Commands +#======================================================================================================================= + +def can_not_skip(mainDebugger, frame): + if hasattr(mainDebugger, 'django_breakpoints') and mainDebugger.django_breakpoints and is_django_render_call(frame): + filename = get_template_file_name(frame) + django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) + if django_breakpoints_for_file: + return True + return False + +def has_exception_breaks(mainDebugger): + return hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break + + +def cmd_step_into(mainDebugger, frame, event, args, stop_info): + mainDebugger, filename, info, thread = args + if is_django_suspended(thread): + #stop_info['django_stop'] = event == 'call' and is_django_render_call(frame) + stop_info['stop'] = stop_info['stop'] and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame) + if stop_info['stop']: + info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame + + +def cmd_step_over(mainDebugger, frame, event, args, stop_info): + mainDebugger, filename, info, thread = args + if is_django_suspended(thread): + stop_info['django_stop'] = event == 'call' and is_django_render_call(frame) + stop_info['stop'] = False + return True + else: + if event == 'return' and info.pydev_django_resolve_frame is not None and is_django_resolve_call(frame.f_back): + #we return to Django suspend mode and should not stop before django rendering frame + info.pydev_step_stop = info.pydev_django_resolve_frame + info.pydev_django_resolve_frame = None + thread.additionalInfo.suspend_type = DJANGO_SUSPEND + stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return') + + return False + + +def stop(mainDebugger, frame, event, args, stop_info, arg): + mainDebugger, filename, info, thread = args + if DictContains(stop_info, 'django_stop') and stop_info['django_stop']: + frame = suspend_django(mainDebugger, mainDebugger, thread, frame) + if frame: + mainDebugger.doWaitSuspend(thread, frame, event, arg) + return True + return False + + +def get_breakpoint(mainDebugger, frame, event, args): + mainDebugger, filename, info, thread = args + flag = False + django_breakpoint = None + result = None + new_frame = None + is_result_exist = False + + if event == 'call' and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'django_breakpoints') and \ + mainDebugger.django_breakpoints and is_django_render_call(frame): + filename = get_template_file_name(frame) + pydev_log.debug("Django is rendering a template: %s\n" % filename) + django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) + if django_breakpoints_for_file: + pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file) + template_line = get_template_line(frame) + pydev_log.debug("Tracing template line: %d\n" % template_line) + + if DictContains(django_breakpoints_for_file, template_line): + is_result_exist = True + django_breakpoint = django_breakpoints_for_file[template_line] + flag = True + new_frame = DjangoTemplateFrame(frame) + result = flag, django_breakpoint, new_frame + return is_result_exist, result + + +def suspend(mainDebugger, pydb_frame, thread, frame): + return True, suspend_django(pydb_frame, mainDebugger, thread, frame) + +def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): + mainDebugger, filename, info, thread = args + exception, value, trace = arg + if hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break and \ + get_exception_name(exception) in ['VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] and \ + just_raised(trace) and is_django_exception_break_context(frame): + render_frame = find_django_render_frame(frame) + if render_frame: + suspend_frame = suspend_django(pydb_frame, mainDebugger, thread, render_frame, CMD_ADD_EXCEPTION_BREAK) + if suspend_frame: + add_exception_to_frame(suspend_frame, (exception, value, trace)) + flag = True + thread.additionalInfo.message = 'VariableDoesNotExist' + suspend_frame.f_back = frame + frame = suspend_frame + return True, (flag, frame) + return False, None \ No newline at end of file diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py new file mode 100644 index 000000000000..854d796676a5 --- /dev/null +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -0,0 +1,347 @@ +from pydevd_breakpoints import LineBreakpoint, get_exception_name +from pydevd_constants import JINJA2_SUSPEND, GetThreadId, STATE_SUSPEND, DictContains +from pydevd_comm import CMD_SET_BREAK, CMD_STEP_OVER, CMD_ADD_EXCEPTION_BREAK +import pydevd_vars +from pydevd_file_utils import GetFileNameAndBaseFromFile +from pydevd_frame import add_exception_to_frame + +class Jinja2LineBreakpoint(LineBreakpoint): + + def __init__(self, file, line, condition, func_name, expression): + self.file = file + LineBreakpoint.__init__(self, line, condition, func_name, expression) + + def is_triggered(self, template_frame_file, template_frame_line): + return self.file == template_frame_file and self.line == template_frame_line + + def __str__(self): + return "Jinja2LineBreakpoint: %s-%d" %(self.file, self.line) + + +def add_line_breakpoint(pydb, type, file, line, condition, func_name, expression): + result = None + if type == 'jinja2-line': + breakpoint = Jinja2LineBreakpoint(file, line, condition, func_name, expression) + if not hasattr(pydb, 'jinja2_breakpoints'): + pydb.jinja2_breakpoints = {} + result = breakpoint, pydb.jinja2_breakpoints + return True, result + return False, result + +def add_exception_breakpoint(pydb, type, exception): + if type == 'jinja2': + if not hasattr(pydb, 'jinja2_exception_break'): + pydb.jinja2_exception_break = {} + pydb.jinja2_exception_break[exception] = True + pydb.setTracingForUntracedContexts() + return True, None + return False, None + +def remove_exception_breakpoint(pydb, type, exception): + if type == 'jinja2': + try: + del pydb.jinja2_exception_break[exception] + return True + except: + pass + return False + +def get_breakpoints(pydb, type): + if type == 'jinja2-line': + return True, pydb.jinja2_breakpoints + return False, None + + +def is_jinja2_render_call(frame): + try: + name = frame.f_code.co_name + if DictContains(frame.f_globals, "__jinja_template__") and name in ("root", "loop", "macro") or name.startswith("block_"): + return True + return False + except: + traceback.print_exc() + return False + + +def suspend_jinja2(py_db_frame, mainDebugger, thread, frame, cmd=CMD_SET_BREAK): + frame = Jinja2TemplateFrame(frame) + + if frame.f_lineno is None: + return None + + pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame}) + py_db_frame.setSuspend(thread, cmd) + + thread.additionalInfo.suspend_type = JINJA2_SUSPEND + thread.additionalInfo.filename = frame.f_code.co_filename + thread.additionalInfo.line = frame.f_lineno + + return frame + +def is_jinja2_suspended(thread): + return thread.additionalInfo.suspend_type == JINJA2_SUSPEND + +def is_jinja2_context_call(frame): + return DictContains(frame.f_locals, "_Context__obj") + +def is_jinja2_internal_function(frame): + return DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ in \ + ('LoopContext', 'TemplateReference', 'Macro', 'BlockReference') + +def find_jinja2_render_frame(frame): + while frame is not None and not is_jinja2_render_call(frame): + frame = frame.f_back + + return frame + +def change_variable(mainDebugger, frame, attr, expression): + if isinstance(frame, Jinja2TemplateFrame): + result = eval(expression, frame.f_globals, frame.f_locals) + frame.changeVariable(attr, result) + + +#======================================================================================================================= +# Jinja2 Frame +#======================================================================================================================= + +class Jinja2TemplateFrame: + + def __init__(self, frame): + file_name = get_jinja2_template_filename(frame) + self.back_context = None + if 'context' in frame.f_locals: + #sometimes we don't have 'context', e.g. in macros + self.back_context = frame.f_locals['context'] + self.f_code = FCode('template', file_name) + self.f_lineno = get_jinja2_template_line(frame) + self.f_back = find_render_function_frame(frame) + self.f_globals = {} + self.f_locals = self.collect_context(frame) + self.f_trace = None + + def collect_context(self, frame): + res = {} + if self.back_context is not None: + for k, v in self.back_context.items(): + res[k] = v + for k, v in frame.f_locals.items(): + if not k.startswith('l_'): + if not k in res: + #local variables should shadow globals from context + res[k] = v + elif v and not is_missing(v): + res[k[2:]] = v + return res + + def changeVariable(self, name, value): + for k, v in self.back_context.items(): + if k == name: + self.back_context.vars[k] = value + +class FCode: + def __init__(self, name, filename): + self.co_name = name + self.co_filename = filename + +def is_missing(item): + if item.__class__.__name__ is 'MissingType': + return True + return False + +def find_render_function_frame(frame): + #in order to hide internal rendering functions + old_frame = frame + try: + while not (DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ == 'Template' and \ + frame.f_code.co_name == 'render'): + frame = frame.f_back + if frame is None: + return old_frame + return frame + except: + return old_frame + +def get_jinja2_template_line(frame): + debug_info = None + if DictContains(frame.f_globals,'__jinja_template__'): + _debug_info = frame.f_globals['__jinja_template__']._debug_info + if _debug_info is not '': + #sometimes template contains only plain text + debug_info = frame.f_globals['__jinja_template__'].debug_info + + if debug_info is None: + return None + + lineno = frame.f_lineno + + for pair in debug_info: + if pair[1] == lineno: + return pair[0] + + return None + +def get_jinja2_template_filename(frame): + if DictContains(frame.f_globals, '__jinja_template__'): + fname = frame.f_globals['__jinja_template__'].filename + filename, base = GetFileNameAndBaseFromFile(fname) + return filename + return None + + +#======================================================================================================================= +# Jinja2 Step Commands +#======================================================================================================================= + + +def has_exception_breaks(mainDebugger): + return hasattr(mainDebugger, 'jinja2_exception_break') and mainDebugger.jinja2_exception_break + +def can_not_skip(mainDebugger, frame): + if hasattr(mainDebugger, 'jinja2_breakpoints') and mainDebugger.jinja2_breakpoints and is_jinja2_render_call(frame): + filename = get_jinja2_template_filename(frame) + jinja2_breakpoints_for_file = mainDebugger.jinja2_breakpoints.get(filename) + if jinja2_breakpoints_for_file: + return True + return False + + +def cmd_step_into(mainDebugger, frame, event, args, stop_info): + mainDebugger, filename, info, thread = args + if not hasattr(info, 'pydev_call_from_jinja2'): + info.pydev_call_from_jinja2 = None + if not hasattr(info, 'pydev_call_inside_jinja2'): + info.pydev_call_inside_jinja2 = None + if is_jinja2_suspended(thread): + stop_info['jinja2_stop'] = event in ('call', 'line') and is_jinja2_render_call(frame) + stop_info['stop'] = False + if info.pydev_call_from_jinja2 is not None: + if is_jinja2_internal_function(frame): + #if internal Jinja2 function was called, we sould continue debugging inside template + info.pydev_call_from_jinja2 = None + else: + #we go into python code from Jinja2 rendering frame + stop_info['stop'] = True + + if event == 'call' and is_jinja2_context_call(frame.f_back): + #we called function from context, the next step will be in function + info.pydev_call_from_jinja2 = 1 + + if event == 'return' and is_jinja2_context_call(frame.f_back): + #we return from python code to Jinja2 rendering frame + info.pydev_step_stop = info.pydev_call_from_jinja2 + info.pydev_call_from_jinja2 = None + thread.additionalInfo.suspend_type = JINJA2_SUSPEND + stop_info['stop'] = False + + #print "info.pydev_call_from_jinja2", info.pydev_call_from_jinja2, "stop_info", stop_info, \ + # "thread.additionalInfo.suspend_type", thread.additionalInfo.suspend_type + #print "event", event, "farme.locals", frame.f_locals + + +def cmd_step_over(mainDebugger, frame, event, args, stop_info): + mainDebugger, filename, info, thread = args + if not hasattr(info, 'pydev_call_from_jinja2'): + info.pydev_call_from_jinja2 = None + if not hasattr(info, 'pydev_call_inside_jinja2'): + info.pydev_call_inside_jinja2 = None + if is_jinja2_suspended(thread): + stop_info['stop'] = False + + if info.pydev_call_inside_jinja2 is None: + if is_jinja2_render_call(frame): + if event == 'call': + info.pydev_call_inside_jinja2 = frame.f_back + if event in ('line', 'return'): + info.pydev_call_inside_jinja2 = frame + else: + if event == 'line': + if is_jinja2_render_call(frame) and info.pydev_call_inside_jinja2 is frame: + stop_info['jinja2_stop'] = True + if event == 'return': + if frame is info.pydev_call_inside_jinja2 and not DictContains(frame.f_back.f_locals,'event'): + info.pydev_call_inside_jinja2 = find_jinja2_render_frame(frame.f_back) + return True + else: + if event == 'return' and is_jinja2_context_call(frame.f_back): + #we return from python code to Jinja2 rendering frame + info.pydev_call_from_jinja2 = None + info.pydev_call_inside_jinja2 = find_jinja2_render_frame(frame) + thread.additionalInfo.suspend_type = JINJA2_SUSPEND + stop_info['stop'] = False + return True + #print "info.pydev_call_from_jinja2", info.pydev_call_from_jinja2, "stop", stop, "jinja_stop", jinja2_stop, \ + # "thread.additionalInfo.suspend_type", thread.additionalInfo.suspend_type + #print "event", event, "info.pydev_call_inside_jinja2", info.pydev_call_inside_jinja2 + #print "frame", frame, "frame.f_back", frame.f_back, "step_stop", info.pydev_step_stop + #print "is_context_call", is_jinja2_context_call(frame) + #print "render", is_jinja2_render_call(frame) + #print "-------------" + return False + + +def stop(mainDebugger, frame, event, args, stop_info, arg): + mainDebugger, filename, info, thread = args + if DictContains(stop_info, 'jinja2_stop') and stop_info['jinja2_stop']: + frame = suspend_jinja2(mainDebugger, mainDebugger, thread, frame) + if frame: + mainDebugger.doWaitSuspend(thread, frame, event, arg) + return True + return False + + +def get_breakpoint(mainDebugger, frame, event, args): + mainDebugger, filename, info, thread = args + is_result_exist = False + result = None + new_frame = None + jinja2_breakpoint = None + flag = False + if event in ('line', 'call') and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'jinja2_breakpoints') and \ + mainDebugger.jinja2_breakpoints and is_jinja2_render_call(frame): + filename = get_jinja2_template_filename(frame) + jinja2_breakpoints_for_file = mainDebugger.jinja2_breakpoints.get(filename) + new_frame = Jinja2TemplateFrame(frame) + + if jinja2_breakpoints_for_file: + lineno = frame.f_lineno + template_lineno = get_jinja2_template_line(frame) + if template_lineno is not None and DictContains(jinja2_breakpoints_for_file, template_lineno): + is_result_exist = True + jinja2_breakpoint = jinja2_breakpoints_for_file[template_lineno] + flag = True + new_frame = Jinja2TemplateFrame(frame) + + result = flag, jinja2_breakpoint, new_frame + return is_result_exist, result + + +def suspend(mainDebugger, pydb_frame, thread, frame): + return True, suspend_jinja2(pydb_frame, mainDebugger, thread, frame) + + +def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): + mainDebugger, filename, info, thread = args + exception, value, trace = arg + if hasattr(mainDebugger, 'jinja2_exception_break') and mainDebugger.jinja2_exception_break: + if get_exception_name(exception) in ('UndefinedError', 'TemplateNotFound', 'TemplatesNotFound'): + #errors in rendering + render_frame = find_jinja2_render_frame(frame) + if render_frame: + suspend_frame = suspend_jinja2(pydb_frame, mainDebugger, thread, render_frame, CMD_ADD_EXCEPTION_BREAK) + if suspend_frame: + add_exception_to_frame(suspend_frame, (exception, value, trace)) + flag = True + suspend_frame.f_back = frame + frame = suspend_frame + return True, (flag, frame) + elif get_exception_name(exception) in ('TemplateSyntaxError', 'TemplateAssertionError'): + #errors in compile time + name = frame.f_code.co_name + if name in ('template', 'top-level template code') or name.startswith('block '): + #Jinja2 translates exception info and creates fake frame on his own + pydb_frame.setSuspend(thread, CMD_ADD_EXCEPTION_BREAK) + add_exception_to_frame(frame, (exception, value, trace)) + thread.additionalInfo.suspend_type = JINJA2_SUSPEND + flag = True + return True, (flag, frame) + return False, None \ No newline at end of file diff --git a/python/helpers/pydev/test_debug.py b/python/helpers/pydev/test_debug.py index 2196ca6f9540..27da09b5593d 100644 --- a/python/helpers/pydev/test_debug.py +++ b/python/helpers/pydev/test_debug.py @@ -5,16 +5,18 @@ import os test_data_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', 'testData', 'debug')) + class PyDevTestCase(unittest.TestCase): def testZipFileExits(self): from pydevd_file_utils import exists - self.assertTrue(exists(test_data_path +'/zipped_lib.zip/zipped_module.py')) + self.assertTrue(exists(test_data_path + '/zipped_lib.zip/zipped_module.py')) self.assertFalse(exists(test_data_path + '/zipped_lib.zip/zipped_module2.py')) self.assertFalse(exists(test_data_path + '/zipped_lib2.zip/zipped_module.py')) def testEggFileExits(self): from pydevd_file_utils import exists + self.assertTrue(exists(test_data_path + '/pycharm-debug.egg/pydev/pydevd.py')) self.assertFalse(exists(test_data_path + '/pycharm-debug.egg/pydev/pydevd2.py')) diff --git a/python/helpers/pydev/tests/check_pydevconsole.py b/python/helpers/pydev/tests/check_pydevconsole.py new file mode 100644 index 000000000000..0ff1a8618a24 --- /dev/null +++ b/python/helpers/pydev/tests/check_pydevconsole.py @@ -0,0 +1,110 @@ +import sys +import os + +# Put pydevconsole in the path. +sys.argv[0] = os.path.dirname(sys.argv[0]) +sys.path.insert(1, os.path.join(os.path.dirname(sys.argv[0]))) + +print('Running tests with:', sys.executable) +print('PYTHONPATH:') +print('\n'.join(sorted(sys.path))) + +import threading +import unittest + +import pydevconsole +from pydev_imports import xmlrpclib, SimpleXMLRPCServer + +try: + raw_input + raw_input_name = 'raw_input' +except NameError: + raw_input_name = 'input' + +#======================================================================================================================= +# Test +#======================================================================================================================= +class Test(unittest.TestCase): + def startClientThread(self, client_port): + class ClientThread(threading.Thread): + def __init__(self, client_port): + threading.Thread.__init__(self) + self.client_port = client_port + + def run(self): + class HandleRequestInput: + def RequestInput(self): + return 'RequestInput: OK' + + handle_request_input = HandleRequestInput() + + import pydev_localhost + + print('Starting client with:', pydev_localhost.get_localhost(), self.client_port) + client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False) + client_server.register_function(handle_request_input.RequestInput) + client_server.serve_forever() + + client_thread = ClientThread(client_port) + client_thread.setDaemon(True) + client_thread.start() + return client_thread + + + def getFreeAddresses(self): + import socket + + s = socket.socket() + s.bind(('', 0)) + port0 = s.getsockname()[1] + + s1 = socket.socket() + s1.bind(('', 0)) + port1 = s1.getsockname()[1] + s.close() + s1.close() + return port0, port1 + + + def testServer(self): + client_port, server_port = self.getFreeAddresses() + + class ServerThread(threading.Thread): + def __init__(self, client_port, server_port): + threading.Thread.__init__(self) + self.client_port = client_port + self.server_port = server_port + + def run(self): + import pydev_localhost + + print('Starting server with:', pydev_localhost.get_localhost(), self.server_port, self.client_port) + pydevconsole.StartServer(pydev_localhost.get_localhost(), self.server_port, self.client_port) + + server_thread = ServerThread(client_port, server_port) + server_thread.setDaemon(True) + server_thread.start() + + client_thread = self.startClientThread(client_port) #@UnusedVariable + + import time + + time.sleep(.3) #let's give it some time to start the threads + + import pydev_localhost + + server = xmlrpclib.Server('http://%s:%s' % (pydev_localhost.get_localhost(), server_port)) + server.addExec("import sys; print('Running with: %s %s' % (sys.executable or sys.platform, sys.version))") + server.addExec('class Foo:') + server.addExec(' pass') + server.addExec('') + server.addExec('foo = Foo()') + server.addExec('a = %s()' % raw_input_name) + server.addExec('print (a)') + +#======================================================================================================================= +# main +#======================================================================================================================= +if __name__ == '__main__': + unittest.main() + diff --git a/python/helpers/pydev/tests/test_pydev_ipython_010.py b/python/helpers/pydev/tests/test_pydev_ipython_010.py new file mode 100644 index 000000000000..1822763d4b29 --- /dev/null +++ b/python/helpers/pydev/tests/test_pydev_ipython_010.py @@ -0,0 +1,80 @@ +# TODO: This test no longer works (check if it should be fixed or removed altogether). + +#import unittest +#import sys +#import os +##make it as if we were executing from the directory above this one +#sys.argv[0] = os.path.dirname(sys.argv[0]) +##twice the dirname to get the previous level from this file. +#sys.path.insert(1, os.path.join(os.path.dirname(sys.argv[0]))) +# +#from pydev_localhost import get_localhost +# +# +#IS_JYTHON = sys.platform.find('java') != -1 +# +##======================================================================================================================= +## TestCase +##======================================================================================================================= +#class TestCase(unittest.TestCase): +# +# def setUp(self): +# unittest.TestCase.setUp(self) +# +# def tearDown(self): +# unittest.TestCase.tearDown(self) +# +# def testIPython(self): +# try: +# from pydev_ipython_console import PyDevFrontEnd +# except: +# if IS_JYTHON: +# return +# front_end = PyDevFrontEnd(get_localhost(), 0) +# +# front_end.input_buffer = 'if True:' +# self.assert_(not front_end._on_enter()) +# +# front_end.input_buffer = 'if True:\n' + \ +# front_end.continuation_prompt() + ' a = 10\n' +# self.assert_(not front_end._on_enter()) +# +# +# front_end.input_buffer = 'if True:\n' + \ +# front_end.continuation_prompt() + ' a = 10\n\n' +# self.assert_(front_end._on_enter()) +# +# +## front_end.input_buffer = ' print a' +## self.assert_(not front_end._on_enter()) +## front_end.input_buffer = '' +## self.assert_(front_end._on_enter()) +# +# +## front_end.input_buffer = 'a.' +## front_end.complete_current_input() +## front_end.input_buffer = 'if True:' +## front_end._on_enter() +# front_end.input_buffer = 'a = 30' +# front_end._on_enter() +# front_end.input_buffer = 'print a' +# front_end._on_enter() +# front_end.input_buffer = 'a?' +# front_end._on_enter() +# print front_end.complete('%') +# print front_end.complete('%e') +# print front_end.complete('cd c:/t') +# print front_end.complete('cd c:/temp/') +## front_end.input_buffer = 'print raw_input("press enter\\n")' +## front_end._on_enter() +## +# +##======================================================================================================================= +## main +##======================================================================================================================= +#if __name__ == '__main__': +# if sys.platform.find('java') == -1: +# #IPython not available for Jython +# unittest.main() +# else: +# print('not supported on Jython') diff --git a/python/helpers/pydev/uuid_old.py b/python/helpers/pydev/uuid_old.py new file mode 100644 index 000000000000..ae3da25ca557 --- /dev/null +++ b/python/helpers/pydev/uuid_old.py @@ -0,0 +1,541 @@ +r"""UUID objects (universally unique identifiers) according to RFC 4122. + +This module provides immutable UUID objects (class UUID) and the functions +uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 +UUIDs as specified in RFC 4122. + +If all you want is a unique ID, you should probably call uuid1() or uuid4(). +Note that uuid1() may compromise privacy since it creates a UUID containing +the computer's network address. uuid4() creates a random UUID. + +Typical usage: + + >>> import uuid + + # make a UUID based on the host ID and current time + >>> uuid.uuid1() + UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') + + # make a UUID using an MD5 hash of a namespace UUID and a name + >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') + UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') + + # make a random UUID + >>> uuid.uuid4() + UUID('16fd2706-8baf-433b-82eb-8c7fada847da') + + # make a UUID using a SHA-1 hash of a namespace UUID and a name + >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') + UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') + + # make a UUID from a string of hex digits (braces and hyphens ignored) + >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') + + # convert a UUID to a string of hex digits in standard form + >>> str(x) + '00010203-0405-0607-0809-0a0b0c0d0e0f' + + # get the raw 16 bytes of the UUID + >>> x.bytes + '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' + + # make a UUID from a 16-byte string + >>> uuid.UUID(bytes=x.bytes) + UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') +""" + +__author__ = 'Ka-Ping Yee ' + +RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ + 'reserved for NCS compatibility', 'specified in RFC 4122', + 'reserved for Microsoft compatibility', 'reserved for future definition'] + +class UUID(object): + """Instances of the UUID class represent UUIDs as specified in RFC 4122. + UUID objects are immutable, hashable, and usable as dictionary keys. + Converting a UUID to a string with str() yields something in the form + '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts + five possible forms: a similar string of hexadecimal digits, or a tuple + of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and + 48-bit values respectively) as an argument named 'fields', or a string + of 16 bytes (with all the integer fields in big-endian order) as an + argument named 'bytes', or a string of 16 bytes (with the first three + fields in little-endian order) as an argument named 'bytes_le', or a + single 128-bit integer as an argument named 'int'. + + UUIDs have these read-only attributes: + + bytes the UUID as a 16-byte string (containing the six + integer fields in big-endian byte order) + + bytes_le the UUID as a 16-byte string (with time_low, time_mid, + and time_hi_version in little-endian byte order) + + fields a tuple of the six integer fields of the UUID, + which are also available as six individual attributes + and two derived attributes: + + time_low the first 32 bits of the UUID + time_mid the next 16 bits of the UUID + time_hi_version the next 16 bits of the UUID + clock_seq_hi_variant the next 8 bits of the UUID + clock_seq_low the next 8 bits of the UUID + node the last 48 bits of the UUID + + time the 60-bit timestamp + clock_seq the 14-bit sequence number + + hex the UUID as a 32-character hexadecimal string + + int the UUID as a 128-bit integer + + urn the UUID as a URN as specified in RFC 4122 + + variant the UUID variant (one of the constants RESERVED_NCS, + RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) + + version the UUID version number (1 through 5, meaningful only + when the variant is RFC_4122) + """ + + def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, + int=None, version=None): + r"""Create a UUID from either a string of 32 hexadecimal digits, + a string of 16 bytes as the 'bytes' argument, a string of 16 bytes + in little-endian order as the 'bytes_le' argument, a tuple of six + integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, + 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as + the 'fields' argument, or a single 128-bit integer as the 'int' + argument. When a string of hex digits is given, curly braces, + hyphens, and a URN prefix are all optional. For example, these + expressions all yield the same UUID: + + UUID('{12345678-1234-5678-1234-567812345678}') + UUID('12345678123456781234567812345678') + UUID('urn:uuid:12345678-1234-5678-1234-567812345678') + UUID(bytes='\x12\x34\x56\x78'*4) + UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' + + '\x12\x34\x56\x78\x12\x34\x56\x78') + UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) + UUID(int=0x12345678123456781234567812345678) + + Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must + be given. The 'version' argument is optional; if given, the resulting + UUID will have its variant and version set according to RFC 4122, + overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'. + """ + + if [hex, bytes, bytes_le, fields, int].count(None) != 4: + raise TypeError('need one of hex, bytes, bytes_le, fields, or int') + if hex is not None: + hex = hex.replace('urn:', '').replace('uuid:', '') + hex = hex.strip('{}').replace('-', '') + if len(hex) != 32: + raise ValueError('badly formed hexadecimal UUID string') + int = long(hex, 16) + if bytes_le is not None: + if len(bytes_le) != 16: + raise ValueError('bytes_le is not a 16-char string') + bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] + + bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] + + bytes_le[8:]) + if bytes is not None: + if len(bytes) != 16: + raise ValueError('bytes is not a 16-char string') + int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) + if fields is not None: + if len(fields) != 6: + raise ValueError('fields is not a 6-tuple') + (time_low, time_mid, time_hi_version, + clock_seq_hi_variant, clock_seq_low, node) = fields + if not 0 <= time_low < 1<<32L: + raise ValueError('field 1 out of range (need a 32-bit value)') + if not 0 <= time_mid < 1<<16L: + raise ValueError('field 2 out of range (need a 16-bit value)') + if not 0 <= time_hi_version < 1<<16L: + raise ValueError('field 3 out of range (need a 16-bit value)') + if not 0 <= clock_seq_hi_variant < 1<<8L: + raise ValueError('field 4 out of range (need an 8-bit value)') + if not 0 <= clock_seq_low < 1<<8L: + raise ValueError('field 5 out of range (need an 8-bit value)') + if not 0 <= node < 1<<48L: + raise ValueError('field 6 out of range (need a 48-bit value)') + clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low + int = ((time_low << 96L) | (time_mid << 80L) | + (time_hi_version << 64L) | (clock_seq << 48L) | node) + if int is not None: + if not 0 <= int < 1<<128L: + raise ValueError('int is out of range (need a 128-bit value)') + if version is not None: + if not 1 <= version <= 5: + raise ValueError('illegal version number') + # Set the variant to RFC 4122. + int &= ~(0xc000 << 48L) + int |= 0x8000 << 48L + # Set the version number. + int &= ~(0xf000 << 64L) + int |= version << 76L + self.__dict__['int'] = int + + def __cmp__(self, other): + if isinstance(other, UUID): + return cmp(self.int, other.int) + return NotImplemented + + def __hash__(self): + return hash(self.int) + + def __int__(self): + return self.int + + def __repr__(self): + return 'UUID(%r)' % str(self) + + def __setattr__(self, name, value): + raise TypeError('UUID objects are immutable') + + def __str__(self): + hex = '%032x' % self.int + return '%s-%s-%s-%s-%s' % ( + hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) + + def get_bytes(self): + bytes = '' + for shift in range(0, 128, 8): + bytes = chr((self.int >> shift) & 0xff) + bytes + return bytes + + bytes = property(get_bytes) + + def get_bytes_le(self): + bytes = self.bytes + return (bytes[3] + bytes[2] + bytes[1] + bytes[0] + + bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:]) + + bytes_le = property(get_bytes_le) + + def get_fields(self): + return (self.time_low, self.time_mid, self.time_hi_version, + self.clock_seq_hi_variant, self.clock_seq_low, self.node) + + fields = property(get_fields) + + def get_time_low(self): + return self.int >> 96L + + time_low = property(get_time_low) + + def get_time_mid(self): + return (self.int >> 80L) & 0xffff + + time_mid = property(get_time_mid) + + def get_time_hi_version(self): + return (self.int >> 64L) & 0xffff + + time_hi_version = property(get_time_hi_version) + + def get_clock_seq_hi_variant(self): + return (self.int >> 56L) & 0xff + + clock_seq_hi_variant = property(get_clock_seq_hi_variant) + + def get_clock_seq_low(self): + return (self.int >> 48L) & 0xff + + clock_seq_low = property(get_clock_seq_low) + + def get_time(self): + return (((self.time_hi_version & 0x0fffL) << 48L) | + (self.time_mid << 32L) | self.time_low) + + time = property(get_time) + + def get_clock_seq(self): + return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | + self.clock_seq_low) + + clock_seq = property(get_clock_seq) + + def get_node(self): + return self.int & 0xffffffffffff + + node = property(get_node) + + def get_hex(self): + return '%032x' % self.int + + hex = property(get_hex) + + def get_urn(self): + return 'urn:uuid:' + str(self) + + urn = property(get_urn) + + def get_variant(self): + if not self.int & (0x8000 << 48L): + return RESERVED_NCS + elif not self.int & (0x4000 << 48L): + return RFC_4122 + elif not self.int & (0x2000 << 48L): + return RESERVED_MICROSOFT + else: + return RESERVED_FUTURE + + variant = property(get_variant) + + def get_version(self): + # The version bits are only meaningful for RFC 4122 UUIDs. + if self.variant == RFC_4122: + return int((self.int >> 76L) & 0xf) + + version = property(get_version) + +def _find_mac(command, args, hw_identifiers, get_index): + import os + for dir in ['', '/sbin/', '/usr/sbin']: + executable = os.path.join(dir, command) + if not os.path.exists(executable): + continue + + try: + # LC_ALL to get English output, 2>/dev/null to + # prevent output on stderr + cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) + pipe = os.popen(cmd) + except IOError: + continue + + for line in pipe: + words = line.lower().split() + for i in range(len(words)): + if words[i] in hw_identifiers: + return int(words[get_index(i)].replace(':', ''), 16) + return None + +def _ifconfig_getnode(): + """Get the hardware address on Unix by running ifconfig.""" + + # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. + for args in ('', '-a', '-av'): + mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1) + if mac: + return mac + + import socket + ip_addr = socket.gethostbyname(socket.gethostname()) + + # Try getting the MAC addr from arp based on our IP address (Solaris). + mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1) + if mac: + return mac + + # This might work on HP-UX. + mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) + if mac: + return mac + + return None + +def _ipconfig_getnode(): + """Get the hardware address on Windows by running ipconfig.exe.""" + import os, re + dirs = ['', r'c:\windows\system32', r'c:\winnt\system32'] + try: + import ctypes + buffer = ctypes.create_string_buffer(300) + ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) + dirs.insert(0, buffer.value.decode('mbcs')) + except: + pass + for dir in dirs: + try: + pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all') + except IOError: + continue + for line in pipe: + value = line.split(':')[-1].strip().lower() + if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value): + return int(value.replace('-', ''), 16) + +def _netbios_getnode(): + """Get the hardware address on Windows using NetBIOS calls. + See http://support.microsoft.com/kb/118623 for details.""" + import win32wnet, netbios + ncb = netbios.NCB() + ncb.Command = netbios.NCBENUM + ncb.Buffer = adapters = netbios.LANA_ENUM() + adapters._pack() + if win32wnet.Netbios(ncb) != 0: + return + adapters._unpack() + for i in range(adapters.length): + ncb.Reset() + ncb.Command = netbios.NCBRESET + ncb.Lana_num = ord(adapters.lana[i]) + if win32wnet.Netbios(ncb) != 0: + continue + ncb.Reset() + ncb.Command = netbios.NCBASTAT + ncb.Lana_num = ord(adapters.lana[i]) + ncb.Callname = '*'.ljust(16) + ncb.Buffer = status = netbios.ADAPTER_STATUS() + if win32wnet.Netbios(ncb) != 0: + continue + status._unpack() + bytes = map(ord, status.adapter_address) + return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) + + (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5]) + +# Thanks to Thomas Heller for ctypes and for his help with its use here. + +# If ctypes is available, use it to find system routines for UUID generation. +_uuid_generate_random = _uuid_generate_time = _UuidCreate = None +try: + import ctypes, ctypes.util + _buffer = ctypes.create_string_buffer(16) + + # The uuid_generate_* routines are provided by libuuid on at least + # Linux and FreeBSD, and provided by libc on Mac OS X. + for libname in ['uuid', 'c']: + try: + lib = ctypes.CDLL(ctypes.util.find_library(libname)) + except: + continue + if hasattr(lib, 'uuid_generate_random'): + _uuid_generate_random = lib.uuid_generate_random + if hasattr(lib, 'uuid_generate_time'): + _uuid_generate_time = lib.uuid_generate_time + + # On Windows prior to 2000, UuidCreate gives a UUID containing the + # hardware address. On Windows 2000 and later, UuidCreate makes a + # random UUID and UuidCreateSequential gives a UUID containing the + # hardware address. These routines are provided by the RPC runtime. + # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last + # 6 bytes returned by UuidCreateSequential are fixed, they don't appear + # to bear any relationship to the MAC address of any network device + # on the box. + try: + lib = ctypes.windll.rpcrt4 + except: + lib = None + _UuidCreate = getattr(lib, 'UuidCreateSequential', + getattr(lib, 'UuidCreate', None)) +except: + pass + +def _unixdll_getnode(): + """Get the hardware address on Unix using ctypes.""" + _uuid_generate_time(_buffer) + return UUID(bytes=_buffer.raw).node + +def _windll_getnode(): + """Get the hardware address on Windows using ctypes.""" + if _UuidCreate(_buffer) == 0: + return UUID(bytes=_buffer.raw).node + +def _random_getnode(): + """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" + import random + return random.randrange(0, 1<<48L) | 0x010000000000L + +_node = None + +def getnode(): + """Get the hardware address as a 48-bit positive integer. + + The first time this runs, it may launch a separate program, which could + be quite slow. If all attempts to obtain the hardware address fail, we + choose a random 48-bit number with its eighth bit set to 1 as recommended + in RFC 4122. + """ + + global _node + if _node is not None: + return _node + + import sys + if sys.platform == 'win32': + getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] + else: + getters = [_unixdll_getnode, _ifconfig_getnode] + + for getter in getters + [_random_getnode]: + try: + _node = getter() + except: + continue + if _node is not None: + return _node + +_last_timestamp = None + +def uuid1(node=None, clock_seq=None): + """Generate a UUID from a host ID, sequence number, and the current time. + If 'node' is not given, getnode() is used to obtain the hardware + address. If 'clock_seq' is given, it is used as the sequence number; + otherwise a random 14-bit sequence number is chosen.""" + + # When the system provides a version-1 UUID generator, use it (but don't + # use UuidCreate here because its UUIDs don't conform to RFC 4122). + if _uuid_generate_time and node is clock_seq is None: + _uuid_generate_time(_buffer) + return UUID(bytes=_buffer.raw) + + global _last_timestamp + import time + nanoseconds = int(time.time() * 1e9) + # 0x01b21dd213814000 is the number of 100-ns intervals between the + # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. + timestamp = int(nanoseconds/100) + 0x01b21dd213814000L + if timestamp <= _last_timestamp: + timestamp = _last_timestamp + 1 + _last_timestamp = timestamp + if clock_seq is None: + import random + clock_seq = random.randrange(1<<14L) # instead of stable storage + time_low = timestamp & 0xffffffffL + time_mid = (timestamp >> 32L) & 0xffffL + time_hi_version = (timestamp >> 48L) & 0x0fffL + clock_seq_low = clock_seq & 0xffL + clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL + if node is None: + node = getnode() + return UUID(fields=(time_low, time_mid, time_hi_version, + clock_seq_hi_variant, clock_seq_low, node), version=1) + +def uuid3(namespace, name): + """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + import md5 + hash = md5.md5(namespace.bytes + name).digest() + return UUID(bytes=hash[:16], version=3) + +def uuid4(): + """Generate a random UUID.""" + + # When the system provides a version-4 UUID generator, use it. + if _uuid_generate_random: + _uuid_generate_random(_buffer) + return UUID(bytes=_buffer.raw) + + # Otherwise, get randomness from urandom or the 'random' module. + try: + import os + return UUID(bytes=os.urandom(16), version=4) + except: + import random + bytes = [chr(random.randrange(256)) for i in range(16)] + return UUID(bytes=bytes, version=4) + +def uuid5(namespace, name): + """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" + import sha + hash = sha.sha(namespace.bytes + name).digest() + return UUID(bytes=hash[:16], version=5) + +# The following standard UUIDs are for use with uuid3() or uuid5(). + +NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') +NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') +NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') +NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') From d69113f3e20b717bdb1e9f8acfb8b6b5004218f8 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 4 Sep 2014 20:33:37 +0200 Subject: [PATCH 06/69] pass step_cmd to step stop --- python/helpers/pydev/pydevd_frame.py | 2 +- python/helpers/pydev/pydevd_plugins/django_debug.py | 4 ++-- python/helpers/pydev/pydevd_plugins/jinja2_debug.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 8b40f49697d1..85f6cb44bbf4 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -454,7 +454,7 @@ class PyDBFrame: stop_info['stop'] = False if True in stop_info.values(): - stopped_on_plugin = main_debugger.plugin_function('stop', frame, event, self._args, stop_info, arg) + stopped_on_plugin = main_debugger.plugin_function('stop', frame, event, self._args, stop_info, arg, step_cmd) if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin: if event == 'line': self.setSuspend(thread, step_cmd) diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py index 3f0143da419d..6d7910fe0ae2 100644 --- a/python/helpers/pydev/pydevd_plugins/django_debug.py +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -316,10 +316,10 @@ def cmd_step_over(mainDebugger, frame, event, args, stop_info): return False -def stop(mainDebugger, frame, event, args, stop_info, arg): +def stop(mainDebugger, frame, event, args, stop_info, arg, step_cmd): mainDebugger, filename, info, thread = args if DictContains(stop_info, 'django_stop') and stop_info['django_stop']: - frame = suspend_django(mainDebugger, mainDebugger, thread, frame) + frame = suspend_django(mainDebugger, mainDebugger, thread, frame, step_cmd) if frame: mainDebugger.doWaitSuspend(thread, frame, event, arg) return True diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py index 854d796676a5..e461800c4a35 100644 --- a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -279,10 +279,10 @@ def cmd_step_over(mainDebugger, frame, event, args, stop_info): return False -def stop(mainDebugger, frame, event, args, stop_info, arg): +def stop(mainDebugger, frame, event, args, stop_info, arg, step_cmd): mainDebugger, filename, info, thread = args if DictContains(stop_info, 'jinja2_stop') and stop_info['jinja2_stop']: - frame = suspend_jinja2(mainDebugger, mainDebugger, thread, frame) + frame = suspend_jinja2(mainDebugger, mainDebugger, thread, frame, step_cmd) if frame: mainDebugger.doWaitSuspend(thread, frame, event, arg) return True From 08f3326b1f172ad0ae13ee4ac02656ff0220eaf9 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 4 Sep 2014 21:01:01 +0200 Subject: [PATCH 07/69] fix PHP tests --- .../openapi/components/impl/stores/StateStorageManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index 1f136345560d..707153af9c9c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -343,7 +343,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di final Matcher matcher = MACRO_PATTERN.matcher(expanded); while (matcher.find()) { String m = matcher.group(1); - if (!myMacros.containsKey(m)) { + if (m != null && !myMacros.containsKey(m) && (!ApplicationManager.getApplication().isUnitTestMode() || !m.contains("\\com.jetbrains.php."))) { throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); } } From 85b24a86f554a23638d7db969deae32f9c8b0c42 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 4 Sep 2014 21:07:07 +0200 Subject: [PATCH 08/69] fix PHP tests --- .../impl/stores/StateStorageManagerImpl.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index 707153af9c9c..69a8a38a7901 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -340,11 +340,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di expanded = StringUtil.replace(expanded, macro, myMacros.get(macro)); } - final Matcher matcher = MACRO_PATTERN.matcher(expanded); - while (matcher.find()) { - String m = matcher.group(1); - if (m != null && !myMacros.containsKey(m) && (!ApplicationManager.getApplication().isUnitTestMode() || !m.contains("\\com.jetbrains.php."))) { - throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); + // PHP tests use $ as part of name and resulting project name will contain macros-like string + if (!ApplicationManager.getApplication().isUnitTestMode()) { + final Matcher matcher = MACRO_PATTERN.matcher(expanded); + while (matcher.find()) { + String m = matcher.group(1); + if (m != null && !myMacros.containsKey(m)) { + throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); + } } } From cf48408661b81848083cdba2e633812f12f23c7b Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 4 Sep 2014 23:14:55 +0200 Subject: [PATCH 09/69] cleanup --- .../logging/AdditionalTabComponent.java | 4 +- .../AdditionalTabComponentManager.java | 9 ++-- .../logging/DebuggerLogConsoleManager.java | 1 + .../diagnostic/logging/LogConsoleBase.java | 1 + .../diagnostic/logging/LogConsoleImpl.java | 34 ++++++------ .../diagnostic/logging/LogConsoleManager.java | 4 +- .../logging/LogConsoleManagerBase.java | 53 +++++-------------- .../diagnostic/logging/LogFilesManager.java | 4 +- .../intellij/execution/runners/RunTab.java | 2 +- .../xslt/run/HighlightingOutputConsole.java | 2 + .../xpath/xslt/run/XsltRunConfiguration.java | 42 +++++++-------- .../xsltDebugger/ui/AbstractTabComponent.java | 2 + 12 files changed, 67 insertions(+), 91 deletions(-) diff --git a/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java b/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java index b45abc181736..4991071477fb 100644 --- a/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java +++ b/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.diagnostic.logging; import com.intellij.openapi.ui.ComponentContainer; @@ -36,6 +35,7 @@ public abstract class AdditionalTabComponent extends JPanel implements Component protected AdditionalTabComponent() { } + @NotNull public abstract String getTabTitle(); @Nullable diff --git a/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java b/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java index 26f1273b2698..701f1b294003 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /* * Created by IntelliJ IDEA. * User: Anna.Kozlova @@ -23,8 +22,10 @@ package com.intellij.execution.configurations; import com.intellij.diagnostic.logging.AdditionalTabComponent; +import org.jetbrains.annotations.NotNull; public interface AdditionalTabComponentManager { - void addAdditionalTabComponent(AdditionalTabComponent component, final String id); - void removeAdditionalTabComponent(AdditionalTabComponent component); + void addAdditionalTabComponent(@NotNull AdditionalTabComponent component, @NotNull String id); + + void removeAdditionalTabComponent(@NotNull AdditionalTabComponent component); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java index 6f619641acc0..c24c0e869b97 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java @@ -16,6 +16,7 @@ package com.intellij.diagnostic.logging; +@Deprecated /** * User: anna * Date: 01-Feb-2006 diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java index c6226b65035e..f5882d92bcb4 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java @@ -249,6 +249,7 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L activate(); } + @NotNull @Override public String getTabTitle() { return myTitle; diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java index 5933634dfcbc..1f8a48d7c605 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java @@ -17,7 +17,7 @@ package com.intellij.diagnostic.logging; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +44,7 @@ public abstract class LogConsoleImpl extends LogConsoleBase { @NotNull File file, @NotNull Charset charset, long skippedContents, - String title, + @NotNull String title, final boolean buildInActions) { this(project, file, charset, skippedContents, title, buildInActions, GlobalSearchScope.allScope(project)); } @@ -53,7 +53,7 @@ public abstract class LogConsoleImpl extends LogConsoleBase { @NotNull File file, @NotNull Charset charset, long skippedContents, - String title, + @NotNull String title, final boolean buildInActions, final GlobalSearchScope searchScope) { super(project, getReader(file, charset, skippedContents), title, buildInActions, new DefaultLogFilterModel(project), @@ -64,27 +64,30 @@ public abstract class LogConsoleImpl extends LogConsoleBase { } @Nullable - private static Reader getReader(@NotNull final File file, @NotNull final Charset charset, final long skippedContents) { - Reader reader = null; + private static Reader getReader(@NotNull File file, @NotNull Charset charset, long skippedContents) { try { try { - final FileInputStream inputStream = new FileInputStream(file); - reader = new BufferedReader(new InputStreamReader(inputStream, charset)); - if (file.length() >= skippedContents) { //do not skip forward - //noinspection ResultOfMethodCallIgnored - inputStream.skip(skippedContents); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + FileInputStream inputStream = new FileInputStream(file); + //do not skip forward + if (file.length() >= skippedContents) { + long skipped = 0; + while (skipped < skippedContents) { + skipped += inputStream.skip(skippedContents - skipped); + } } + return new BufferedReader(new InputStreamReader(inputStream, charset)); } catch (FileNotFoundException ignored) { - if (FileUtil.createIfDoesntExist(file)) { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset)); + if (FileUtilRt.createIfNotExists(file)) { + return new BufferedReader(new InputStreamReader(new FileInputStream(file), charset)); } + return null; } } catch (Throwable ignored) { - reader = null; + return null; } - return reader; } @Override @@ -104,9 +107,10 @@ public abstract class LogConsoleImpl extends LogConsoleBase { return null; } - final long length = myFile.length(); + long length = myFile.length(); if (length < myOldLength) { reader.close(); + //noinspection IOResourceOpenedButNotSafelyClosed reader = new BufferedReader(new InputStreamReader(new FileInputStream(myFile), myCharset)); } myOldLength = length; diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java index 5f96721185a9..e5807c674b97 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java @@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull; import java.nio.charset.Charset; public interface LogConsoleManager extends AdditionalTabComponentManager { - void addLogConsole(String name, String path, @NotNull Charset charset, long skippedContent, @NotNull RunConfigurationBase runConfiguration); + void addLogConsole(@NotNull String name, @NotNull String path, @NotNull Charset charset, long skippedContent, @NotNull RunConfigurationBase runConfiguration); - void removeLogConsole(final String pathOrId); + void removeLogConsole(@NotNull String pathOrId); } diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java index 355f73f2a41e..6e65ede4e04e 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java @@ -28,21 +28,18 @@ import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManagerAdapter; import com.intellij.ui.content.ContentManagerEvent; import com.intellij.util.ArrayUtil; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; -import java.io.Reader; import java.nio.charset.Charset; -import java.util.HashMap; import java.util.Map; public abstract class LogConsoleManagerBase implements LogConsoleManager, Disposable { private final Project myProject; - - private final Map myAdditionalContent = new HashMap(); - + private final Map myAdditionalContent = new THashMap(); private final GlobalSearchScope mySearchScope; protected LogConsoleManagerBase(@NotNull Project project, @NotNull GlobalSearchScope searchScope) { @@ -50,18 +47,13 @@ public abstract class LogConsoleManagerBase implements LogConsoleManager, Dispos mySearchScope = searchScope; } - protected final Project getProject() { - return myProject; - } - @Override - public void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent, @NotNull RunConfigurationBase runConfiguration) { + public void addLogConsole(@NotNull String name, @NotNull String path, @NotNull Charset charset, long skippedContent, @NotNull RunConfigurationBase runConfiguration) { addLogConsole(name, path, charset, skippedContent, getDefaultIcon(), runConfiguration); } public void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent, Icon icon, @Nullable RunProfile runProfile) { doAddLogConsole(new LogConsoleImpl(myProject, new File(path), charset, skippedContent, name, false, mySearchScope) { - @Override public boolean isActive() { return isConsoleActive(path); @@ -69,23 +61,7 @@ public abstract class LogConsoleManagerBase implements LogConsoleManager, Dispos }, path, icon, runProfile); } - public void addLogConsole(String name, Reader reader, final String id, Icon icon, @Nullable RunProfile runProfile) { - doAddLogConsole(new LogConsoleBase(myProject, - reader, - name, - false, - new DefaultLogFilterModel(myProject), mySearchScope) { - - @Override - public boolean isActive() { - return isConsoleActive(id); - } - }, id, icon, runProfile); - } - - private void doAddLogConsole(final LogConsoleBase log, - final String id, - Icon icon, @Nullable RunProfile runProfile) { + private void doAddLogConsole(@NotNull final LogConsoleBase log, String id, Icon icon, @Nullable RunProfile runProfile) { if (runProfile instanceof RunConfigurationBase) { ((RunConfigurationBase)runProfile).customizeLogConsole(log); } @@ -106,33 +82,28 @@ public abstract class LogConsoleManagerBase implements LogConsoleManager, Dispos } @Override - public void removeLogConsole(final String path) { - final Content content = getUi().findContent(path); + public void removeLogConsole(@NotNull String path) { + Content content = getUi().findContent(path); if (content != null) { - final LogConsoleBase log = (LogConsoleBase)content.getComponent(); - removeAdditionalTabComponent(log); + removeAdditionalTabComponent((LogConsoleBase)content.getComponent()); } } @Override - public void addAdditionalTabComponent(final AdditionalTabComponent tabComponent, final String id) { + public void addAdditionalTabComponent(@NotNull AdditionalTabComponent tabComponent, @NotNull String id) { addAdditionalTabComponent(tabComponent, id, getDefaultIcon()); } - public Content addAdditionalTabComponent(final AdditionalTabComponent tabComponent, String id, Icon icon) { - final Content logContent = createLogContent(tabComponent, id, icon); + public Content addAdditionalTabComponent(@NotNull AdditionalTabComponent tabComponent, @NotNull String id, @Nullable Icon icon) { + Content logContent = getUi().createContent(id, (ComponentWithActions)tabComponent, tabComponent.getTabTitle(), icon, + tabComponent.getPreferredFocusableComponent()); myAdditionalContent.put(tabComponent, logContent); getUi().addContent(logContent); return logContent; } - protected Content createLogContent(AdditionalTabComponent tabComponent, String id, Icon icon) { - return getUi().createContent(id, (ComponentWithActions)tabComponent, tabComponent.getTabTitle(), icon, - tabComponent.getPreferredFocusableComponent()); - } - @Override - public void removeAdditionalTabComponent(AdditionalTabComponent component) { + public void removeAdditionalTabComponent(@NotNull AdditionalTabComponent component) { Disposer.dispose(component); final Content content = myAdditionalContent.remove(component); if (!getUi().isDisposed()) { diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java index 9259dad358c3..0f95b541ce8a 100644 --- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java +++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java @@ -18,8 +18,6 @@ package com.intellij.diagnostic.logging; import com.intellij.execution.configurations.LogFileOptions; import com.intellij.execution.configurations.RunConfigurationBase; import com.intellij.execution.process.ProcessHandler; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import org.jetbrains.annotations.NotNull; @@ -32,7 +30,7 @@ import java.util.TreeMap; public class LogFilesManager { private final LogConsoleManager myManager; - public LogFilesManager(@NotNull final Project project, @NotNull LogConsoleManager manager, @NotNull Disposable parentDisposable) { + public LogFilesManager(@NotNull LogConsoleManager manager) { myManager = manager; } diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java index d6a6e136beae..e2263adb1f55 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java @@ -117,7 +117,7 @@ public abstract class RunTab implements DataProvider, Disposable { if (runConfiguration instanceof RunConfigurationBase && processHandler != null) { RunConfigurationBase configuration = (RunConfigurationBase)runConfiguration; if (myManager == null) { - myManager = new LogFilesManager(myProject, getLogConsoleManager(), contentDescriptor); + myManager = new LogFilesManager(getLogConsoleManager()); } myManager.addLogConsoles(configuration, processHandler); OutputFileUtil.attachDumpListener(configuration, processHandler, console); diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java index 350973b4369d..90f088d86ad6 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java @@ -29,6 +29,7 @@ import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -107,6 +108,7 @@ public class HighlightingOutputConsole extends AdditionalTabComponent implements } } + @NotNull public String getTabTitle() { return TAB_TITLE; } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java index b45a08825d01..8cf2c67d4bc9 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java @@ -15,7 +15,6 @@ */ package org.intellij.lang.xpath.xslt.run; -import com.intellij.diagnostic.logging.DebuggerLogConsoleManager; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; @@ -140,32 +139,29 @@ public final class XsltRunConfiguration extends LocatableConfigurationBase imple return state; } - //invoke before run/debug tabs are shown. - //Should be overriden to add additional tabs for run/debug toolwindow @Override public void createAdditionalTabComponents(final AdditionalTabComponentManager manager, ProcessHandler startedProcess) { - if (myOutputType == OutputType.CONSOLE) { - final HighlightingOutputConsole console = new HighlightingOutputConsole(getProject(), myFileType); + if (myOutputType == OutputType.CONSOLE) { + final HighlightingOutputConsole console = new HighlightingOutputConsole(getProject(), myFileType); - final List extensions = XsltRunnerExtension.getExtensions(this, manager instanceof DebuggerLogConsoleManager); - boolean consoleTabAdded = false; - for (XsltRunnerExtension extension : extensions) { - if (extension.createTabs(getProject(), manager, console, startedProcess)) { - consoleTabAdded = true; - } - } - if (!consoleTabAdded) { - manager.addAdditionalTabComponent(console, console.getTabTitle()); // TODO: verify parameter - } - - final OutputTabAdapter listener = new OutputTabAdapter(startedProcess, console); - - if (startedProcess.isStartNotified()) { - listener.startNotified(new ProcessEvent(startedProcess)); - } else { - startedProcess.addProcessListener(listener); - } + boolean consoleTabAdded = false; + for (XsltRunnerExtension extension : XsltRunnerExtension.getExtensions(this, false /* doesn't matter, xslt debugger uses own flag */)) { + if (extension.createTabs(getProject(), manager, console, startedProcess)) { + consoleTabAdded = true; + } } + if (!consoleTabAdded) { + manager.addAdditionalTabComponent(console, console.getTabTitle()); // TODO: verify parameter + } + + final OutputTabAdapter listener = new OutputTabAdapter(startedProcess, console); + if (startedProcess.isStartNotified()) { + listener.startNotified(new ProcessEvent(startedProcess)); + } + else { + startedProcess.addProcessListener(listener); + } + } } @Override diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java index 6efb2221d135..0dadd1db18ab 100644 --- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java +++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java @@ -1,6 +1,7 @@ package org.intellij.plugins.xsltDebugger.ui; import com.intellij.diagnostic.logging.AdditionalTabComponent; +import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -16,6 +17,7 @@ abstract class AbstractTabComponent extends AdditionalTabComponent { myTabTitle = tabTitle; } + @NotNull @Override public String getTabTitle() { return myTabTitle; From cbf6781d00da109cff55efcc3041616966311f01 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 24 Jul 2014 17:41:24 +0200 Subject: [PATCH 10/69] commands for jinja2 exception breakpoint (cherry picked from commit 8131998) --- .../com/jetbrains/python/debugger/pydev/AbstractCommand.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index f92d8d110b80..b1fd58c4bd10 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -33,6 +33,8 @@ public abstract class AbstractCommand { public static final int SMART_STEP_INTO = 128; public static final int EXIT = 129; public static final int CALL_SIGNATURE_TRACE = 130; + public static final int ADD_JINJA2_EXCEPTION_BREAKPOINT = 131; + public static final int REMOVE_JINJA2_EXCEPTION_BREAKPOINT = 132; public static final int CMD_RUN_CUSTOM_OPERATION = 135; public static final int SHOW_CONSOLE = 142; public static final int ERROR = 901; From cffddb8d7b8336356def702426d21f443d03dae1 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Tue, 12 Aug 2014 18:12:11 +0200 Subject: [PATCH 11/69] rewrite adding and removing breakpoints with plugins (cherry picked from commit f0e8831) --- .../pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java | 2 +- .../com/jetbrains/python/debugger/pydev/AbstractCommand.java | 4 ---- .../python/debugger/PyExceptionBreakpointProperties.java | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java index c01be15384ab..7fffc636a9fb 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java @@ -80,7 +80,7 @@ public class PyThreadInfo { } public boolean isExceptionBreak() { - return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT || myStopReason == AbstractCommand.ADD_DJANGO_EXCEPTION_BREAKPOINT; + return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT; } @Override diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index b1fd58c4bd10..d13addaade04 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -28,13 +28,9 @@ public abstract class AbstractCommand { public static final int ADD_EXCEPTION_BREAKPOINT = 122; public static final int REMOVE_EXCEPTION_BREAKPOINT = 123; public static final int LOAD_SOURCE = 124; - public static final int ADD_DJANGO_EXCEPTION_BREAKPOINT = 125; - public static final int REMOVE_DJANGO_EXCEPTION_BREAKPOINT = 126; public static final int SMART_STEP_INTO = 128; public static final int EXIT = 129; public static final int CALL_SIGNATURE_TRACE = 130; - public static final int ADD_JINJA2_EXCEPTION_BREAKPOINT = 131; - public static final int REMOVE_JINJA2_EXCEPTION_BREAKPOINT = 132; public static final int CMD_RUN_CUSTOM_OPERATION = 135; public static final int SHOW_CONSOLE = 142; public static final int ERROR = 901; diff --git a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java index 7799cfccdfa3..93f9d89e386c 100644 --- a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java +++ b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java @@ -79,6 +79,10 @@ public class PyExceptionBreakpointProperties extends ExceptionBreakpointProperti myNotifyOnlyOnFirst = notifyOnlyOnFirst; } + public String getException() { + return "python-" + myException; + } + @Override public ExceptionBreakpointCommand createAddCommand(RemoteDebugger debugger) { return ExceptionBreakpointCommand.addExceptionBreakpointCommand(debugger, getException(), From 3d6b55255bc7beb907f6357dfe855386fb61fe65 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 5 Sep 2014 01:04:34 +0200 Subject: [PATCH 12/69] Handle absent options of exception breaks. --- python/helpers/pydev/pydevd.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 2b9b4ee94a1c..de9231f2f293 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -1038,7 +1038,11 @@ class PyDB: pass elif cmd_id == CMD_ADD_EXCEPTION_BREAK: - exception, notify_always, notify_on_terminate = text.split('\t', 2) + if text.find(' ')!= -1: + exception, notify_always, notify_on_terminate = text.split('\t', 2) + else: + exception, notify_always, notify_on_terminate = text, 0, 0 + if exception.find('-') != -1: type, exception = exception.split('-') else: From 7bef498071d09e655d503acb7ce0b127a7f72a94 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 5 Sep 2014 05:00:46 +0400 Subject: [PATCH 13/69] ability to insert fragments --- .../src/com/intellij/ui/SimpleColoredText.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java index af851951e363..8c899f1a6b5c 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -45,6 +45,12 @@ public class SimpleColoredText implements ColoredTextContainer { myAttributes.add(attributes); } + public void insert(int index, @NotNull String fragment, @NotNull SimpleTextAttributes attributes) { + myTexts.add(index, fragment); + myCachedToString = null; + myAttributes.add(index, attributes); + } + @Override public void append(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, Object tag) { append(fragment, attributes); From 4c5fe690074bae796458f790accf8e9e6165b7c0 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 5 Sep 2014 05:02:33 +0400 Subject: [PATCH 14/69] make point protected and add parameterless method invoke --- .../impl/evaluate/quick/common/AbstractValueHint.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java index 7b860b49d255..c24ce74df1c6 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java @@ -65,7 +65,7 @@ public abstract class AbstractValueHint { private final Project myProject; private final Editor myEditor; private final ValueHintType myType; - private final Point myPoint; + protected final Point myPoint; private LightweightHint myCurrentHint; private boolean myHintHidden; private TextRange myCurrentRange; @@ -132,6 +132,10 @@ public abstract class AbstractValueHint { } } + public void invokeHint() { + invokeHint(null); + } + public void invokeHint(Runnable hideRunnable) { myHideRunnable = hideRunnable; From 2039e71c649c10e8975c7abae1cf0592f956584b Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Fri, 5 Sep 2014 05:05:56 +0400 Subject: [PATCH 15/69] make all debugger value hints expand by keyboard shortcut --- .../impl/evaluate/quick/XValueHint.java | 45 ++++++++++++++++++- .../impl/frame/XVariablesViewBase.java | 38 +--------------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java index ca78932701d2..37b641e1042e 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -20,15 +20,23 @@ import com.intellij.execution.console.LanguageConsoleImpl; import com.intellij.execution.console.LanguageConsoleView; import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ShortcutSet; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredText; +import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Consumer; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerUtil; @@ -68,6 +76,8 @@ public class XValueHint extends AbstractValueHint { private final String myExpression; private final String myValueName; private final @Nullable XSourcePosition myExpressionPosition; + private final ExpressionInfo myExpressionInfo; + private Disposable myDisposable; public XValueHint(@NotNull Project project, @NotNull Editor editor, @NotNull Point point, @NotNull ValueHintType type, @NotNull ExpressionInfo expressionInfo, @NotNull XDebuggerEvaluator evaluator, @@ -78,6 +88,7 @@ public class XValueHint extends AbstractValueHint { myDebugSession = session; myExpression = XDebuggerEvaluateActionHandler.getExpressionText(expressionInfo, editor.getDocument()); myValueName = XDebuggerEvaluateActionHandler.getDisplayText(expressionInfo, editor.getDocument()); + myExpressionInfo = expressionInfo; VirtualFile file; ConsoleView consoleView = ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW.get(editor); @@ -97,6 +108,33 @@ public class XValueHint extends AbstractValueHint { return true; } + @Override + protected boolean showHint(final JComponent component) { + boolean result = super.showHint(component); + if (result && getType() == ValueHintType.MOUSE_OVER_HINT) { + myDisposable = Disposer.newDisposable(); + ShortcutSet shortcut = ActionManager.getInstance().getAction("ShowErrorDescription").getShortcutSet(); + new DumbAwareAction() { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + hideHint(); + final Point point = new Point(myPoint.x, myPoint.y + getEditor().getLineHeight()); + new XValueHint(getProject(), getEditor(), point, ValueHintType.MOUSE_CLICK_HINT, myExpressionInfo, myEvaluator, myDebugSession).invokeHint(); + } + }.registerCustomShortcutSet(shortcut, getEditor().getContentComponent(), myDisposable); + } + return result; + } + + @Override + public void hideHint() { + super.hideHint(); + if (myDisposable != null) { + Disposer.dispose(myDisposable); + + } + } + @Override protected void evaluateAndShowHint() { myEvaluator.evaluate(myExpression, new XEvaluationCallbackBase() { @@ -136,6 +174,11 @@ public class XValueHint extends AbstractValueHint { showTree(result); } else { + if (getType() == ValueHintType.MOUSE_OVER_HINT) { + text.insert(0, "(" + KeymapUtil.getFirstKeyboardShortcutText("ShowErrorDescription") + ") ", + SimpleTextAttributes.GRAYED_ATTRIBUTES); + } + JComponent component = createExpandableHintComponent(text, new Runnable() { @Override public void run() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java index 635f57bf5edf..5872d41b4b84 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java @@ -17,8 +17,6 @@ package com.intellij.xdebugger.impl.frame; import com.intellij.ide.dnd.DnDManager; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; @@ -28,8 +26,6 @@ import com.intellij.openapi.editor.event.SelectionListener; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl; -import com.intellij.openapi.keymap.KeymapUtil; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; @@ -37,8 +33,6 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.SimpleColoredText; -import com.intellij.ui.SimpleTextAttributes; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XSourcePosition; @@ -126,38 +120,8 @@ public abstract class XVariablesViewBase extends XDebugView { final int offset = range.getStartOffset(); final LogicalPosition pos = editor.offsetToLogicalPosition(offset); final Point point = editor.logicalPositionToXY(pos); - final Point fullPopupPoint = new Point(point.x, point.y + editor.getLineHeight()); - final Disposable disposable = Disposer.newDisposable(); - final CustomShortcutSet expandShortcut = CustomShortcutSet.fromString("F2");//todo[kb] remove hardcoded shortcut - new DumbAwareAction() { - @Override - public void actionPerformed(AnActionEvent e) { - new XValueHint(project, editor, fullPopupPoint, ValueHintType.MOUSE_CLICK_HINT, info, evaluator, - session).invokeHint(new Runnable() { - public void run() { - } - }); - } - }.registerCustomShortcutSet(expandShortcut, editor.getComponent(), disposable); - - new XValueHint(project, editor, point, ValueHintType.MOUSE_OVER_HINT, info, evaluator, session) { - @Override - protected JComponent createExpandableHintComponent(SimpleColoredText text, Runnable expand) { - final SimpleColoredText patched = new SimpleColoredText(); - patched.append("(Press " + KeymapUtil.getShortcutsText(expandShortcut.getShortcuts()) + ") ", SimpleTextAttributes.GRAY_ATTRIBUTES); - for (int i = 0; i < text.getTexts().size(); i++) { - patched.append(text.getTexts().get(i), text.getAttributes().get(i)); - } - return super.createExpandableHintComponent(patched, expand); - } - }.invokeHint( - new Runnable() { - @Override - public void run() { - Disposer.dispose(disposable); - } - }); + new XValueHint(project, editor, point, ValueHintType.MOUSE_OVER_HINT, info, evaluator, session).invokeHint(); } finally { token.finish(); From 40048ccc8966aeb632dfcd5cb16265075cc8010b Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 5 Sep 2014 04:42:12 +0200 Subject: [PATCH 16/69] Debugger plugins refactored. --- python/helpers/pydev/pydevd.py | 115 ++++-------------- python/helpers/pydev/pydevd_frame.py | 23 ++-- python/helpers/pydev/pydevd_plugin_utils.py | 46 +++++++ .../pydev/pydevd_plugins/django_debug.py | 32 ++--- .../pydev/pydevd_plugins/jinja2_debug.py | 32 +++-- 5 files changed, 110 insertions(+), 138 deletions(-) create mode 100644 python/helpers/pydev/pydevd_plugin_utils.py diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index de9231f2f293..5db8daa490b1 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -9,7 +9,8 @@ pydev_monkey_qt.patch_qt() import traceback -from pluginbase import PluginBase +from pydevd_plugin_utils import load_plugins, NullProxy, PluginProxy + from pydevd_frame import add_exception_to_frame import pydev_imports from pydevd_breakpoints import * #@UnusedWildImport @@ -347,13 +348,9 @@ class PyDB: self.filename_to_lines_where_exceptions_are_ignored = {} #working with plugins - self.usable_plugin = None - self.plugins = [] - #we call this functions very often, so we need cache them - self.can_not_skip_cache = None - self.has_exception_breaks_cache = None - self.load_plugins() + self.plugins = load_plugins('pydevd_plugins') + self.plugin = NullProxy() def haveAliveThreads(self): @@ -861,10 +858,13 @@ class PyDB: file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint supported_type = True else: - supported_type, result = self.add_plugin_breakpoint('add_line_breakpoint', type, file, line, condition, expression, func_name) - if supported_type: + result = self.add_plugin_breakpoint('add_line_breakpoint', type, file, line, condition, expression, func_name) + if result is not None: + supported_type = True breakpoint, breakpoints = result file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint + else: + supported_type = False if not supported_type: raise NameError(type) @@ -904,8 +904,8 @@ class PyDB: breakpoints = self.breakpoints file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint else: - supported_type, result = self.plugin_func_with_result('get_breakpoints', breakpoint_type) - if supported_type: + result = self.plugin.get_breakpoints(self, breakpoint_type) + if result is not None: file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint breakpoints = result @@ -1038,7 +1038,7 @@ class PyDB: pass elif cmd_id == CMD_ADD_EXCEPTION_BREAK: - if text.find(' ')!= -1: + if text.find(' ') != -1: exception, notify_always, notify_on_terminate = text.split('\t', 2) else: exception, notify_always, notify_on_terminate = text, 0, 0 @@ -1086,7 +1086,7 @@ class PyDB: pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]) update_exception_hook(self) else: - supported_type = self.plugin_function('remove_exception_breakpoint', type, exception) + supported_type = self.plugin.remove_exception_breakpoint(self, type, exception) if not supported_type: raise NameError(type) @@ -1109,7 +1109,7 @@ class PyDB: elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK: exception = text - self.plugin_function('remove_exception_breakpoint', 'django', exception) + self.plugin.remove_exception_breakpoint(self, 'django', exception) elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION: # Command which takes care for the debug console communication @@ -1590,83 +1590,18 @@ class PyDB: cmd = self.cmdFactory.makeExitMessage() self.writer.addCommand(cmd) - def load_plugins(self): - plugin_base = PluginBase(package='pydevd_plugins') - self.plugin_source = plugin_base.make_plugin_source(searchpath=[os.path.dirname(os.path.realpath(__file__)) + '/pydevd_plugins']) - for plugin in self.plugin_source.list_plugins(): - loaded_plugin = None - try: - loaded_plugin = self.plugin_source.load_plugin(plugin) - except: - pydev_log.error("Failed to load plugin %s" % plugin) - if loaded_plugin: - self.plugins.append(loaded_plugin) - def add_plugin_breakpoint(self, func_name, *args, **kwargs): - #add breakpoint from plugin and remember usable plugin - for loaded_plugin in self.plugins: - if hasattr(loaded_plugin, func_name): - func = getattr(loaded_plugin, func_name) - result_exist, result = func(self, *args, **kwargs) - if result_exist: - self.usable_plugin = loaded_plugin - return result_exist, result - return False, None - - def can_not_skip_from_plugin(self, *args, **kwargs): - if not self.usable_plugin: - return False - if not self.can_not_skip_cache: - loaded_plugin = self.usable_plugin - can_not_skip_fun = getattr(loaded_plugin, 'can_not_skip', None) - if can_not_skip_fun: - self.can_not_skip_cache = can_not_skip_fun - else: - pydev_log.error("Implementation for function 'can_not_skip' is necessary in plugin %s" % loaded_plugin) - return False - func = self.can_not_skip_cache - if func(self, *args, **kwargs): - return True - return False - - def has_exception_breaks_from_plugin(self, *args, **kwargs): - if not self.usable_plugin: - return False - if not self.has_exception_breaks_cache: - loaded_plugin = self.usable_plugin - has_exc_b_fun = getattr(loaded_plugin, 'has_exception_breaks', None) - if has_exc_b_fun: - self.has_exception_breaks_cache = has_exc_b_fun - else: - pydev_log.error("Implementation for function 'has_exception_breaks' is necessary in plugin %s" % loaded_plugin) - return False - func = self.has_exception_breaks_cache - if func(self, *args, **kwargs): - return True - return False - - def plugin_function(self, func_name, *args, **kwargs): - #call function from plugin - if not self.usable_plugin: - return False - loaded_plugin = self.usable_plugin - if hasattr(loaded_plugin, func_name): - func = getattr(loaded_plugin, func_name) - if func(self, *args, **kwargs): - return True - return False - - def plugin_func_with_result(self, func_name, *args, **kwargs): - #call function from plugin and return its result - if not self.usable_plugin: - return False, None - loaded_plugin = self.usable_plugin - if hasattr(loaded_plugin, func_name): - func = getattr(loaded_plugin, func_name) - result_exist, result = func(self, *args, **kwargs) - if result_exist: - return result_exist, result - return False, None + # add breakpoint from plugin and remember plugin to use + for plugin in self.plugins: + if hasattr(plugin, func_name): + func = getattr(plugin, func_name) + result = func(self, *args, **kwargs) + if result: + # On adding breakpoint we override plugin that will be used + # That means that we don't work with more then 1 plugin at a time + self.plugin = plugin + return result + return None def wait_for_commands(self, globals): thread = threading.currentThread() diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 85f6cb44bbf4..349d54a68391 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -97,8 +97,8 @@ class PyDBFrame: flag = False else: try: - exist_result, result = mainDebugger.plugin_func_with_result('exception_break', self, frame, event, self._args, arg) - if exist_result: + result = mainDebugger.plugin.exception_break(mainDebugger, self, frame, event, self._args, arg) + if result: (flag, frame) = result except: @@ -243,7 +243,7 @@ class PyDBFrame: is_exception_event = event == 'exception' has_exception_breakpoints = main_debugger.break_on_caught_exceptions \ - or main_debugger.has_exception_breaks_from_plugin() + or main_debugger.plugin.has_exception_breaks(main_debugger) if is_exception_event: if has_exception_breakpoints: @@ -284,7 +284,7 @@ class PyDBFrame: or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame) if can_skip: - can_skip = not main_debugger.can_not_skip_from_plugin(frame) + can_skip = main_debugger.plugin.can_skip(main_debugger, frame) # Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint, # we will return nothing for the next trace @@ -339,8 +339,9 @@ class PyDBFrame: if info.pydev_step_cmd == CMD_STEP_OVER and info.pydev_step_stop is frame and event in ('line', 'return'): stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later) else: - exist_result, result = main_debugger.plugin_func_with_result('get_breakpoint', frame, event, self._args) - if exist_result: + result = main_debugger.plugin.get_breakpoint(main_debugger, frame, event, self._args) + if result: + exist_result = True (flag, breakpoint, new_frame) = result if breakpoint: @@ -369,8 +370,8 @@ class PyDBFrame: if stop_info['stop']: self.setSuspend(thread, CMD_SET_BREAK) elif flag: - exist_result, result = main_debugger.plugin_func_with_result('suspend', self, thread, frame) - if exist_result: + result = main_debugger.plugin.suspend(main_debugger, self, thread, frame) + if result: frame = result # if thread has a suspend flag, we suspend with a busy wait @@ -401,11 +402,11 @@ class PyDBFrame: elif step_cmd == CMD_STEP_INTO: stop_info['stop'] = event in ('line', 'return') - main_debugger.plugin_function('cmd_step_into', frame, event, self._args, stop_info) + main_debugger.plugin.cmd_step_into(main_debugger, frame, event, self._args, stop_info) elif step_cmd == CMD_STEP_OVER: stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return') - main_debugger.plugin_function('cmd_step_over', frame, event, self._args, stop_info) + main_debugger.plugin.cmd_step_over(main_debugger, frame, event, self._args, stop_info) elif step_cmd == CMD_SMART_STEP_INTO: stop_info['stop'] = False @@ -454,7 +455,7 @@ class PyDBFrame: stop_info['stop'] = False if True in stop_info.values(): - stopped_on_plugin = main_debugger.plugin_function('stop', frame, event, self._args, stop_info, arg, step_cmd) + stopped_on_plugin = main_debugger.plugin.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd) if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin: if event == 'line': self.setSuspend(thread, step_cmd) diff --git a/python/helpers/pydev/pydevd_plugin_utils.py b/python/helpers/pydev/pydevd_plugin_utils.py new file mode 100644 index 000000000000..76f031049299 --- /dev/null +++ b/python/helpers/pydev/pydevd_plugin_utils.py @@ -0,0 +1,46 @@ +import os + +import pydev_log +from pluginbase import PluginBase + + + +def load_plugins(package): + plugin_base = PluginBase(package=package) + plugin_source = plugin_base.make_plugin_source(searchpath=[os.path.dirname(os.path.realpath(__file__)) + '/' + package], persist=True) + plugins = [] + for plugin in plugin_source.list_plugins(): + loaded_plugin = None + try: + loaded_plugin = plugin_source.load_plugin(plugin) + except: + pydev_log.error("Failed to load plugin %s" % plugin) + if loaded_plugin: + plugins.append(loaded_plugin) + + return plugins + + +class NullProxy(object): + def __init__(self): + def foo(*args, **kwargs): + return None + self.null_func = foo + + def __getattr__(self, name): + return self.null_func + +class PluginProxy(object): + def __init__(self, plugin): + self.plugin = plugin + self.cache = {} + + def __getattr__(self, name): + if not hasattr(self.cache, name): + self.cache[name] = getattr(self.plugin, name) + + return self.cache[name] + + + + diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py index 6d7910fe0ae2..eb5d1876c595 100644 --- a/python/helpers/pydev/pydevd_plugins/django_debug.py +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -22,14 +22,12 @@ class DjangoLineBreakpoint(LineBreakpoint): def add_line_breakpoint(pydb, type, file, line, condition, expression, func_name): - result = None if type == 'django-line': breakpoint = DjangoLineBreakpoint(file, line, condition, func_name, expression) if not hasattr(pydb, 'django_breakpoints'): pydb.django_breakpoints = {} - result = breakpoint, pydb.django_breakpoints - return True, result - return False, result + return breakpoint, pydb.django_breakpoints + return None def add_exception_breakpoint(pydb, type, exception): if type == 'django': @@ -37,8 +35,8 @@ def add_exception_breakpoint(pydb, type, exception): pydb.django_exception_break = {} pydb.django_exception_break[exception] = True pydb.setTracingForUntracedContexts() - return True, None - return False, None + return True + return False def remove_exception_breakpoint(pydb, type, exception): @@ -52,8 +50,8 @@ def remove_exception_breakpoint(pydb, type, exception): def get_breakpoints(pydb): if type == 'django-line': - return True, pydb.django_breakpoints - return False, None + return pydb.django_breakpoints + return None def inherits(cls, *names): if cls.__name__ in names: @@ -278,13 +276,13 @@ def just_raised(trace): # Django Step Commands #======================================================================================================================= -def can_not_skip(mainDebugger, frame): +def can_skip(mainDebugger, frame): if hasattr(mainDebugger, 'django_breakpoints') and mainDebugger.django_breakpoints and is_django_render_call(frame): filename = get_template_file_name(frame) django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename) if django_breakpoints_for_file: - return True - return False + return False + return True def has_exception_breaks(mainDebugger): return hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break @@ -330,9 +328,7 @@ def get_breakpoint(mainDebugger, frame, event, args): mainDebugger, filename, info, thread = args flag = False django_breakpoint = None - result = None new_frame = None - is_result_exist = False if event == 'call' and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'django_breakpoints') and \ mainDebugger.django_breakpoints and is_django_render_call(frame): @@ -345,16 +341,14 @@ def get_breakpoint(mainDebugger, frame, event, args): pydev_log.debug("Tracing template line: %d\n" % template_line) if DictContains(django_breakpoints_for_file, template_line): - is_result_exist = True django_breakpoint = django_breakpoints_for_file[template_line] flag = True new_frame = DjangoTemplateFrame(frame) - result = flag, django_breakpoint, new_frame - return is_result_exist, result + return flag, django_breakpoint, new_frame def suspend(mainDebugger, pydb_frame, thread, frame): - return True, suspend_django(pydb_frame, mainDebugger, thread, frame) + return suspend_django(pydb_frame, mainDebugger, thread, frame) def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): mainDebugger, filename, info, thread = args @@ -371,5 +365,5 @@ def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): thread.additionalInfo.message = 'VariableDoesNotExist' suspend_frame.f_back = frame frame = suspend_frame - return True, (flag, frame) - return False, None \ No newline at end of file + return (flag, frame) + return None \ No newline at end of file diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py index e461800c4a35..52f94384460c 100644 --- a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -25,8 +25,8 @@ def add_line_breakpoint(pydb, type, file, line, condition, func_name, expression if not hasattr(pydb, 'jinja2_breakpoints'): pydb.jinja2_breakpoints = {} result = breakpoint, pydb.jinja2_breakpoints - return True, result - return False, result + return result + return result def add_exception_breakpoint(pydb, type, exception): if type == 'jinja2': @@ -34,8 +34,8 @@ def add_exception_breakpoint(pydb, type, exception): pydb.jinja2_exception_break = {} pydb.jinja2_exception_break[exception] = True pydb.setTracingForUntracedContexts() - return True, None - return False, None + return True + return False def remove_exception_breakpoint(pydb, type, exception): if type == 'jinja2': @@ -48,8 +48,8 @@ def remove_exception_breakpoint(pydb, type, exception): def get_breakpoints(pydb, type): if type == 'jinja2-line': - return True, pydb.jinja2_breakpoints - return False, None + return pydb.jinja2_breakpoints + return None def is_jinja2_render_call(frame): @@ -196,13 +196,13 @@ def get_jinja2_template_filename(frame): def has_exception_breaks(mainDebugger): return hasattr(mainDebugger, 'jinja2_exception_break') and mainDebugger.jinja2_exception_break -def can_not_skip(mainDebugger, frame): +def can_skip(mainDebugger, frame): if hasattr(mainDebugger, 'jinja2_breakpoints') and mainDebugger.jinja2_breakpoints and is_jinja2_render_call(frame): filename = get_jinja2_template_filename(frame) jinja2_breakpoints_for_file = mainDebugger.jinja2_breakpoints.get(filename) if jinja2_breakpoints_for_file: - return True - return False + return False + return True def cmd_step_into(mainDebugger, frame, event, args, stop_info): @@ -291,8 +291,6 @@ def stop(mainDebugger, frame, event, args, stop_info, arg, step_cmd): def get_breakpoint(mainDebugger, frame, event, args): mainDebugger, filename, info, thread = args - is_result_exist = False - result = None new_frame = None jinja2_breakpoint = None flag = False @@ -306,17 +304,15 @@ def get_breakpoint(mainDebugger, frame, event, args): lineno = frame.f_lineno template_lineno = get_jinja2_template_line(frame) if template_lineno is not None and DictContains(jinja2_breakpoints_for_file, template_lineno): - is_result_exist = True jinja2_breakpoint = jinja2_breakpoints_for_file[template_lineno] flag = True new_frame = Jinja2TemplateFrame(frame) - result = flag, jinja2_breakpoint, new_frame - return is_result_exist, result + return flag, jinja2_breakpoint, new_frame def suspend(mainDebugger, pydb_frame, thread, frame): - return True, suspend_jinja2(pydb_frame, mainDebugger, thread, frame) + return suspend_jinja2(pydb_frame, mainDebugger, thread, frame) def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): @@ -333,7 +329,7 @@ def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): flag = True suspend_frame.f_back = frame frame = suspend_frame - return True, (flag, frame) + return (flag, frame) elif get_exception_name(exception) in ('TemplateSyntaxError', 'TemplateAssertionError'): #errors in compile time name = frame.f_code.co_name @@ -343,5 +339,5 @@ def exception_break(mainDebugger, pydb_frame, frame, event, args, arg): add_exception_to_frame(frame, (exception, value, trace)) thread.additionalInfo.suspend_type = JINJA2_SUSPEND flag = True - return True, (flag, frame) - return False, None \ No newline at end of file + return (flag, frame) + return None \ No newline at end of file From b7bdfcfb0084a50ef90fd974c41e894ea2418333 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 5 Sep 2014 04:48:41 +0200 Subject: [PATCH 17/69] Remove code duplication. --- python/helpers/pydev/pydevd.py | 2 +- python/helpers/pydev/pydevd_frame.py | 5 ++--- python/helpers/pydev/pydevd_frame_utils.py | 3 +++ python/helpers/pydev/pydevd_plugins/django_debug.py | 8 +------- python/helpers/pydev/pydevd_plugins/jinja2_debug.py | 7 +------ 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 5db8daa490b1..c0a3d3723ba9 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -11,7 +11,7 @@ import traceback from pydevd_plugin_utils import load_plugins, NullProxy, PluginProxy -from pydevd_frame import add_exception_to_frame +from pydevd_frame_utils import add_exception_to_frame import pydev_imports from pydevd_breakpoints import * #@UnusedWildImport import fix_getpass diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 349d54a68391..704d77b3ca38 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -15,6 +15,8 @@ from pydevd_comm import CMD_ADD_DJANGO_EXCEPTION_BREAK, \ CMD_STEP_INTO, CMD_SMART_STEP_INTO, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT from pydevd_constants import * # @UnusedWildImport from pydevd_file_utils import GetFilenameAndBase + +from pydev_frame_utils import add_exception_to_frame try: from pydevd_signature import sendSignatureCallTrace except ImportError: @@ -564,6 +566,3 @@ class PyDBFrame: if flag: frame = suspend_django(self, mainDebugger, thread, frame) return flag, frame - -def add_exception_to_frame(frame, exception_info): - frame.f_locals['__exception__'] = exception_info \ No newline at end of file diff --git a/python/helpers/pydev/pydevd_frame_utils.py b/python/helpers/pydev/pydevd_frame_utils.py index be9ada35883a..0202d6246cc9 100644 --- a/python/helpers/pydev/pydevd_frame_utils.py +++ b/python/helpers/pydev/pydevd_frame_utils.py @@ -21,3 +21,6 @@ class FCode: def __init__(self, name, filename): self.co_name = name self.co_filename = filename + +def add_exception_to_frame(frame, exception_info): + frame.f_locals['__exception__'] = exception_info diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py index eb5d1876c595..64835d775908 100644 --- a/python/helpers/pydev/pydevd_plugins/django_debug.py +++ b/python/helpers/pydev/pydevd_plugins/django_debug.py @@ -6,7 +6,7 @@ from pydevd_breakpoints import LineBreakpoint, get_exception_name import pydevd_vars import traceback import pydev_log -from pydevd_frame import add_exception_to_frame +from pydevd_frame_utils import add_exception_to_frame, FCode class DjangoLineBreakpoint(LineBreakpoint): @@ -252,12 +252,6 @@ class DjangoTemplateFrame: d[k] = value -class FCode: - def __init__(self, name, filename): - self.co_name = name - self.co_filename = filename - - def is_django_exception_break_context(frame): try: name = frame.f_code.co_name diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py index 52f94384460c..7109fbb30e25 100644 --- a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py +++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py @@ -3,7 +3,7 @@ from pydevd_constants import JINJA2_SUSPEND, GetThreadId, STATE_SUSPEND, DictCon from pydevd_comm import CMD_SET_BREAK, CMD_STEP_OVER, CMD_ADD_EXCEPTION_BREAK import pydevd_vars from pydevd_file_utils import GetFileNameAndBaseFromFile -from pydevd_frame import add_exception_to_frame +from pydevd_frame_utils import add_exception_to_frame, FCode class Jinja2LineBreakpoint(LineBreakpoint): @@ -138,11 +138,6 @@ class Jinja2TemplateFrame: if k == name: self.back_context.vars[k] = value -class FCode: - def __init__(self, name, filename): - self.co_name = name - self.co_filename = filename - def is_missing(item): if item.__class__.__name__ is 'MissingType': return True From 5dabc5fa75e8197c94ef511f63bf3702791df481 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 5 Sep 2014 05:00:13 +0200 Subject: [PATCH 18/69] Remove unused code. --- python/helpers/pydev/django_debug.py | 124 ------------------------- python/helpers/pydev/django_frame.py | 132 --------------------------- python/helpers/pydev/pydevd.py | 4 +- python/helpers/pydev/pydevd_frame.py | 70 +------------- python/helpers/pydev/pydevd_vars.py | 9 +- 5 files changed, 9 insertions(+), 330 deletions(-) delete mode 100644 python/helpers/pydev/django_debug.py delete mode 100644 python/helpers/pydev/django_frame.py diff --git a/python/helpers/pydev/django_debug.py b/python/helpers/pydev/django_debug.py deleted file mode 100644 index 2b17864db47e..000000000000 --- a/python/helpers/pydev/django_debug.py +++ /dev/null @@ -1,124 +0,0 @@ -import inspect -from django_frame import DjangoTemplateFrame -from pydevd_comm import CMD_SET_BREAK -from pydevd_constants import DJANGO_SUSPEND, GetThreadId, DictContains -from pydevd_file_utils import NormFileToServer -from pydevd_breakpoints import LineBreakpoint -import pydevd_vars -import traceback - -class DjangoLineBreakpoint(LineBreakpoint): - - def __init__(self, file, line, condition, func_name, expression): - self.file = file - LineBreakpoint.__init__(self, line, condition, func_name, expression) - - def is_triggered(self, template_frame_file, template_frame_line): - return self.file == template_frame_file and self.line == template_frame_line - - def __str__(self): - return "DjangoLineBreakpoint: %s-%d" %(self.file, self.line) - - -def inherits(cls, *names): - if cls.__name__ in names: - return True - inherits_node = False - for base in inspect.getmro(cls): - if base.__name__ in names: - inherits_node = True - break - return inherits_node - - -def is_django_render_call(frame): - try: - name = frame.f_code.co_name - if name != 'render': - return False - - if not DictContains(frame.f_locals, 'self'): - return False - - cls = frame.f_locals['self'].__class__ - - inherits_node = inherits(cls, 'Node') - - if not inherits_node: - return False - - clsname = cls.__name__ - return clsname != 'TextNode' and clsname != 'NodeList' - except: - traceback.print_exc() - return False - - -def is_django_context_get_call(frame): - try: - if not DictContains(frame.f_locals, 'self'): - return False - - cls = frame.f_locals['self'].__class__ - - return inherits(cls, 'BaseContext') - except: - traceback.print_exc() - return False - - -def is_django_resolve_call(frame): - try: - name = frame.f_code.co_name - if name != '_resolve_lookup': - return False - - if not DictContains(frame.f_locals, 'self'): - return False - - cls = frame.f_locals['self'].__class__ - - clsname = cls.__name__ - return clsname == 'Variable' - except: - traceback.print_exc() - return False - - -def is_django_suspended(thread): - return thread.additionalInfo.suspend_type == DJANGO_SUSPEND - - -def suspend_django(py_db_frame, mainDebugger, thread, frame, cmd=CMD_SET_BREAK): - frame = DjangoTemplateFrame(frame) - - if frame.f_lineno is None: - return None - - #try: - # if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno: - # return None # don't stay twice on the same line - #except AttributeError: - # pass - - pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame}) - - py_db_frame.setSuspend(thread, cmd) - thread.additionalInfo.suspend_type = DJANGO_SUSPEND - - thread.additionalInfo.filename = frame.f_code.co_filename - thread.additionalInfo.line = frame.f_lineno - - return frame - - -def find_django_render_frame(frame): - while frame is not None and not is_django_render_call(frame): - frame = frame.f_back - - return frame - - - - - diff --git a/python/helpers/pydev/django_frame.py b/python/helpers/pydev/django_frame.py deleted file mode 100644 index 4181572aed3c..000000000000 --- a/python/helpers/pydev/django_frame.py +++ /dev/null @@ -1,132 +0,0 @@ -from pydevd_file_utils import GetFileNameAndBaseFromFile -import pydev_log -import traceback -from pydevd_constants import DictContains - -def read_file(filename): - f = open(filename, "r") - try: - s = f.read() - finally: - f.close() - return s - - -def offset_to_line_number(text, offset): - curLine = 1 - curOffset = 0 - while curOffset < offset: - if curOffset == len(text): - return -1 - c = text[curOffset] - if c == '\n': - curLine += 1 - elif c == '\r': - curLine += 1 - if curOffset < len(text) and text[curOffset + 1] == '\n': - curOffset += 1 - - curOffset += 1 - - return curLine - - -def get_source(frame): - try: - node = frame.f_locals['self'] - if hasattr(node, 'source'): - return node.source - else: - pydev_log.error_once( - "WARNING: Template path is not available. Please set TEMPLATE_DEBUG=True " - "in your settings.py to make django template breakpoints working") - return None - - except: - pydev_log.debug(traceback.format_exc()) - return None - - -def get_template_file_name(frame): - try: - source = get_source(frame) - if source is None: - pydev_log.debug("Source is None\n") - return None - fname = source[0].name - - if fname == '': - pydev_log.debug("Source name is %s\n" % fname) - return None - else: - filename, base = GetFileNameAndBaseFromFile(fname) - return filename - except: - pydev_log.debug(traceback.format_exc()) - return None - - -def get_template_line(frame, template_frame_file): - source = get_source(frame) - try: - return offset_to_line_number(read_file(template_frame_file), source[1][0]) - except: - return None - - -class DjangoTemplateFrame: - def __init__( - self, - frame, - template_frame_file=None, - template_frame_line=None): - - if template_frame_file is None: - template_frame_file = get_template_file_name(frame) - - self.back_context = frame.f_locals['context'] - self.f_code = FCode('Django Template', template_frame_file) - - if template_frame_line is None: - template_frame_line = get_template_line(frame, template_frame_file) - self.f_lineno = template_frame_line - - self.f_back = frame - self.f_globals = {} - self.f_locals = self.collect_context() - self.f_trace = None - - def collect_context(self): - res = {} - try: - for d in self.back_context.dicts: - res.update(d) - except AttributeError: - pass - return res - - def changeVariable(self, name, value): - for d in self.back_context.dicts: - if DictContains(d, name): - d[name] = value - self.f_locals[name] = value - - -class FCode: - def __init__(self, name, filename): - self.co_name = name - self.co_filename = filename - - -def is_django_exception_break_context(frame): - try: - return frame.f_code.co_name in ['_resolve_lookup', 'find_template'] - except: - return False - - -def just_raised(trace): - if trace is None: - return False - return trace.tb_next is None - diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index c0a3d3723ba9..d4b2ef937ebc 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -119,7 +119,7 @@ DONT_TRACE = { '_pydev_threading':1, '_pydev_Queue':1, 'django_debug.py':1, - 'django_frame.py':1, + 'jinja2_debug.py':1, 'pydev_log.py':1, 'pydev_monkey.py':1 , 'pydevd.py':1 , @@ -304,7 +304,6 @@ class PyDB: self._cmd_queue = {} # the hash of Queues. Key is thread id, value is thread self.breakpoints = {} - #self.django_breakpoints = {} self.file_to_id_to_line_breakpoint = {} self.file_to_id_to_plugin_breakpoint = {} @@ -314,7 +313,6 @@ class PyDB: self.break_on_uncaught_exceptions = {} self.break_on_caught_exceptions = {} - self.django_exception_break = {} self.readyToRun = False self._main_lock = _pydev_thread.allocate_lock() self._lock_running_thread_ids = _pydev_thread.allocate_lock() diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index 704d77b3ca38..93b5cb2e1620 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -3,20 +3,14 @@ import os.path import re import traceback # @Reimport -from django_debug import find_django_render_frame -from django_debug import is_django_render_call, is_django_suspended, suspend_django, is_django_resolve_call, is_django_context_get_call -from django_frame import DjangoTemplateFrame -from django_frame import is_django_exception_break_context -from django_frame import just_raised, get_template_file_name, get_template_line import pydev_log from pydevd_breakpoints import get_exception_breakpoint, get_exception_name -from pydevd_comm import CMD_ADD_DJANGO_EXCEPTION_BREAK, \ - CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVER, CMD_SET_BREAK, \ +from pydevd_comm import CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVER, CMD_SET_BREAK, \ CMD_STEP_INTO, CMD_SMART_STEP_INTO, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT from pydevd_constants import * # @UnusedWildImport from pydevd_file_utils import GetFilenameAndBase -from pydev_frame_utils import add_exception_to_frame +from pydevd_frame_utils import add_exception_to_frame try: from pydevd_signature import sendSignatureCallTrace except ImportError: @@ -57,7 +51,7 @@ class PyDBFrame: def doWaitSuspend(self, *args, **kwargs): self._args[0].doWaitSuspend(*args, **kwargs) - def _is_django_render_call(self, frame): + def _is_django_render_call(self, frame): # todo: cache in plugins the same way try: return self._cached_is_django_render_call except: @@ -387,8 +381,6 @@ class PyDBFrame: #step handling. We stop when we hit the right frame try: - stop_info['django_stop'] = False - should_skip = False if pydevd_dont_trace.should_trace_hook is not None: if not hasattr(self, 'should_skip'): @@ -511,58 +503,4 @@ class PyDBFrame: except ImportError: if hasattr(sys, 'exc_clear'): #jython does not have it sys.exc_clear() #don't keep the traceback - pass #ok, psyco not available - - def should_stop_on_django_breakpoint(self, frame, event, arg): - mainDebugger = self._args[0] - thread = self._args[3] - flag = False - template_frame_file = get_template_file_name(frame) - - #pydev_log.debug("Django is rendering a template: %s\n" % template_frame_file) - - django_breakpoints_for_file = mainDebugger.django_breakpoints.get(template_frame_file) - if django_breakpoints_for_file: - - #pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file) - - template_frame_line = get_template_line(frame, template_frame_file) - - #pydev_log.debug("Tracing template line: %d\n" % template_frame_line) - - if DictContains(django_breakpoints_for_file, template_frame_line): - django_breakpoint = django_breakpoints_for_file[template_frame_line] - - if django_breakpoint.is_triggered(template_frame_file, template_frame_line): - - #pydev_log.debug("Breakpoint is triggered.\n") - - flag = True - new_frame = DjangoTemplateFrame( - frame, - template_frame_file=template_frame_file, - template_frame_line=template_frame_line, - ) - - if django_breakpoint.condition is not None: - try: - val = eval(django_breakpoint.condition, new_frame.f_globals, new_frame.f_locals) - if not val: - flag = False - pydev_log.debug("Condition '%s' is evaluated to %s. Not suspending.\n" % (django_breakpoint.condition, val)) - except: - pydev_log.info( - 'Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1])) - - if django_breakpoint.expression is not None: - try: - try: - val = eval(django_breakpoint.expression, new_frame.f_globals, new_frame.f_locals) - except: - val = sys.exc_info()[1] - finally: - if val is not None: - thread.additionalInfo.message = val - if flag: - frame = suspend_django(self, mainDebugger, thread, frame) - return flag, frame + pass #ok, psyco not available \ No newline at end of file diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index 3baea5b61b99..655449f36be7 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -2,7 +2,6 @@ resolution/conversion to XML. """ import pickle -from django_frame import DjangoTemplateFrame from pydevd_constants import * #@UnusedWildImport from types import * #@UnusedWildImport @@ -360,10 +359,10 @@ def changeAttrExpression(thread_id, frame_id, attr, expression): try: expression = expression.replace('@LINE@', '\n') - if isinstance(frame, DjangoTemplateFrame): - result = eval(expression, frame.f_globals, frame.f_locals) - frame.changeVariable(attr, result) - return + # if isinstance(frame, DjangoTemplateFrame): # TODO: implemente for plugins + # result = eval(expression, frame.f_globals, frame.f_locals) + # frame.changeVariable(attr, result) + # return if attr[:7] == "Globals": attr = attr[8:] From af021a7a18f17270c811966cf5807b4b052bec20 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 5 Sep 2014 08:19:29 +0400 Subject: [PATCH 19/69] add sync update method --- .../documentation/QuickDocUtil.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java index 064bd020183b..4fad06ede87e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java @@ -26,9 +26,9 @@ import com.intellij.psi.PsiElement; import com.intellij.ui.content.Content; import com.intellij.ui.popup.AbstractPopup; import com.intellij.util.Producer; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; - -import javax.swing.*; +import org.jetbrains.annotations.Nullable; /** * @author gregsh @@ -40,32 +40,34 @@ public class QuickDocUtil { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - final String documentation = docProducer.produce(); - if (StringUtil.isEmpty(documentation)) return; - // modal dialogs with fragment editors fix: can't guess proper modality state here - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - DocumentationManager documentationManager = DocumentationManager.getInstance(project); - DocumentationComponent component; - JBPopup hint = documentationManager.getDocInfoHint(); - if (hint != null) { - component = (DocumentationComponent)((AbstractPopup)hint).getComponent(); - } - else if (documentationManager.hasActiveDockedDocWindow()) { - ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION); - Content selectedContent = toolWindow == null ? null : toolWindow.getContentManager().getSelectedContent(); - component = selectedContent == null ? null : (DocumentationComponent)selectedContent.getComponent(); - } - else { - component = null; - } - if (component != null) { - component.replaceText(documentation, element); - } - } - }); + updateQuickDoc(project, element, docProducer.produce()); + } + }); + } + + public static void updateQuickDoc(@NotNull final Project project, @NotNull final PsiElement element, @Nullable final String documentation) { + if (StringUtil.isEmpty(documentation)) return; + // modal dialogs with fragment editors fix: can't guess proper modality state here + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + DocumentationManager documentationManager = DocumentationManager.getInstance(project); + DocumentationComponent component; + JBPopup hint = documentationManager.getDocInfoHint(); + if (hint != null) { + component = (DocumentationComponent)((AbstractPopup)hint).getComponent(); + } + else if (documentationManager.hasActiveDockedDocWindow()) { + ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION); + Content selectedContent = toolWindow == null ? null : toolWindow.getContentManager().getSelectedContent(); + component = selectedContent == null ? null : (DocumentationComponent)selectedContent.getComponent(); + } + else { + component = null; + } + if (component != null) { + component.replaceText(documentation, element); + } } }); } From b10e0c507290d875375687240ddeb00db5ebceab Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 09:30:28 +0400 Subject: [PATCH 20/69] IDEA-81929: Support java -jar run configurations --- .../application/ApplicationConfiguration.java | 46 +--- .../BaseJavaApplicationCommandLineState.java | 70 ++++++ .../jar/JarApplicationCommandLineState.java | 43 ++++ .../jar/JarApplicationConfigurable.form | 39 ++++ .../jar/JarApplicationConfigurable.java | 86 ++++++++ .../jar/JarApplicationConfiguration.java | 201 ++++++++++++++++++ .../jar/JarApplicationConfigurationType.java | 48 +++++ .../jar/JarApplicationDebuggerRunner.java | 37 ++++ .../runners/ProcessProxyFactoryImpl.java | 7 +- .../execution/util/JavaParametersUtil.java | 3 +- .../configurations/CommandLineBuilder.java | 2 +- .../configurations/SimpleJavaParameters.java | 10 +- .../openapi/projectRoots/JdkUtil.java | 12 +- .../src/messages/ExecutionBundle.properties | 5 +- resources/src/META-INF/IdeaPlugin.xml | 2 + 15 files changed, 562 insertions(+), 49 deletions(-) create mode 100644 java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index 578d5fbba6ea..b736d9f0b127 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -21,20 +21,16 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent; import com.intellij.execution.configurations.*; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.junit.RefactoringListeners; -import com.intellij.execution.process.KillableColoredProcessHandler; -import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.util.JavaParametersUtil; import com.intellij.execution.util.ProgramParametersUtil; import com.intellij.openapi.components.PathMacroManager; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -81,7 +77,7 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration(this, env); JavaRunConfigurationModule module = getConfigurationModule(); state.setConsoleBuilder(TextConsoleBuilderFactory.getInstance().createBuilder(getProject(), module.getSearchScope())); return state; @@ -253,14 +249,9 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration extends BaseJavaApplicationCommandLineState { + public JavaApplicationCommandLineState(@NotNull final T configuration, final ExecutionEnvironment environment) { + super(environment, configuration); } @Override @@ -269,37 +260,14 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration extends JavaCommandLineState { + protected final T myConfiguration; + + public BaseJavaApplicationCommandLineState(ExecutionEnvironment environment, @NotNull final T configuration) { + super(environment); + myConfiguration = configuration; + } + + protected void setupJavaParameters(JavaParameters params) throws ExecutionException { + JavaParametersUtil.configureConfiguration(params, myConfiguration); + + for(RunConfigurationExtension ext: Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) { + ext.updateJavaParameters(getConfiguration(), params, getRunnerSettings()); + } + } + + @NotNull + @Override + protected OSProcessHandler startProcess() throws ExecutionException { + OSProcessHandler handler = SystemInfo.isWindows ? super.startProcess() : KillableColoredProcessHandler.create(createCommandLine()); + RunnerSettings runnerSettings = getRunnerSettings(); + JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(getConfiguration(), handler, runnerSettings); + return handler; + } + + @Override + protected boolean ansiColoringEnabled() { + return true; + } + + protected T getConfiguration() { + return myConfiguration; + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java new file mode 100644 index 000000000000..c93ab85d4cec --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.execution.ExecutionException; +import com.intellij.execution.application.BaseJavaApplicationCommandLineState; +import com.intellij.execution.configurations.JavaParameters; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class JarApplicationCommandLineState extends BaseJavaApplicationCommandLineState { + public JarApplicationCommandLineState(@NotNull final JarApplicationConfiguration configuration, final ExecutionEnvironment environment) { + super(environment, configuration); + } + + @Override + protected JavaParameters createJavaParameters() throws ExecutionException { + final JavaParameters params = new JavaParameters(); + final String jreHome = myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null; + params.setJdk(JavaParametersUtil.createProjectJdk(myConfiguration.getProject(), jreHome)); + setupJavaParameters(params); + params.setJarPath(FileUtil.toSystemDependentName(myConfiguration.getJarPath())); + return params; + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form new file mode 100644 index 000000000000..b6012a096c95 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form @@ -0,0 +1,39 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java new file mode 100644 index 000000000000..071f348a79a4 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.execution.ui.AlternativeJREPanel; +import com.intellij.execution.ui.CommonJavaParametersPanel; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.LabeledComponent; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.PanelWithAnchor; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class JarApplicationConfigurable extends SettingsEditor implements PanelWithAnchor { + private CommonJavaParametersPanel myCommonProgramParameters; + private LabeledComponent myJarPathComponent; + private JPanel myWholePanel; + + private AlternativeJREPanel myAlternativeJREPanel; + private final Project myProject; + private JComponent myAnchor; + + public JarApplicationConfigurable(final Project project) { + myProject = project; + myAnchor = UIUtil.mergeComponentsWithAnchor(myJarPathComponent, myCommonProgramParameters, myAlternativeJREPanel); + } + + public void applyEditorTo(final JarApplicationConfiguration configuration) throws ConfigurationException { + myCommonProgramParameters.applyTo(configuration); + configuration.setAlternativeJrePath(myAlternativeJREPanel.getPath()); + configuration.setAlternativeJrePathEnabled(myAlternativeJREPanel.isPathEnabled()); + configuration.setJarPath(FileUtil.toSystemIndependentName(myJarPathComponent.getComponent().getText())); + } + + public void resetEditorFrom(final JarApplicationConfiguration configuration) { + myCommonProgramParameters.reset(configuration); + myJarPathComponent.getComponent().setText(FileUtil.toSystemDependentName(configuration.getJarPath())); + myAlternativeJREPanel.init(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled()); + } + + @NotNull + public JComponent createEditor() { + return myWholePanel; + } + + private void createUIComponents() { + myJarPathComponent = new LabeledComponent(); + TextFieldWithBrowseButton textFieldWithBrowseButton = new TextFieldWithBrowseButton(); + textFieldWithBrowseButton.addBrowseFolderListener("Choose Jar File", null, myProject, + new FileChooserDescriptor(false, false, true, true, false, false)); + myJarPathComponent.setComponent(textFieldWithBrowseButton); + } + + @Override + public JComponent getAnchor() { + return myAnchor; + } + + @Override + public void setAnchor(@Nullable JComponent anchor) { + myAnchor = anchor; + myCommonProgramParameters.setAnchor(anchor); + myAlternativeJREPanel.setAnchor(anchor); + myJarPathComponent.setAnchor(anchor); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java new file mode 100644 index 000000000000..5aaa0a3b0bd6 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java @@ -0,0 +1,201 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.diagnostic.logging.LogConfigurationPanel; +import com.intellij.execution.*; +import com.intellij.execution.configuration.EnvironmentVariablesComponent; +import com.intellij.execution.configurations.*; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; +import com.intellij.openapi.components.PathMacroManager; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.options.SettingsEditorGroup; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; +import com.intellij.util.xmlb.XmlSerializer; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author nik + */ +public class JarApplicationConfiguration extends RunConfigurationBase implements CommonJavaRunConfigurationParameters { + private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters(); + private JarApplicationConfigurationBean myBean = new JarApplicationConfigurationBean(); + private Map myEnvs = new LinkedHashMap(); + + public JarApplicationConfiguration(Project project, ConfigurationFactory factory, String name) { + super(project, factory, name); + } + + @NotNull + @Override + public SettingsEditor getConfigurationEditor() { + SettingsEditorGroup group = new SettingsEditorGroup(); + group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new JarApplicationConfigurable(getProject())); + JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group); + group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel()); + return group; + } + + @Override + public void readExternal(Element element) throws InvalidDataException { + PathMacroManager.getInstance(getProject()).expandPaths(element); + super.readExternal(element); + JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element); + XmlSerializer.deserializeInto(myBean, element); + EnvironmentVariablesComponent.readExternal(element, getEnvs()); + } + + @Override + public void writeExternal(Element element) throws WriteExternalException { + super.writeExternal(element); + JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element); + XmlSerializer.serializeInto(myBean, element, SERIALIZATION_FILTERS); + EnvironmentVariablesComponent.writeExternal(element, getEnvs()); + PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element); + } + + @Override + public void checkConfiguration() throws RuntimeConfigurationException { + JavaParametersUtil.checkAlternativeJRE(this); + ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), null); + File jarFile = new File(getJarPath()); + if (!jarFile.exists()) { + throw new RuntimeConfigurationWarning("Jar file '" + jarFile.getAbsolutePath() + "' doesn't exist"); + } + JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this); + } + + @Nullable + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException { + return new JarApplicationCommandLineState(this, environment); + } + + public String getJarPath() { + return myBean.JAR_PATH; + } + + public void setJarPath(String jarPath) { + myBean.JAR_PATH = jarPath; + } + + @Override + public void setVMParameters(String value) { + myBean.VM_PARAMETERS = value; + } + + @Override + public String getVMParameters() { + return myBean.VM_PARAMETERS; + } + + @Override + public boolean isAlternativeJrePathEnabled() { + return myBean.ALTERNATIVE_JRE_PATH_ENABLED; + } + + @Override + public void setAlternativeJrePathEnabled(boolean enabled) { + myBean.ALTERNATIVE_JRE_PATH_ENABLED = enabled; + } + + @Override + public String getAlternativeJrePath() { + return myBean.ALTERNATIVE_JRE_PATH; + } + + @Override + public void setAlternativeJrePath(String path) { + myBean.ALTERNATIVE_JRE_PATH = path; + } + + @Nullable + @Override + public String getRunClass() { + return null; + } + + @Nullable + @Override + public String getPackage() { + return null; + } + + @Override + public void setProgramParameters(@Nullable String value) { + myBean.PROGRAM_PARAMETERS = value; + } + + @Nullable + @Override + public String getProgramParameters() { + return myBean.PROGRAM_PARAMETERS; + } + + @Override + public void setWorkingDirectory(@Nullable String value) { + myBean.WORKING_DIRECTORY = value; + } + + @Nullable + @Override + public String getWorkingDirectory() { + return myBean.WORKING_DIRECTORY; + } + + @Override + public void setEnvs(@NotNull Map envs) { + myEnvs.clear(); + myEnvs.putAll(envs); + } + + @NotNull + @Override + public Map getEnvs() { + return myEnvs; + } + + @Override + public void setPassParentEnvs(boolean passParentEnvs) { + myBean.PASS_PARENT_ENVS = passParentEnvs; + } + + @Override + public boolean isPassParentEnvs() { + return myBean.PASS_PARENT_ENVS; + } + + private static class JarApplicationConfigurationBean { + public String JAR_PATH = ""; + public String VM_PARAMETERS = ""; + public String PROGRAM_PARAMETERS = ""; + public String WORKING_DIRECTORY = ""; + public boolean ALTERNATIVE_JRE_PATH_ENABLED; + public String ALTERNATIVE_JRE_PATH = ""; + public boolean PASS_PARENT_ENVS = true; + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java new file mode 100644 index 000000000000..05fb3aaa0972 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.execution.ExecutionBundle; +import com.intellij.execution.configuration.ConfigurationFactoryEx; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.ConfigurationTypeBase; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; + +public class JarApplicationConfigurationType extends ConfigurationTypeBase implements ConfigurationType { + public JarApplicationConfigurationType() { + super("JarApplication", ExecutionBundle.message("jar.application.configuration.name"), + ExecutionBundle.message("jar.application.configuration.description"), AllIcons.FileTypes.Archive); + addFactory(new ConfigurationFactoryEx(this) { + @Override + public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) { + JarApplicationConfiguration jarApplicationConfiguration = (JarApplicationConfiguration)configuration; + if (StringUtil.isEmpty(jarApplicationConfiguration.getWorkingDirectory())) { + String baseDir = FileUtil.toSystemIndependentName(StringUtil.notNullize(configuration.getProject().getBasePath())); + jarApplicationConfiguration.setWorkingDirectory(baseDir); + } + } + + public RunConfiguration createTemplateConfiguration(Project project) { + return new JarApplicationConfiguration(project, this, ""); + } + }); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java new file mode 100644 index 000000000000..dc5bfbfb6129 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.debugger.impl.GenericDebuggerRunner; +import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.executors.DefaultDebugExecutor; +import org.jetbrains.annotations.NotNull; + +/** + * @author nik + */ +public class JarApplicationDebuggerRunner extends GenericDebuggerRunner { + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { + return DefaultDebugExecutor.EXECUTOR_ID.equals(executorId) && profile instanceof JarApplicationConfiguration; + } + + @NotNull + @Override + public String getRunnerId() { + return "JarDebug"; + } +} diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java index 6af48770e78d..4b20e2189202 100644 --- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java +++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java @@ -30,15 +30,16 @@ import java.io.File; public class ProcessProxyFactoryImpl extends ProcessProxyFactory { public ProcessProxy createCommandLineProxy(final JavaCommandLine javaCmdLine) throws ExecutionException { ProcessProxyImpl proxy = null; - if (ProcessProxyImpl.useLauncher()) { + final JavaParameters javaParameters = javaCmdLine.getJavaParameters(); + String mainClass = javaParameters.getMainClass(); + if (ProcessProxyImpl.useLauncher() && mainClass != null) { try { proxy = new ProcessProxyImpl(); - final JavaParameters javaParameters = javaCmdLine.getJavaParameters(); JavaSdkUtil.addRtJar(javaParameters.getClassPath()); final ParametersList vmParametersList = javaParameters.getVMParametersList(); vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_PORT_NUMBER, String.valueOf(proxy.getPortNumber())); vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_BINPATH, PathManager.getBinPath()); - javaParameters.getProgramParametersList().prepend(javaParameters.getMainClass()); + javaParameters.getProgramParametersList().prepend(mainClass); javaParameters.setMainClass(ProcessProxyImpl.LAUNCH_MAIN_CLASS); } catch (ProcessProxyImpl.NoMoreSocketsException e) { diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java index 18aead7fe7f1..4d948dae8a2d 100644 --- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java +++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java @@ -27,7 +27,6 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdk; -import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.ex.PathUtilEx; @@ -118,7 +117,7 @@ public class JavaParametersUtil { return jreHome == null ? JavaParameters.getModuleJdk(module) : createAlternativeJdk(jreHome); } - private static Sdk createProjectJdk(final Project project, final String jreHome) throws CantRunException { + public static Sdk createProjectJdk(final Project project, final String jreHome) throws CantRunException { return jreHome == null ? createProjectJdk(project) : createAlternativeJdk(jreHome); } diff --git a/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java b/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java index ac081d04b5c7..8ae0d9bae3e3 100644 --- a/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java +++ b/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java @@ -79,7 +79,7 @@ public class CommandLineBuilder { if (exePath == null) { throw new CantRunException(ExecutionBundle.message("run.configuration.cannot.find.vm.executable")); } - if (javaParameters.getMainClass() == null) { + if (javaParameters.getMainClass() == null && javaParameters.getJarPath() == null) { throw new CantRunException(ExecutionBundle.message("main.class.is.not.specified.error.message")); } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java index 7b3c45d5c7de..59fe6c2f1be2 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java @@ -40,11 +40,16 @@ public class SimpleJavaParameters extends SimpleProgramParameters { private Charset myCharset = CharsetToolkit.getDefaultSystemCharset(); private boolean myUseDynamicClasspath; private boolean myUseDynamicVMOptions; - + private String myJarPath; + public String getMainClass() { return myMainClass; } + public String getJarPath() { + return myJarPath; + } + /** * @return jdk used to launch the application. * If the instance of the JavaParameters is used to configure app server startup script, @@ -62,6 +67,9 @@ public class SimpleJavaParameters extends SimpleProgramParameters { public void setMainClass(@NonNls final String mainClass) { myMainClass = mainClass; } + public void setJarPath(@NonNls final String jarPath) { + myJarPath = jarPath; + } public PathsList getClassPath() { return myClassPath; diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java index 4291e9b401bf..337909b318e5 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java @@ -247,7 +247,15 @@ public class JdkUtil { } final String mainClass = javaParameters.getMainClass(); - commandLine.addParameter(mainClass); + String jarPath = javaParameters.getJarPath(); + if (mainClass != null) { + commandLine.addParameter(mainClass); + } + else if (jarPath != null) { + commandLine.addParameter("-jar"); + commandLine.addParameter(jarPath); + } + commandLine.addParameters(javaParameters.getProgramParametersList().getList()); commandLine.setWorkDirectory(javaParameters.getWorkingDirectory()); @@ -260,7 +268,7 @@ public class JdkUtil { ParametersList parametersList) { commandLine.addParameters(parametersList.getList()); appendEncoding(javaParameters, commandLine, parametersList); - if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){ + if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp") && !javaParameters.getClassPath().getPathList().isEmpty()){ commandLine.addParameter("-classpath"); commandLine.addParameter(javaParameters.getClassPath().getPathsString()); } diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index 183dda3d52b8..a49bcced6f50 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -40,9 +40,12 @@ jre.not.valid.error.message=''{0}'' is not valid JRE home applet.configuration.description=Applet configuration applet.configuration.name=Applet -application.configuration.description=Application configuration +application.configuration.description=Java application configuration application.configuration.name=Application +jar.application.configuration.description=Configuration to run a JAR file using 'java -jar' command +jar.application.configuration.name=JAR Application + run.configuration.norunner.selected.label=No runner selected run.configuration.configuration.tab.title=Configuration run.configuration.startup.connection.rab.title=Startup/Connection diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index ec30ca2614dc..6e3ca97edb51 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1224,6 +1224,7 @@ + @@ -1452,6 +1453,7 @@ + From cc53bf00223b8aee37c1769642b82436333a9fcc Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 09:41:22 +0400 Subject: [PATCH 21/69] unused method removed --- .../debugger/impl/DebuggerSession.java | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index 2c515f2302a9..4ffe870eca0a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -15,7 +15,10 @@ */ package com.intellij.debugger.impl; -import com.intellij.debugger.*; +import com.intellij.debugger.DebugEnvironment; +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.DebuggerInvocationUtil; +import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationListener; @@ -29,14 +32,10 @@ import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter; import com.intellij.debugger.ui.breakpoints.LineBreakpoint; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionResult; -import com.intellij.execution.Executor; -import com.intellij.execution.configurations.ModuleRunProfile; import com.intellij.execution.configurations.RemoteConnection; import com.intellij.execution.configurations.RemoteState; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.process.ProcessOutputTypes; -import com.intellij.execution.runners.ExecutionEnvironmentBuilder; -import com.intellij.execution.runners.ProgramRunner; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -380,19 +379,6 @@ public class DebuggerSession implements AbstractDebuggerSession { return getContextManager().getContext().getSuspendContext(); } - @Nullable - protected ExecutionResult attach(@NotNull Executor executor, - @NotNull ProgramRunner runner, - @NotNull ModuleRunProfile profile, - @NotNull RunProfileState state, - RemoteConnection remoteConnection, - boolean pollConnection) throws ExecutionException { - return attach(new DefaultDebugEnvironment(new ExecutionEnvironmentBuilder(myDebugProcess.getProject(), executor).runProfile(profile).runner(runner).build(), - state, - remoteConnection, - pollConnection)); - } - @Nullable protected ExecutionResult attach(DebugEnvironment environment) throws ExecutionException { RemoteConnection remoteConnection = environment.getRemoteConnection(); From e1719a15f6c2d13b69045b7be54dc594fdbea153 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 09:40:05 +0200 Subject: [PATCH 22/69] =?UTF-8?q?move=20check=20before=20expand=20?= =?UTF-8?q?=E2=80=94=20expanded=20file=20path=20could=20contain=20"$...$"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/stores/StateStorageManagerImpl.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java index 69a8a38a7901..f8b05cc73b70 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java @@ -335,22 +335,18 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di @Override @NotNull public synchronized String expandMacros(@NotNull String file) { + Matcher matcher = MACRO_PATTERN.matcher(file); + while (matcher.find()) { + String m = matcher.group(1); + if (!myMacros.containsKey(m)) { + throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); + } + } + String expanded = file; for (String macro : myMacros.keySet()) { expanded = StringUtil.replace(expanded, macro, myMacros.get(macro)); } - - // PHP tests use $ as part of name and resulting project name will contain macros-like string - if (!ApplicationManager.getApplication().isUnitTestMode()) { - final Matcher matcher = MACRO_PATTERN.matcher(expanded); - while (matcher.find()) { - String m = matcher.group(1); - if (m != null && !myMacros.containsKey(m)) { - throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file); - } - } - } - return expanded; } From 45595ef17b85d7e151cab34b7fc4b1e11819e3c3 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 12:02:08 +0400 Subject: [PATCH 23/69] added option to specify context module for JAR application configuration (IDEA-81929) --- .../jar/JarApplicationConfigurable.form | 14 ++++++-- .../jar/JarApplicationConfigurable.java | 7 ++++ .../jar/JarApplicationConfiguration.java | 24 ++++++++++++- .../configurations/ModuleRunProfile.java | 2 +- .../configurations/SearchScopeProvider.java | 4 +-- .../SearchScopeProvidingRunProfile.java | 34 +++++++++++++++++++ .../options/ModuleListCellRenderer.java | 13 ++++++- .../application/options/ModulesComboBox.java | 10 ++++++ .../configuration/ModulesAlphaComparator.java | 7 ++-- 9 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form index b6012a096c95..db191dde6fa3 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form @@ -1,6 +1,6 @@
- + @@ -16,7 +16,7 @@ - + @@ -34,6 +34,16 @@ + + + + + + + + + + diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java index 071f348a79a4..debdb7b9fdc6 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.jar; +import com.intellij.application.options.ModulesComboBox; import com.intellij.execution.ui.AlternativeJREPanel; import com.intellij.execution.ui.CommonJavaParametersPanel; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -34,6 +35,7 @@ import javax.swing.*; public class JarApplicationConfigurable extends SettingsEditor implements PanelWithAnchor { private CommonJavaParametersPanel myCommonProgramParameters; private LabeledComponent myJarPathComponent; + private LabeledComponent myModuleComponent; private JPanel myWholePanel; private AlternativeJREPanel myAlternativeJREPanel; @@ -43,6 +45,9 @@ public class JarApplicationConfigurable extends SettingsEditor"); + modulesComboBox.fillModules(project); } public void applyEditorTo(final JarApplicationConfiguration configuration) throws ConfigurationException { @@ -50,12 +55,14 @@ public class JarApplicationConfigurable extends SettingsEditor myEnvs = new LinkedHashMap(); + private JavaRunConfigurationModule myConfigurationModule; public JarApplicationConfiguration(Project project, ConfigurationFactory factory, String name) { super(project, factory, name); + myConfigurationModule = new JavaRunConfigurationModule(project, true); } @NotNull @@ -67,6 +70,15 @@ public class JarApplicationConfiguration extends RunConfigurationBase implements JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element); XmlSerializer.deserializeInto(myBean, element); EnvironmentVariablesComponent.readExternal(element, getEnvs()); + myConfigurationModule.readExternal(element); + } + + public void setModule(Module module) { + myConfigurationModule.setModule(module); + } + + public Module getModule() { + return myConfigurationModule.getModule(); } @Override @@ -76,6 +88,9 @@ public class JarApplicationConfiguration extends RunConfigurationBase implements XmlSerializer.serializeInto(myBean, element, SERIALIZATION_FILTERS); EnvironmentVariablesComponent.writeExternal(element, getEnvs()); PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element); + if (myConfigurationModule.getModule() != null) { + myConfigurationModule.writeExternal(element); + } } @Override @@ -89,6 +104,13 @@ public class JarApplicationConfiguration extends RunConfigurationBase implements JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this); } + @NotNull + @Override + public Module[] getModules() { + Module module = myConfigurationModule.getModule(); + return module != null ? new Module[] {module}: Module.EMPTY_ARRAY; + } + @Nullable @Override public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException { diff --git a/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java index 9a1dfad2955a..45519c91baeb 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java @@ -19,5 +19,5 @@ package com.intellij.execution.configurations; /** * @author spleaner */ -public interface ModuleRunProfile extends RunProfileWithCompileBeforeLaunchOption { +public interface ModuleRunProfile extends RunProfileWithCompileBeforeLaunchOption, SearchScopeProvidingRunProfile { } diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java index ea6b158e0bc2..e3f0c22a2132 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java @@ -28,8 +28,8 @@ public class SearchScopeProvider { @NotNull public static GlobalSearchScope createSearchScope(@NotNull Project project, @Nullable RunProfile runProfile) { Module[] modules = null; - if (runProfile instanceof ModuleRunProfile) { - modules = ((ModuleRunProfile)runProfile).getModules(); + if (runProfile instanceof SearchScopeProvidingRunProfile) { + modules = ((SearchScopeProvidingRunProfile)runProfile).getModules(); } if (modules == null || modules.length == 0) { return GlobalSearchScope.allScope(project); diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java new file mode 100644 index 000000000000..afdd273384e8 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 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.intellij.execution.configurations; + +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; + +/** + * Base interface for run configurations that can specify which part of the project should be used to search sources. This information + * will be used to provide more accurate navigation to sources from stack traces, debugger, etc + * + * @author nik + */ +public interface SearchScopeProvidingRunProfile extends RunProfile { + /** + * @return modules where to search sources for this configuration + */ + @NotNull + Module[] getModules(); +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java b/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java index f544517bb5d4..6bc5f6505c92 100644 --- a/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java @@ -3,6 +3,7 @@ package com.intellij.application.options; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.ui.ListCellRendererWrapper; +import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -10,10 +11,20 @@ import javax.swing.*; * @author yole */ public class ModuleListCellRenderer extends ListCellRendererWrapper { + private final String myEmptySelectionText; + + public ModuleListCellRenderer() { + this("[none]"); + } + + public ModuleListCellRenderer(@NotNull String emptySelectionText) { + myEmptySelectionText = emptySelectionText; + } + @Override public void customize(JList list, Module module, int index, boolean selected, boolean hasFocus) { if (module == null) { - setText("[none]"); + setText(myEmptySelectionText); } else { setIcon(ModuleType.get(module).getIcon()); diff --git a/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java b/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java index 17434cb0c7ba..4c2ef3a3d16c 100644 --- a/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java +++ b/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java @@ -36,6 +36,7 @@ import java.util.List; */ public class ModulesComboBox extends ComboBox { private final SortedComboBoxModel myModel; + private boolean myAllowEmptySelection; public ModulesComboBox() { this(new SortedComboBoxModel(ModulesAlphaComparator.INSTANCE)); @@ -58,8 +59,17 @@ public class ModulesComboBox extends ComboBox { setRenderer(new ModuleListCellRenderer()); } + public void allowEmptySelection(@NotNull String emptySelectionText) { + myAllowEmptySelection = true; + myModel.add(null); + setRenderer(new ModuleListCellRenderer(emptySelectionText)); + } + public void setModules(@NotNull Collection modules) { myModel.setAll(modules); + if (myAllowEmptySelection) { + myModel.add(null); + } } public void fillModules(@NotNull Project project) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java index 8a561e4003b4..61a5c71861c3 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java @@ -29,8 +29,9 @@ public class ModulesAlphaComparator implements Comparator{ @Override public int compare(Module module1, Module module2) { - final String name1 = module1.getName(); - final String name2 = module2.getName(); - return name1.compareToIgnoreCase(name2); + if (module1 == null && module2 == null) return 0; + if (module1 == null && module2 != null) return -1; + if (module1 != null && module2 == null) return 1; + return module1.getName().compareToIgnoreCase(module2.getName()); } } From 7a403dd8a5c72a4fd1b685aa9f9bb796fb1d5af8 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:05:24 +0200 Subject: [PATCH 24/69] replace return replacement if text equals to replaced text (avoid String creation) --- .../openapi/util/text/StringUtil.java | 25 +++++++++++++------ .../intellij/util/text/StringUtilTest.java | 15 ++++++++--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index c26cb10030c4..c2b7de8ba7ed 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -153,17 +153,26 @@ public class StringUtil extends StringUtilRt { int i = 0; while (i < text.length()) { - final int i1 = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i); - if (i1 < 0) { - if (i == 0) return text; + final int index = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i); + if (index < 0) { + if (i == 0) { + return text; + } + newText.append(text, i, text.length()); break; } else { - if (newText == null) newText = new StringBuilder(text.length() - i); - newText.append(text, i, i1); + if (newText == null) { + if (text.length() == oldS.length()) { + return newS; + } + newText = new StringBuilder(text.length() - i); + } + + newText.append(text, i, index); newText.append(newS); - i = i1 + oldS.length(); + i = index + oldS.length(); } } return newText != null ? newText.toString() : ""; @@ -1786,7 +1795,7 @@ public class StringUtil extends StringUtilRt { public static boolean contains(@NotNull CharSequence sequence, @NotNull CharSequence infix) { return indexOf(sequence, infix) >= 0; } - + @Contract(pure = true) public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) { for (int i = 0; i < sequence.length() - infix.length(); i++) { @@ -2448,7 +2457,7 @@ public class StringUtil extends StringUtilRt { * \r
* * will return the following array: foo\r\n, \n, bar\n, \r\n, baz\r, \r - * + * */ @NotNull @Contract(pure = true) diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index d2f593d13ff1..93ebb038cae1 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -111,7 +111,7 @@ public class StringUtilTest extends TestCase { public void testFormatLinks() { assertEquals("http://a-b+c", StringUtil.formatLinks("http://a-b+c")); } - + public void testCopyHeapCharBuffer() { String s = "abcde"; CharBuffer buffer = CharBuffer.allocate(s.length()); @@ -124,7 +124,7 @@ public class StringUtilTest extends TestCase { assertNull(CharArrayUtil.fromSequenceWithoutCopying(buffer.subSequence(1, 5))); assertNull(CharArrayUtil.fromSequenceWithoutCopying(buffer.subSequence(1, 2))); } - + public void testTitleCase() { assertEquals("Couldn't Connect to Debugger", StringUtil.wordsToBeginFromUpperCase("Couldn't connect to debugger")); } @@ -198,7 +198,7 @@ public class StringUtilTest extends TestCase { assertEquals(Arrays.asList("aa"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("aa"))); assertEquals(Arrays.asList("\n", "\n", "aa\n", "\n", "bb\n", "cc\n", "\n"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\n\naa\n\nbb\ncc\n\n"))); - + assertEquals(Arrays.asList("\r", "\r\n", "\r"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\r\r\n\r"))); assertEquals(Arrays.asList("\r\n", "\r", "\r\n"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\r\n\r\r\n"))); @@ -224,4 +224,13 @@ public class StringUtilTest extends TestCase { } } } + + public void testReplaceReturnReplacementIfTextEqualsToReplacedText() { + String newS = "/tmp"; + assertSame(StringUtil.replace("$PROJECT_FILE$", "$PROJECT_FILE$".toLowerCase().toUpperCase() /* ensure new String instance */, newS), newS); + } + + public void testReplace() { + assertEquals(StringUtil.replace("$PROJECT_FILE$/filename", "$PROJECT_FILE$", "/tmp"), "/tmp/filename"); + } } From b56cdf97d5ef8976a230310e6ba875f6980b2d1a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 12:17:52 +0400 Subject: [PATCH 25/69] revert disjunction elimination in common api --- .../impl/quickfix/ChangeMethodSignatureFromUsageFix.java | 7 ++++++- java/java-psi-api/src/com/intellij/psi/GenericsUtil.java | 3 --- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java index d85fb72894d7..d753875208c3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java @@ -333,6 +333,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig else { PsiType exprType = RefactoringUtil.getTypeByExpression(expression); if (exprType == null) return null; + if (exprType instanceof PsiDisjunctionType) { + exprType = ((PsiDisjunctionType)exprType).getLeastUpperBound(); + } final ParameterInfoImpl changedParameterInfo = new ParameterInfoImpl(i, parameter.getName(), exprType); result.add(changedParameterInfo); changedParams.add(changedParameterInfo); @@ -403,7 +406,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig if (varargParam != null && pi >= parameters.length) return false; PsiType exprType = RefactoringUtil.getTypeByExpression(expression); if (exprType == null) return false; - exprType = GenericsUtil.getVariableTypeByExpressionType(exprType); + if (exprType instanceof PsiDisjunctionType) { + exprType = ((PsiDisjunctionType)exprType).getLeastUpperBound(); + } JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject()); String name = suggestUniqueParameterName(codeStyleManager, expression, exprType, existingNames); final ParameterInfoImpl newParameterInfo = new ParameterInfoImpl(-1, name, exprType, expression.getText().replace('\n', ' ')); diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 163055f442fa..4646aea635b3 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -351,9 +351,6 @@ public class GenericsUtil { @Nullable public static PsiType getVariableTypeByExpressionType(@Nullable PsiType type, final boolean openCaptured) { if (type == null) return null; - if (type instanceof PsiDisjunctionType) { - type = ((PsiDisjunctionType)type).getLeastUpperBound(); - } if (type instanceof PsiCapturedWildcardType) { type = ((PsiCapturedWildcardType)type).getWildcard(); } From 0e24b7c6fe6072cb790a6341309a452ac2331ddd Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:25:04 +0200 Subject: [PATCH 26/69] cleanup --- .../intellij/execution/impl/DefaultJavaProgramRunner.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index 7f5ae45f3348..a99182489cde 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -144,7 +144,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { } @Override - public void update(final AnActionEvent event) { + public void update(@NotNull final AnActionEvent event) { final Presentation presentation = event.getPresentation(); if (!isVisible()) { presentation.setVisible(false); @@ -173,7 +173,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { } @Override - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler); if (proxy != null) { final WiseDumpThreadsListener wiseListener = Boolean.TRUE.equals(Boolean.getBoolean(ourWiseThreadDumpProperty)) ? @@ -255,7 +255,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { } @Override - public void actionPerformed(final AnActionEvent e) { + public void actionPerformed(@NotNull final AnActionEvent e) { ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler); if (proxy != null) { proxy.sendStop(); From 9debbd72d1300dad6d0b01869f0f77a07346a6a0 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:31:08 +0200 Subject: [PATCH 27/69] =?UTF-8?q?fix=20tests=20=E2=80=94=20dispose=20run?= =?UTF-8?q?=20content=20descriptor=20on=20project=20dispose?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../intellij/execution/impl/DefaultJavaProgramRunner.java | 5 +---- .../com/intellij/execution/runners/RunContentBuilder.java | 1 + .../src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index a99182489cde..0b8f32964d59 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -34,7 +34,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; import com.intellij.unscramble.AnalyzeStacktraceUtil; import com.intellij.unscramble.ThreadDumpConsoleFactory; import com.intellij.unscramble.ThreadDumpParser; @@ -100,9 +99,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { if (shouldAddDefaultActions) { addDefaultActions(contentBuilder); } - RunContentDescriptor contentDescriptor = contentBuilder.showRunContent(env.getContentToReuse()); - Disposer.register(env.getProject(), contentDescriptor); - return contentDescriptor; + return contentBuilder.showRunContent(env.getContentToReuse()); } @Deprecated diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java index 2893f3be5973..2b0f800a5088 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java @@ -222,6 +222,7 @@ public class RunContentBuilder extends RunTab { public RunContentDescriptor showRunContent(@Nullable RunContentDescriptor reuseContent) { RunContentDescriptor descriptor = createDescriptor(); Disposer.register(descriptor, this); + Disposer.register(myProject, myRunContentDescriptor); myRunContentDescriptor = descriptor; RunContentManagerImpl.copyContentAndBehavior(descriptor, reuseContent); return descriptor; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 890f0c3e622f..8dc06a1b24ec 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -133,6 +133,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { myConsole = session.getConsoleView(); myRunContentDescriptor = new RunContentDescriptor(myConsole, session.getDebugProcess().getProcessHandler(), myUi.getComponent(), session.getSessionName(), icon); Disposer.register(myRunContentDescriptor, this); + Disposer.register(myProject, myRunContentDescriptor); } @Nullable From d8060fbd0753b624a9aca4aecf37cf6e03ae6f4f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:35:59 +0200 Subject: [PATCH 28/69] clear dataProviders on dispose --- .../src/com/intellij/ui/content/impl/ContentManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java index d0b110f083bf..51cb45ab3be2 100644 --- a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java @@ -33,9 +33,8 @@ import com.intellij.ui.components.panels.Wrapper; import com.intellij.ui.content.*; import com.intellij.ui.switcher.SwitchProvider; import com.intellij.ui.switcher.SwitchTarget; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.SmartList; - +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -703,6 +702,7 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene myContentWithChangedComponent.clear(); myUI = null; myListeners.clear(); + dataProviders.clear(); } @Override From e3df5a29b80af8f1385ef8ec5d895129268738a9 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 12:42:56 +0400 Subject: [PATCH 29/69] create 'JAR Application' configuration from context menu for jar files (IDEA-81929) --- .../jar/JarApplicationConfiguration.java | 2 +- .../JarApplicationConfigurationProducer.java | 63 +++++++++++++++++++ .../jar/JarApplicationConfigurationType.java | 6 ++ resources/src/META-INF/IdeaPlugin.xml | 1 + 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java index 7f153165ca32..970abc055032 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java @@ -42,7 +42,7 @@ import java.util.Map; /** * @author nik */ -public class JarApplicationConfiguration extends RunConfigurationBase implements CommonJavaRunConfigurationParameters, SearchScopeProvidingRunProfile { +public class JarApplicationConfiguration extends LocatableConfigurationBase implements CommonJavaRunConfigurationParameters, SearchScopeProvidingRunProfile { private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters(); private JarApplicationConfigurationBean myBean = new JarApplicationConfigurationBean(); private Map myEnvs = new LinkedHashMap(); diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java new file mode 100644 index 000000000000..41e2ee9f2291 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2014 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.intellij.execution.jar; + +import com.intellij.execution.Location; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public class JarApplicationConfigurationProducer extends RunConfigurationProducer { + public JarApplicationConfigurationProducer() { + super(JarApplicationConfigurationType.getInstance()); + } + + @Override + protected boolean setupConfigurationFromContext(JarApplicationConfiguration configuration, + ConfigurationContext context, + Ref sourceElement) { + VirtualFile file = getJarFileFromContext(context); + if (file != null) { + configuration.setName(file.getName()); + configuration.setJarPath(file.getPath()); + return true; + } + return false; + } + + @Nullable + private static VirtualFile getJarFileFromContext(ConfigurationContext context) { + Location location = context.getLocation(); + if (location == null) return null; + + VirtualFile file = location.getVirtualFile(); + return file != null && FileTypes.ARCHIVE.equals(file.getFileType()) ? file : null; + } + + @Override + public boolean isConfigurationFromContext(JarApplicationConfiguration configuration, ConfigurationContext context) { + VirtualFile file = getJarFileFromContext(context); + return file != null && FileUtil.pathsEqual(file.getPath(), configuration.getJarPath()); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java index 05fb3aaa0972..8c7fdebc8c52 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java @@ -19,6 +19,7 @@ import com.intellij.execution.ExecutionBundle; import com.intellij.execution.configuration.ConfigurationFactoryEx; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.ConfigurationTypeBase; +import com.intellij.execution.configurations.ConfigurationTypeUtil; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.icons.AllIcons; import com.intellij.openapi.project.Project; @@ -27,6 +28,11 @@ import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; public class JarApplicationConfigurationType extends ConfigurationTypeBase implements ConfigurationType { + @NotNull + public static JarApplicationConfigurationType getInstance() { + return ConfigurationTypeUtil.findConfigurationType(JarApplicationConfigurationType.class); + } + public JarApplicationConfigurationType() { super("JarApplication", ExecutionBundle.message("jar.application.configuration.name"), ExecutionBundle.message("jar.application.configuration.description"), AllIcons.FileTypes.Archive); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 6e3ca97edb51..ca054922776c 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1225,6 +1225,7 @@ + From 05fcdce317ae58a1375cfb49f6dee0ba2bee1de6 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 12:48:43 +0400 Subject: [PATCH 30/69] don't suggest to create 'JAR application' configuration for zip files --- .../execution/jar/JarApplicationConfigurationProducer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java index 41e2ee9f2291..b2b9f8fef81c 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java @@ -18,9 +18,9 @@ package com.intellij.execution.jar; import com.intellij.execution.Location; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.RunConfigurationProducer; -import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nullable; @@ -52,7 +52,7 @@ public class JarApplicationConfigurationProducer extends RunConfigurationProduce if (location == null) return null; VirtualFile file = location.getVirtualFile(); - return file != null && FileTypes.ARCHIVE.equals(file.getFileType()) ? file : null; + return file != null && FileUtilRt.extensionEquals(file.getName(), "jar") ? file : null; } @Override From 1a7d442dc594244cbabcc2c3f0dc9e996d7ad198 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 13:02:46 +0400 Subject: [PATCH 31/69] FileDownloader: synchronization added --- .../util/download/impl/FileDownloaderImpl.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java index e9be287a24d3..20d889d1edfa 100644 --- a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java +++ b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java @@ -379,6 +379,7 @@ public class FileDownloaderImpl implements FileDownloader { private final ProgressIndicator myParent; private final int myTasksCount; private final AtomicDouble myTotalFraction; + private final Object myLock = new Object(); private LinkedHashMap myText2Stack = new LinkedHashMap(); private ConcurrentTasksProgressManager(ProgressIndicator parent, int tasksCount) { @@ -398,12 +399,17 @@ public class FileDownloaderImpl implements FileDownloader { public void setText2(@NotNull SubTaskProgressIndicator subTask, @Nullable String text) { if (text != null) { - myText2Stack.put(subTask, text); + synchronized (myLock) { + myText2Stack.put(subTask, text); + } myParent.setText2(text); } else { - myText2Stack.remove(subTask); - String prev = myText2Stack.getLastValue(); + String prev; + synchronized (myLock) { + myText2Stack.remove(subTask); + prev = myText2Stack.getLastValue(); + } if (prev != null) { myParent.setText2(prev); } From d785412c8e1ec0880a8febb178d82840e472ce15 Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Fri, 5 Sep 2014 13:06:27 +0400 Subject: [PATCH 32/69] EDU-147 preview mode for task files --- .../resources/META-INF/plugin.xml | 3 + .../coursecreator/CCProjectComponent.java | 42 ++++++- .../coursecreator/CCProjectService.java | 2 +- .../coursecreator/actions/AddTaskWindow.java | 5 +- .../coursecreator/actions/CCShowPreview.java | 104 ++++++++++++++++++ .../actions/CreateCourseArchive.java | 15 ++- .../coursecreator/format/TaskWindow.java | 7 +- 7 files changed, 164 insertions(+), 14 deletions(-) create mode 100644 python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java diff --git a/python/edu/course-creator/resources/META-INF/plugin.xml b/python/edu/course-creator/resources/META-INF/plugin.xml index 775e4fadb6f1..65e7153aea1b 100644 --- a/python/edu/course-creator/resources/META-INF/plugin.xml +++ b/python/edu/course-creator/resources/META-INF/plugin.xml @@ -54,6 +54,9 @@ + + + diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java index 34de943d2ad0..7cec23a9a7d2 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java @@ -1,12 +1,13 @@ package org.jetbrains.plugins.coursecreator; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ProjectComponent; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.event.EditorFactoryEvent; import com.intellij.openapi.editor.impl.EditorFactoryImpl; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; @@ -15,7 +16,10 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.coursecreator.format.Course; +import java.io.IOException; + public class CCProjectComponent implements ProjectComponent { + private static final Logger LOG = Logger.getInstance(CCProjectComponent.class.getName()); private final Project myProject; public CCProjectComponent(Project project) { @@ -39,13 +43,43 @@ public class CCProjectComponent implements ProjectComponent { public void run() { Course course = CCProjectService.getInstance(myProject).getCourse(); if (course != null) { - EditorFactory.getInstance().addEditorFactoryListener(new CCEditorFactoryListener(), myProject); + myProject.getMessageBus().connect(myProject).subscribe( + FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { + @Override + public void selectionChanged(@NotNull FileEditorManagerEvent event) { + final VirtualFile oldFile = event.getOldFile(); + if (oldFile == null) { + return; + } + if (CCProjectService.getInstance(myProject).isTaskFile(oldFile)) { + FileEditorManager.getInstance(myProject).closeFile(oldFile); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + oldFile.delete(myProject); + } + catch (IOException e) { + LOG.error(e); + } + } + }); + } + } + }); + + final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener(); + EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject); VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles(); for (VirtualFile file : files) { + if (CCProjectService.getInstance(myProject).isTaskFile(file)) { + FileEditorManager.getInstance(myProject).closeFile(file); + continue; + } FileEditor fileEditor = FileEditorManager.getInstance(myProject).getSelectedEditor(file); if (fileEditor instanceof PsiAwareTextEditorImpl) { Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor(); - new CCEditorFactoryListener().editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor )); + editorFactoryListener.editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor)); } } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java index 2b9ad27a855e..17bb8013e2a7 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java @@ -116,7 +116,7 @@ public class CCProjectService implements PersistentStateComponent { } List taskWindows = taskFile.getTaskWindows(); for (TaskWindow taskWindow : taskWindows) { - taskWindow.drawHighlighter(editor); + taskWindow.drawHighlighter(editor, false); } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java index ff88cea5fd42..0bc631dbd784 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java @@ -13,6 +13,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.coursecreator.CCProjectService; import org.jetbrains.plugins.coursecreator.format.*; import org.jetbrains.plugins.coursecreator.ui.CreateTaskWindowDialog; @@ -59,12 +60,12 @@ public class AddTaskWindow extends DumbAwareAction { } int index = taskFile.getTaskWindows().size() + 1; taskFile.addTaskWindow(taskWindow, index); - taskWindow.drawHighlighter(editor); + taskWindow.drawHighlighter(editor, false); DaemonCodeAnalyzerImpl.getInstance(project).restart(file); } @Override - public void update(AnActionEvent event) { + public void update(@NotNull AnActionEvent event) { final Presentation presentation = event.getPresentation(); final Project project = event.getData(CommonDataKeys.PROJECT); if (project == null) { diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java new file mode 100644 index 000000000000..bccaacaf1957 --- /dev/null +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.plugins.coursecreator.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.intellij.util.containers.hash.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.coursecreator.CCProjectService; +import org.jetbrains.plugins.coursecreator.format.*; + +import java.util.Map; + +public class CCShowPreview extends DumbAwareAction { + public CCShowPreview() { + super("Show preview","Show preview", null); + } + + @Override + public void update(@NotNull AnActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setEnabled(false); + presentation.setVisible(false); + final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); + if (file != null && file.getName().contains(".answer")) { + presentation.setEnabled(true); + presentation.setVisible(true); + } + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getProject(); + if (project == null) { + return; + } + final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); + if (file == null || !file.getName().contains(".answer")) { + return; + } + final PsiDirectory taskDir = file.getContainingDirectory(); + if (taskDir == null) { + return; + } + PsiDirectory lessonDir = taskDir.getParentDirectory(); + if (lessonDir == null) { + return; + } + Course course = CCProjectService.getInstance(project).getCourse(); + if (course == null) { + return; + } + Lesson lesson = course.getLesson(lessonDir.getName()); + Task task = lesson.getTask(taskDir.getName()); + TaskFile taskFile = task.getTaskFile(file.getName()); + final Map taskFilesCopy = new HashMap(); + for (final Map.Entry entry : task.getTaskFiles().entrySet()) { + if (entry.getValue() == taskFile) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + CreateCourseArchive.createUserFile(project, taskFilesCopy, taskDir.getVirtualFile(), taskDir.getVirtualFile(), entry); + } + }); + } + } + String userFileName = FileUtil.getNameWithoutExtension(file.getName()) + ".py"; + VirtualFile userFile = taskDir.getVirtualFile().findChild(userFileName); + if (userFile != null) { + FileEditorManager.getInstance(project).openFile(userFile, true); + Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + if (editor == null) { + return; + } + for (TaskWindow taskWindow : taskFile.getTaskWindows()) { + taskWindow.drawHighlighter(editor, true); + } + CreateCourseArchive.resetTaskFiles(taskFilesCopy); + } + } +} \ No newline at end of file diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java index 059d0c9e0069..8db49156c987 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java @@ -62,15 +62,20 @@ public class CreateCourseArchive extends DumbAwareAction { final VirtualFile baseDir = project.getBaseDir(); final Map lessons = course.getLessonsMap(); //map to store initial task file - Map taskFiles = new HashMap(); + final Map taskFiles = new HashMap(); for (Map.Entry lesson : lessons.entrySet()) { final VirtualFile lessonDir = baseDir.findChild(lesson.getKey()); if (lessonDir == null) continue; for (Map.Entry task : lesson.getValue().myTasksMap.entrySet()) { final VirtualFile taskDir = lessonDir.findChild(task.getKey()); if (taskDir == null) continue; - for (Map.Entry entry : task.getValue().task_files.entrySet()) { - createUserFile(project, taskFiles, taskDir, taskDir, entry); + for (final Map.Entry entry : task.getValue().task_files.entrySet()) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + createUserFile(project, taskFiles, taskDir, taskDir, entry); + } + }); } } } @@ -129,13 +134,15 @@ public class CreateCourseArchive extends DumbAwareAction { }); } }, "x", "qwe"); - document.addDocumentListener(new InsertionListener(taskFile)); + InsertionListener listener = new InsertionListener(taskFile); + document.addDocumentListener(listener); taskFilesCopy.put(taskFile, taskFileSaved); Collections.sort(taskFile.getTaskWindows()); for (int i = taskFile.getTaskWindows().size() - 1; i >= 0; i--) { final TaskWindow taskWindow = taskFile.getTaskWindows().get(i); replaceTaskWindow(project, document, taskWindow); } + document.removeDocumentListener(listener); } private static void replaceTaskWindow(@NotNull final Project project, diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java index 121d169a3358..6b1be7ef3e7d 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java @@ -68,16 +68,17 @@ public class TaskWindow implements Comparable{ } } - public void drawHighlighter(@NotNull final Editor editor) { + public void drawHighlighter(@NotNull final Editor editor, boolean useLength) { int startOffset = editor.getDocument().getLineStartOffset(line) + start; - int endOffset = startOffset + myReplacementLength; + int highlighterLength = useLength ? length : myReplacementLength; + int endOffset = startOffset + highlighterLength; TextAttributes defaultTestAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.LIVE_TEMPLATE_ATTRIBUTES); RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, HighlighterLayer.LAST + 1, defaultTestAttributes, HighlighterTargetArea.EXACT_RANGE); highlighter.setGreedyToLeft(true); - highlighter.setGreedyToRight(true); + highlighter.setGreedyToRight(false); } public int getIndex() { From 4225b2e93f697897354dadddb8b699bf664f2e94 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 13:17:10 +0400 Subject: [PATCH 33/69] change initial expectations for light extract object --- .../extractMethod/ExtractMethodProcessor.java | 27 ++++--- .../ExtractLightMethodObjectHandler.java | 75 +++++++++++++++---- .../ExtractMethodObjectHandler.java | 40 +++++----- .../SimpleGeneration.java | 4 +- .../ExtractMethodObject4DebuggerTest.java | 19 ++--- 5 files changed, 108 insertions(+), 57 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index e63b3751e425..44d1c2f9da10 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -575,10 +575,16 @@ public class ExtractMethodProcessor implements MatchProvider { chooseAnchor(); - int col = myEditor.getCaretModel().getLogicalPosition().column; - int line = myEditor.getCaretModel().getLogicalPosition().line; - LogicalPosition pos = new LogicalPosition(0, 0); - myEditor.getCaretModel().moveToLogicalPosition(pos); + LogicalPosition pos1; + if (myEditor != null) { + int col = myEditor.getCaretModel().getLogicalPosition().column; + int line = myEditor.getCaretModel().getLogicalPosition().line; + pos1 = new LogicalPosition(line, col); + LogicalPosition pos = new LogicalPosition(0, 0); + myEditor.getCaretModel().moveToLogicalPosition(pos); + } else { + pos1 = null; + } final SearchScope processConflictsScope = myMethodVisibility.equals(PsiModifier.PRIVATE) ? new LocalSearchScope(myTargetClass) : @@ -610,12 +616,13 @@ public class ExtractMethodProcessor implements MatchProvider { ApplicationManager.getApplication().runWriteAction(extract); } - LogicalPosition pos1 = new LogicalPosition(line, col); - myEditor.getCaretModel().moveToLogicalPosition(pos1); - int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset(); - myEditor.getCaretModel().moveToOffset(offset); - myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - myEditor.getSelectionModel().removeSelection(); + if (myEditor != null) { + myEditor.getCaretModel().moveToLogicalPosition(pos1); + int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset(); + myEditor.getCaretModel().moveToOffset(offset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + myEditor.getSelectionModel().removeSelection(); + } } private void doExtract() throws IncorrectOperationException { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java index c5ee560434a5..30eb9035d419 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java @@ -16,18 +16,27 @@ package com.intellij.refactoring.extractMethodObject; import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.controlFlow.*; import com.intellij.refactoring.extractMethod.AbstractExtractDialog; import com.intellij.refactoring.extractMethod.InputVariables; +import com.intellij.refactoring.extractMethod.PrepareFailedException; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.VariableData; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + public class ExtractLightMethodObjectHandler { private static final Logger LOG = Logger.getInstance("#" + ExtractLightMethodObjectHandler.class.getName()); @@ -51,36 +60,74 @@ public class ExtractLightMethodObjectHandler { @Nullable public static ExtractedData extractLightMethodObject(final Project project, - final Editor editor, final PsiFile file, - final PsiElement[] elements, - final String methodName) { - if (elements == null || elements.length == 0) { + @NotNull final PsiCodeFragment fragment, + final String methodName) throws PrepareFailedException { + final PsiElement[] elements = fragment.getChildren(); + if (elements.length == 0) { return null; } final PsiFile copy = PsiFileFactory.getInstance(project) .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), true); - final PsiElement[] elementsCopy = new PsiElement[elements.length]; - for (int i = 0; i < elements.length; i++) { - PsiElement element = elements[i]; - final TextRange textRange = element.getTextRange(); - elementsCopy[i] = CodeInsightUtil.findElementInRange(copy, textRange.getStartOffset(), textRange.getEndOffset(), element.getClass()); + final PsiElement originalContext = fragment.getContext(); + if (originalContext == null) { + return null; } + final TextRange range = originalContext.getTextRange(); + final PsiElement originalAnchor = + CodeInsightUtil.findElementInRange(copy, range.getStartOffset(), range.getEndOffset(), originalContext.getClass()); + //todo before this or super, not found etc + final PsiElement anchor = RefactoringUtil.getParentStatement(originalAnchor, false); + final PsiElement[] elementsCopy = new PsiElement[elements.length]; + final PsiElement container = anchor.getParent(); + elementsCopy[0] = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public PsiElement compute() { + return container.addRangeAfter(elements[0], elements[elements.length - 1], anchor); + } + }); + for (int i = 1; i < elements.length; i++) { + elementsCopy[i] = elementsCopy[i - 1].getNextSibling(); + } + + final ControlFlow controlFlow; + try { + controlFlow = ControlFlowFactory.getInstance(project).getControlFlow(container, AllVariablesControlFlowPolicy.getInstance()); + } + catch (AnalysisCanceledException e) { + return null; + } + + final List variables = ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize()); + + final String outputVariables = StringUtil.join(variables, new Function() { + @Override + public String fun(PsiVariable variable) { + return "\"variable: \" + " + variable.getName(); + } + }, " +"); + final PsiStatement outStatement = JavaPsiFacade.getElementFactory(project).createStatementFromText("System.out.println(" + outputVariables + ");", anchor); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + container.addAfter(outStatement, elementsCopy[elementsCopy.length - 1]); + } + }); final Document document = PsiDocumentManager.getInstance(project).getDocument(copy); LOG.assertTrue(document != null); - final int startOffset = elements[0].getTextRange().getStartOffset(); - final int endOffset = elements[elements.length - 1].getTextRange().getEndOffset(); + final int startOffset = elementsCopy[0].getTextRange().getStartOffset(); + final int endOffset = elementsCopy[elementsCopy.length - 1].getTextRange().getEndOffset(); final RangeMarker callSiteMarker = document.createRangeMarker(startOffset, endOffset); callSiteMarker.setGreedyToLeft(true); callSiteMarker.setGreedyToRight(true); try { - final ExtractMethodObjectProcessor extractMethodObjectProcessor = new ExtractMethodObjectProcessor(project, editor, elementsCopy, "") { + final ExtractMethodObjectProcessor extractMethodObjectProcessor = new ExtractMethodObjectProcessor(project, null, elementsCopy, "") { @Override protected AbstractExtractDialog createExtractMethodObjectDialog(MyExtractMethodProcessor processor) { return new LightExtractMethodObjectDialog(this, methodName); @@ -88,7 +135,7 @@ public class ExtractLightMethodObjectHandler { }; extractMethodObjectProcessor.getExtractProcessor().setShowErrorDialogs(false); - ExtractMethodObjectHandler.extractMethodObject(project, editor, file, extractMethodObjectProcessor); + ExtractMethodObjectHandler.extractMethodObject(project, null, extractMethodObjectProcessor); final String generatedCall = document.getText(new TextRange(callSiteMarker.getStartOffset(), callSiteMarker.getEndOffset())); return new ExtractedData(generatedCall, extractMethodObjectProcessor.getInnerClass()); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java index b09a02cfd561..8004dcf77578 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java @@ -20,12 +20,10 @@ */ package com.intellij.refactoring.extractMethodObject; -import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ScrollType; @@ -37,12 +35,9 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.extractMethod.AbstractExtractDialog; import com.intellij.refactoring.extractMethod.ExtractMethodHandler; -import com.intellij.refactoring.extractMethod.InputVariables; import com.intellij.refactoring.extractMethod.PrepareFailedException; import com.intellij.refactoring.util.CommonRefactoringUtil; -import com.intellij.refactoring.util.VariableData; import com.intellij.refactoring.util.duplicates.DuplicatesImpl; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -69,20 +64,18 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { return; } - extractMethodObject(project, editor, file, new ExtractMethodObjectProcessor(project, editor, elements, "")); - } - - static void extractMethodObject(Project project, Editor editor, PsiFile file, ExtractMethodObjectProcessor processor) { - final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); try { - if (!extractProcessor.prepare()) return; + extractMethodObject(project, editor, new ExtractMethodObjectProcessor(project, editor, elements, "")); } catch (PrepareFailedException e) { CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), ExtractMethodObjectProcessor.REFACTORING_NAME, HelpID.EXTRACT_METHOD_OBJECT); ExtractMethodHandler.highlightPrepareError(e, file, editor, project); - return; } + } + static void extractMethodObject(Project project, Editor editor, ExtractMethodObjectProcessor processor) throws PrepareFailedException { + final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); + if (!extractProcessor.prepare()) return; if (!CommonRefactoringUtil.checkReadOnlyStatus(project, extractProcessor.getTargetClass().getContainingFile())) return; if (extractProcessor.showDialog()) { run(project, editor, processor, extractProcessor); @@ -90,11 +83,16 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { } public static void run(@NotNull final Project project, - @NotNull final Editor editor, + final Editor editor, @NotNull final ExtractMethodObjectProcessor processor, @NotNull final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor) { - final int offset = editor.getCaretModel().getOffset(); - final RangeMarker marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); + final RangeMarker marker; + if (editor != null) { + final int offset = editor.getCaretModel().getOffset(); + marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); + } else { + marker = null; + } CommandProcessor.getInstance().executeCommand(project, new Runnable() { public void run() { PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() { @@ -119,7 +117,9 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { if (processor.isCreateInnerClass()) { processor.moveUsedMethodsToInner(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + if (editor != null) { + DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + } } ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -134,9 +134,11 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { }); } }, ExtractMethodObjectProcessor.REFACTORING_NAME, ExtractMethodObjectProcessor.REFACTORING_NAME); - editor.getCaretModel().moveToOffset(marker.getStartOffset()); - marker.dispose(); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + if (editor != null) { + editor.getCaretModel().moveToOffset(marker.getStartOffset()); + marker.dispose(); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } } public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) { diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java index 178a4844ef5f..873f2205e1af 100644 --- a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java +++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java @@ -1,7 +1,5 @@ class Sample { void foo() { - int i = 0; - int j = 0; - System.out.println(i + j); + System.out.println("hello world"); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java index 64e355126e2f..bc6c1befaa12 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java @@ -21,10 +21,9 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; +import com.intellij.psi.*; import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; import com.intellij.testFramework.IdeaTestUtil; import org.jetbrains.annotations.NotNull; @@ -36,16 +35,14 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { return JavaTestUtil.getJavaTestDataPath(); } - private void doTest(String expectedCallSite, String expectedClass) throws Exception { + private void doTest(String evaluatedText, String expectedCallSite, String expectedClass) throws Exception { final String testName = getTestName(false); configureByFile("/refactoring/extractMethodObject4Debugger/" + testName + ".java"); - int startOffset = getEditor().getSelectionModel().getSelectionStart(); - int endOffset = getEditor().getSelectionModel().getSelectionEnd(); - PsiElement[] elements = CodeInsightUtil.findStatementsInRange(getFile(), startOffset, endOffset); - assertTrue(elements.length > 0); - + final int offset = getEditor().getCaretModel().getOffset(); + final PsiElement context = getFile().findElementAt(offset); + final JavaCodeFragment fragment = JavaCodeFragmentFactory.getInstance(getProject()).createCodeBlockCodeFragment(evaluatedText, context, false); final ExtractLightMethodObjectHandler.ExtractedData extractedData = - ExtractLightMethodObjectHandler.extractLightMethodObject(getProject(), getEditor(), getFile(), elements, "test"); + ExtractLightMethodObjectHandler.extractLightMethodObject(getProject(), getFile(), fragment, "test"); assertNotNull(extractedData); assertEquals(expectedCallSite, extractedData.getGeneratedCallText()); final PsiClass innerClass = extractedData.getGeneratedInnerClass(); @@ -53,7 +50,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { } public void testSimpleGeneration() throws Exception { - doTest(" Test test = new Test().invoke();\n" + + doTest("int i = 0; int j = 0;", "Test test = new Test().invoke();\n" + " int i = test.getI();\n" + " int j = test.getJ();", From 037229fb6c72589e0ca1e9f2471ff57f6893f267 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 13:32:35 +0400 Subject: [PATCH 34/69] test fixed --- .../execution/configurations/JavaCommandLineTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java index 2708ac91181c..e4d0bc039c5d 100644 --- a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java +++ b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java @@ -48,6 +48,14 @@ public class JavaCommandLineTest extends LightIdeaTestCase { } } + public void testJarParameter() throws CantRunException { + JavaParameters javaParameters = new JavaParameters(); + javaParameters.setJdk(getProjectJDK()); + javaParameters.setJarPath("my-jar-file.jar"); + String commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString(); + assertTrue(commandLineString, commandLineString.contains("-jar my-jar-file.jar")); + } + public void testClasspath() throws CantRunException { JavaParameters javaParameters; String commandLineString; @@ -55,12 +63,14 @@ public class JavaCommandLineTest extends LightIdeaTestCase { javaParameters = new JavaParameters(); final Sdk internalJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk(); javaParameters.setJdk(internalJdk); + javaParameters.getClassPath().add("my-jar-file.jar"); javaParameters.setMainClass("Main"); commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString(); assertTrue(containsClassPath(commandLineString)); javaParameters = new JavaParameters(); javaParameters.setJdk(internalJdk); + javaParameters.getClassPath().add("my-jar-file.jar"); javaParameters.setMainClass("Main"); javaParameters.getVMParametersList().add("-cp"); javaParameters.getVMParametersList().add(".."); @@ -70,6 +80,7 @@ public class JavaCommandLineTest extends LightIdeaTestCase { javaParameters = new JavaParameters(); javaParameters.setJdk(internalJdk); + javaParameters.getClassPath().add("my-jar-file.jar"); javaParameters.setMainClass("Main"); javaParameters.getVMParametersList().add("-classpath"); javaParameters.getVMParametersList().add(".."); From 32ce4a29875aec61c3f205068557d3a316032eec Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Fri, 5 Sep 2014 13:51:07 +0400 Subject: [PATCH 35/69] remove duplicating method --- .../src/com/intellij/util/containers/ContainerUtil.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 053bab6c86f2..ab8ab2a33aa4 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -68,12 +68,6 @@ public class ContainerUtil extends ContainerUtilRt { return ContainerUtilRt.newHashMap(keys, values); } - @NotNull - @Contract(pure=true) - public static Map newHashMap(int initialCapacity) { - return ContainerUtilRt.newHashMap(initialCapacity); - } - @NotNull @Contract(pure=true) public static TreeMap newTreeMap() { From bbbdc98bbdbaa4e79fa1835f878353ba947b030d Mon Sep 17 00:00:00 2001 From: Alexander Doroshko Date: Thu, 4 Sep 2014 18:43:50 +0400 Subject: [PATCH 36/69] DefaultWebServerPathHandler must be last --- platform/platform-resources/src/META-INF/XmlPlugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 566d674d0063..b6653d81eec7 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -548,7 +548,7 @@ - + From a14f1e64d843a003dbb286ece0c8e949c5fdf24e Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 5 Sep 2014 13:59:45 +0400 Subject: [PATCH 37/69] SettingsTreeView refactoring --- .../com/intellij/ui/treeStructure/Tree.java | 2 +- .../options/newEditor/SettingsTreeView.java | 249 +++++++++--------- 2 files changed, 119 insertions(+), 132 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java index 4a974b993616..96fab545d3e7 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java @@ -843,7 +843,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith * @return the deepest visible component of the renderer */ @Nullable - protected Component getDeepestRendererComponentAt(int x, int y) { + public Component getDeepestRendererComponentAt(int x, int y) { int row = getRowForLocation(x, y); if (row >= 0) { TreeCellRenderer renderer = getCellRenderer(); diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java index b86282f95309..0e579cfd7ef2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java @@ -49,6 +49,7 @@ import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.plaf.TreeUI; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import java.awt.*; @@ -63,6 +64,7 @@ import java.util.List; * @author Sergey.Malenkov */ final class SettingsTreeView extends JComponent implements Disposable, OptionsEditorColleague { + private static final String NODE_ICON = "settings.tree.view.icon"; private static final Color NORMAL_NODE = new JBColor(Gray._60, Gray._140); private static final Color WRONG_CONTENT = JBColor.RED; private static final Color MODIFIED_CONTENT = JBColor.BLUE; @@ -74,7 +76,6 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd private final MyRoot myRoot; private final JScrollPane myScroller; private JLabel mySeparator; - private final MyRenderer myRenderer = new MyRenderer(); private final IdentityHashMap myConfigurableToNodeMap = new IdentityHashMap(); private final IdentityHashMap myConfigurableToWrapperMap = new IdentityHashMap(); @@ -98,9 +99,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd myTree.setRowHeight(-1); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - myTree.setCellRenderer(myRenderer); + myTree.setCellRenderer(new MyRenderer()); myTree.setRootVisible(false); myTree.setShowsRootHandles(false); + myTree.setExpandableItemsEnabled(false); myScroller = ScrollPaneFactory.createScrollPane(myTree, true); myScroller.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent()); @@ -272,7 +274,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } int height = mySeparator.getPreferredSize().height; ConfigurableGroup group = findConfigurableGroupAt(0, height); - if (group != null && group == findConfigurableGroupAt(0, -myRenderer.getSeparatorHeight())) { + if (group != null && group == findConfigurableGroupAt(0, 0)) { mySeparator.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0)); mySeparator.setText(group.getDisplayName()); @@ -403,7 +405,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } SimpleNode[] result = new SimpleNode[myGroups.length]; for (int i = 0; i < myGroups.length; i++) { - result[i] = new MyNode(this, myGroups[i]); + result[i] = new MyNode(this, myGroups[i], 0); } return result; } @@ -413,21 +415,24 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd private final Configurable.Composite myComposite; private final Configurable myConfigurable; private final String myDisplayName; + private final int myLevel; - private MyNode(CachingSimpleNode parent, Configurable configurable) { + private MyNode(CachingSimpleNode parent, Configurable configurable, int level) { super(parent); myComposite = configurable instanceof Configurable.Composite ? (Configurable.Composite)configurable : null; myConfigurable = configurable; String name = configurable.getDisplayName(); myDisplayName = name != null ? name.replace("\n", " ") : "{ " + configurable.getClass().getSimpleName() + " }"; + myLevel = level; } - private MyNode(CachingSimpleNode parent, ConfigurableGroup group) { + private MyNode(CachingSimpleNode parent, ConfigurableGroup group, int level) { super(parent); myComposite = group; myConfigurable = group instanceof Configurable ? (Configurable)group : null; String name = group.getDisplayName(); myDisplayName = name != null ? name.replace("\n", " ") : "{ " + group.getClass().getSimpleName() + " }"; + myLevel = level; } @Override @@ -444,7 +449,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } SimpleNode[] result = new SimpleNode[configurables.length]; for (int i = 0; i < configurables.length; i++) { - result[i] = new MyNode(this, configurables[i]); + result[i] = new MyNode(this, configurables[i], myLevel + 1); if (myConfigurable != null) { myFilter.myContext.registerKid(myConfigurable, configurables[i]); } @@ -458,25 +463,17 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } } - private final class MyRenderer extends GroupedElementsRenderer.Tree { - private JLabel myNodeIcon; - private JLabel myProjectIcon; + private final class MyRenderer extends JPanel implements TreeCellRenderer { + private final JLabel myTextLabel = new ErrorLabel(); + private final JLabel myNodeIcon = new JLabel(" ", SwingConstants.RIGHT); + private final JLabel myProjectIcon = new JLabel(" ", SwingConstants.LEFT); - protected JComponent createItemComponent() { - myTextLabel = new ErrorLabel(); - return myTextLabel; - } - - @Override - protected void layout() { - myNodeIcon = new JLabel(" ", SwingConstants.RIGHT); - myProjectIcon = new JLabel(" ", SwingConstants.LEFT); - myNodeIcon.setOpaque(false); - myTextLabel.setOpaque(false); - myProjectIcon.setOpaque(false); - myRendererComponent.add(BorderLayout.CENTER, myComponent); - myRendererComponent.add(BorderLayout.WEST, myNodeIcon); - myRendererComponent.add(BorderLayout.EAST, myProjectIcon); + public MyRenderer() { + super(new BorderLayout()); + myNodeIcon.setName(NODE_ICON); + add(BorderLayout.CENTER, myTextLabel); + add(BorderLayout.WEST, myNodeIcon); + add(BorderLayout.EAST, myProjectIcon); } public Component getTreeCellRendererComponent(JTree tree, @@ -487,7 +484,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd int row, boolean focused) { myTextLabel.setFont(UIUtil.getLabelFont()); - myRendererComponent.setBackground(selected ? UIUtil.getTreeSelectionBackground() : myTree.getBackground()); + setPreferredSize(null); MyNode node = extractNode(value); if (node == null) { @@ -499,28 +496,19 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd if (myRoot == node.getParent()) { myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD)); } - TreePath path = tree.getPathForRow(row); - if (path == null) { - if (value instanceof DefaultMutableTreeNode) { - path = new TreePath(((DefaultMutableTreeNode)value).getPath()); + if (tree.isVisible()) { + int indent = node.myLevel * (UIUtil.getTreeLeftChildIndent() + UIUtil.getTreeRightChildIndent()); + Insets treeInsets = tree.getInsets(); + if (treeInsets != null) { + indent += treeInsets.left + treeInsets.right; + } + int visibleWidth = tree.getVisibleRect().width; + if (visibleWidth > indent) { + Dimension size = getPreferredSize(); + size.width = visibleWidth - indent; + //setPreferredSize(size); } } - int forcedWidth = 2000; - if (path != null && tree.isVisible()) { - Rectangle visibleRect = tree.getVisibleRect(); - - int nestingLevel = tree.isRootVisible() ? path.getPathCount() - 1 : path.getPathCount() - 2; - - int left = UIUtil.getTreeLeftChildIndent(); - int right = UIUtil.getTreeRightChildIndent(); - - Insets treeInsets = tree.getInsets(); - - int indent = (left + right) * nestingLevel + (treeInsets != null ? treeInsets.left + treeInsets.right : 0); - - forcedWidth = visibleRect.width > 0 ? visibleRect.width - indent : forcedWidth; - } - myRendererComponent.setPrefereedWidth(forcedWidth - 4); } // update font color for modified configurables myTextLabel.setForeground(selected ? UIUtil.getTreeSelectionForeground() : NORMAL_NODE); @@ -569,25 +557,20 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd myProjectIcon.setVisible(false); } // configure node icon - if (value instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value; - TreePath treePath = new TreePath(treeNode.getPath()); - myNodeIcon.setIcon(myTree.getHandleIcon(treeNode, treePath)); + Icon nodeIcon = null; + if (node != null) { + if (0 == node.getChildCount()) { + nodeIcon = myTree.getEmptyHandle(); + } + else if (value instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value; + nodeIcon = myTree.isExpanded(new TreePath(treeNode.getPath())) + ? myTree.getExpandedHandle() + : myTree.getCollapsedHandle(); + } } - else { - myNodeIcon.setIcon(null); - } - return myRendererComponent; - } - - int getSeparatorHeight() { - return mySeparatorComponent.getParent() == null ? 0 : mySeparatorComponent.getPreferredSize().height; - } - - public boolean isUnderHandle(Point point) { - Point handlePoint = SwingUtilities.convertPoint(myRendererComponent, point, myNodeIcon); - Rectangle bounds = myNodeIcon.getBounds(); - return bounds.x < handlePoint.x && bounds.getMaxX() >= handlePoint.x; + myNodeIcon.setIcon(nodeIcon); + return this; } } @@ -621,11 +604,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd @Override public void setUI(TreeUI ui) { - TreeUI actualUI = ui; - if (!(ui instanceof MyTreeUi)) { - actualUI = new MyTreeUi(); - } - super.setUI(actualUI); + super.setUI(ui instanceof MyTreeUi ? ui : new MyTreeUi()); } @Override @@ -664,84 +643,92 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd } @Override - protected void processMouseEvent(MouseEvent e) { + protected void processMouseEvent(MouseEvent event) { MyTreeUi ui = (MyTreeUi)myTree.getUI(); - boolean toggleNow = MouseEvent.MOUSE_RELEASED == e.getID() - && UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED) - && !ui.isToggleEvent(e); + if (!ui.processMouseEvent(event)) { + super.processMouseEvent(event); + } + } + } - if (toggleNow || MouseEvent.MOUSE_PRESSED == e.getID()) { - TreePath path = getPathForLocation(e.getX(), e.getY()); - if (path != null) { - Rectangle bounds = getPathBounds(path); - if (bounds != null && path.getLastPathComponent() instanceof DefaultMutableTreeNode) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); - boolean selected = isPathSelected(path); - boolean expanded = isExpanded(path); - Component comp = - myRenderer.getTreeCellRendererComponent(this, node, selected, expanded, node.isLeaf(), getRowForPath(path), isFocusOwner()); + private static final class MyTreeUi extends WideSelectionTreeUI { + boolean processMouseEvent(MouseEvent event) { + if (super.tree instanceof SimpleTree) { + SimpleTree tree = (SimpleTree)super.tree; - comp.setBounds(bounds); - comp.validate(); + boolean toggleNow = MouseEvent.MOUSE_RELEASED == event.getID() + && UIUtil.isActionClick(event, MouseEvent.MOUSE_RELEASED) + && !isToggleEvent(event); - Point point = new Point(e.getX() - bounds.x, e.getY() - bounds.y); - if (myRenderer.isUnderHandle(point)) { - if (toggleNow) { - ui.toggleExpandState(path); - } - e.consume(); - return; + if (toggleNow || MouseEvent.MOUSE_PRESSED == event.getID()) { + Component component = tree.getDeepestRendererComponentAt(event.getX(), event.getY()); + if (component != null && NODE_ICON.equals(component.getName())) { + if (toggleNow) { + toggleExpandState(tree.getPathForLocation(event.getX(), event.getY())); } + event.consume(); + return true; } } } - - super.processMouseEvent(e); + return false; } - private final class MyTreeUi extends WideSelectionTreeUI { + @Override + protected boolean shouldPaintExpandControl(TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { + return false; + } - @Override - public void toggleExpandState(TreePath path) { - super.toggleExpandState(path); - } + @Override + protected void paintHorizontalPartOfLeg(Graphics g, + Rectangle clipBounds, + Insets insets, + Rectangle bounds, + TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { - @Override - public boolean isToggleEvent(MouseEvent event) { - return super.isToggleEvent(event); - } + } - @Override - protected boolean shouldPaintExpandControl(TreePath path, - int row, - boolean isExpanded, - boolean hasBeenExpanded, - boolean isLeaf) { - return false; - } + @Override + protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { + } - @Override - protected void paintHorizontalPartOfLeg(Graphics g, - Rectangle clipBounds, - Insets insets, - Rectangle bounds, - TreePath path, - int row, - boolean isExpanded, - boolean hasBeenExpanded, - boolean isLeaf) { + @Override + public void paint(Graphics g, JComponent c) { + GraphicsUtil.setupAntialiasing(g); + super.paint(g, c); + } - } - - @Override - protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) { - } - - @Override - public void paint(Graphics g, JComponent c) { - GraphicsUtil.setupAntialiasing(g); - super.paint(g, c); + @Override + protected void paintRow(Graphics g, + Rectangle clipBounds, + Insets insets, + Rectangle bounds, + TreePath path, + int row, + boolean isExpanded, + boolean hasBeenExpanded, + boolean isLeaf) { + if (tree != null) { + int width = tree.getWidth(); + Container parent = tree.getParent(); + if (parent instanceof JViewport) { + JViewport viewport = (JViewport)parent; + width = viewport.getWidth() - viewport.getViewPosition().x; + } + width -= bounds.x; + if (bounds.width < width) { + bounds.width = width; + } } + super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); } } From deccaa0e15120728306baffc87bbc205a59b6ff7 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 5 Sep 2014 14:55:52 +0400 Subject: [PATCH 38/69] fixed build info into PyCharm Edu builds. --- python/edu/build/pycharm_edu_build.gant | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index b1fbedd83483..8765a69e55e0 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -158,7 +158,6 @@ public layoutEducational(String classesPath, Set usedJars) { usedJars = collectUsedJars(modules(), approvedJars(), ["/ant/"], null) } - def appInfo = appInfoFile() def paths = new Paths(home) buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], { projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_edu"), false).each { @@ -166,6 +165,7 @@ public layoutEducational(String classesPath, Set usedJars) { } }, "-Didea.platform.prefix=PyCharmEdu -Didea.no.jre.check=true") + def appInfo = appInfoFile() if (!dryRun) { wireBuildDate("PE-${buildNumber}", appInfo) } @@ -223,7 +223,7 @@ private layoutPlugins(layouts) { } private String appInfoFile() { - return "$pythonEduHome/resources/idea/PyCharmEduApplicationInfo.xml" + return "$pythonEduHome/out/pycharm/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml" } private layoutFull(Map args, String target, Set usedJars) { From 04c7d54273e7bdc2e577c77a2ee0396881433b13 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 5 Sep 2014 15:04:25 +0400 Subject: [PATCH 39/69] Fixed IAE in RunContentBuilder.showRunContent --- .../src/com/intellij/execution/runners/RunContentBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java index 2b0f800a5088..792ad6803d8c 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java @@ -222,7 +222,9 @@ public class RunContentBuilder extends RunTab { public RunContentDescriptor showRunContent(@Nullable RunContentDescriptor reuseContent) { RunContentDescriptor descriptor = createDescriptor(); Disposer.register(descriptor, this); - Disposer.register(myProject, myRunContentDescriptor); + if (myRunContentDescriptor != null) { + Disposer.register(myProject, myRunContentDescriptor); + } myRunContentDescriptor = descriptor; RunContentManagerImpl.copyContentAndBehavior(descriptor, reuseContent); return descriptor; From c0aa25d9b20066ecb2bed811ecf2a7e8517dc27b Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 5 Sep 2014 15:10:31 +0400 Subject: [PATCH 40/69] underline link on mouse over only --- .../src/com/intellij/ui/HyperlinkLabel.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java b/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java index 6a99624a620b..1e81eb729e40 100644 --- a/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java +++ b/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java @@ -58,6 +58,7 @@ public class HyperlinkLabel extends HighlightableComponent { private HighlightedText myHighlightedText; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private boolean myUseIconAsLink; + private final Color myTextEffectColor; private final TextAttributes myAnchorAttributes; private HyperlinkListener myHyperlinkListener = null; @@ -79,8 +80,8 @@ public class HyperlinkLabel extends HighlightableComponent { } public HyperlinkLabel(String text, final Color textForegroundColor, final Color textBackgroundColor, final Color textEffectColor) { - myAnchorAttributes = - new TextAttributes(textForegroundColor, textBackgroundColor, textEffectColor, EffectType.LINE_UNDERSCORE, Font.PLAIN); + myTextEffectColor = textEffectColor; + myAnchorAttributes = new TextAttributes(textForegroundColor, textBackgroundColor, null, null, Font.PLAIN); enforceBackgroundOutsideText(textBackgroundColor); setHyperlinkText(text); enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); @@ -115,6 +116,7 @@ public class HyperlinkLabel extends HighlightableComponent { protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_EXITED) { setCursor(Cursor.getDefaultCursor()); + updateLinkUnderlining(e); } else if (UIUtil.isActionClick(e, MouseEvent.MOUSE_PRESSED) && isOnLink(e.getX())) { fireHyperlinkEvent(); @@ -126,10 +128,32 @@ public class HyperlinkLabel extends HighlightableComponent { protected void processMouseMotionEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_MOVED) { setCursor(isOnLink(e.getX()) ? Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : Cursor.getDefaultCursor()); + updateLinkUnderlining(e); } super.processMouseMotionEvent(e); } + private void updateLinkUnderlining(MouseEvent e) { + boolean wasUnderlined = myAnchorAttributes.getEffectType() == EffectType.LINE_UNDERSCORE; + if (e.getID() == MouseEvent.MOUSE_EXITED) { + if (wasUnderlined) { + myAnchorAttributes.setEffectColor(null); + myAnchorAttributes.setEffectType(null); + repaint(); + } + } + else if (e.getID() == MouseEvent.MOUSE_MOVED) { + if (!wasUnderlined) { + HighlightedRegion region = findRegionByX(e.getX()); + if (region != null && region.textAttributes == myAnchorAttributes) { + myAnchorAttributes.setEffectColor(myTextEffectColor); + myAnchorAttributes.setEffectType(EffectType.LINE_UNDERSCORE); + repaint(); + } + } + } + } + private boolean isOnLink(int x) { if (myUseIconAsLink && myIcon != null && x < myIcon.getIconWidth()) { return true; From 15c652ee7117d18a3a8aa736921d6c8c59ef3ec0 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:53:58 +0200 Subject: [PATCH 41/69] cleanup --- .../execution/junit2/ui/ConsolePanel.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java b/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java index 3fe67a6d5e1b..d4102d4df784 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java @@ -41,6 +41,7 @@ import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.Alarm; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; @@ -69,25 +70,30 @@ public class ConsolePanel extends TestResultsPanel { myPrinter = printer; } + @Override public void initUI() { super.initUI(); myStartingProgress = new StartingProgress(myTreeView); } + @Override protected JComponent createStatisticsPanel() { myStatisticsPanel = new StatisticsPanel(); return myStatisticsPanel; } + @Override protected ToolbarPanel createToolbarPanel() { return new JUnitToolbarPanel(myProperties, myEnvironment, this); } + @Override protected TestStatusLine createStatusLine() { myStatusLine = new JUnitStatusLine(); return myStatusLine; } + @Override protected JComponent createTestTreeView() { myTreeView = new JUnitTestTreeView(); return myTreeView; @@ -129,6 +135,7 @@ public class ConsolePanel extends TestResultsPanel { return myPrinter; } + @Override public void dispose() { stopStartingProgress(); myPrinter = null; @@ -145,8 +152,10 @@ public class ConsolePanel extends TestResultsPanel { private ProcessHandler myProcess; private long myStartedAt = System.currentTimeMillis(); private final ProcessAdapter myProcessListener = new ProcessAdapter() { + @Override public void processTerminated(ProcessEvent event) { ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override public void run() { doStop(); } @@ -162,7 +171,9 @@ public class ConsolePanel extends TestResultsPanel { myTree.setPaintBusy(true); //myStartingLabel.setBackground(UIManager.getColor("Tree.background")); myTree.setCellRenderer(new TreeCellRenderer() { - public Component getTreeCellRendererComponent(final JTree tree, final Object value, + @NotNull + @Override + public Component getTreeCellRendererComponent(@NotNull final JTree tree, final Object value, final boolean selected, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { myStartingLabel.clear(); @@ -173,7 +184,8 @@ public class ConsolePanel extends TestResultsPanel { } }); myTree.addPropertyChangeListener(JTree.TREE_MODEL_PROPERTY, new PropertyChangeListener() { - public void propertyChange(final PropertyChangeEvent evt) { + @Override + public void propertyChange(@NotNull final PropertyChangeEvent evt) { myTree.removePropertyChangeListener(JTree.TREE_MODEL_PROPERTY, this); doStop(); } @@ -189,6 +201,7 @@ public class ConsolePanel extends TestResultsPanel { myProcess = null; } + @Override public void run() { myModel.nodeChanged(myRootNode); postRepaint(); From 517128c62efae59a346854616cfa89fa4c862d20 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 10:54:42 +0200 Subject: [PATCH 42/69] cleanup --- .../execution/testframework/ui/TestResultsPanel.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java index a7519429381d..1f4b93238f9c 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java @@ -75,6 +75,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { Disposer.register(this, myToolbarPanel); final Splitter splitter = createSplitter(mySplitterProportionProperty, mySplitterDefaultProportion); Disposer.register(this, new Disposable(){ + @Override public void dispose() { remove(splitter); splitter.dispose(); @@ -91,6 +92,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { rightPanel.add(SameHeightPanel.wrap(myStatusLine, myToolbarPanel), BorderLayout.NORTH); myStatisticsSplitter = createSplitter(myStatisticsSplitterProportionProperty, 0.5f); new AwtVisitor(myConsole) { + @Override public boolean visit(Component component) { if (component instanceof JScrollPane) { ((JScrollPane) component).putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.TOP | SideBorder.LEFT); @@ -104,6 +106,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { showStatistics(); } myProperties.addListener(TestConsoleProperties.SHOW_STATISTICS, new TestFrameworkPropertyListener() { + @Override public void onChanged(Boolean value) { if (value.booleanValue()) { showStatistics(); @@ -145,6 +148,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { return outputTab; } + @Override public void dispose() { } @@ -167,9 +171,9 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { } splitter.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(final PropertyChangeEvent evt) { - if (propertiesComponent == null) return; - if (evt.getPropertyName().equals(Splitter.PROP_PROPORTION)) { + @Override + public void propertyChange(@NotNull final PropertyChangeEvent event) { + if (event.getPropertyName().equals(Splitter.PROP_PROPORTION)) { propertiesComponent.setValue(proportionProperty, String.valueOf(splitter.getProportion())); } } From 658da7eaa86109bdc8c02e57a0eef6d69d48908b Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 11:08:07 +0200 Subject: [PATCH 43/69] cleanup --- .../debugger/ui/DebuggerSessionTab.java | 2 +- .../src/messages/ExecutionBundle.properties | 12 ++++----- .../execution/testframework/TestsUIUtil.java | 6 ++--- .../xdebugger/impl/ui/XDebugSessionTab.java | 5 ---- .../execution/junit2/ui/JUnitStatusLine.java | 27 +++++++++++-------- .../junit2/ui/JUnitTreeConsoleView.java | 3 +++ 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java index 87d2f73124df..547ac7f5ea3f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java @@ -200,7 +200,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos }); ExecutionResult executionResult = debuggerSession.getProcess().getExecutionResult(); - myConsole = executionResult.getExecutionConsole(); +// myConsole = executionResult.getExecutionConsole(); // myRunContentDescriptor = new RunContentDescriptor(myConsole, executionResult.getProcessHandler(), myUi.getComponent(), getSessionName(), // environment.getIcon()); initUI(executionResult); diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index a49bcced6f50..508ac2ad2801 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -135,10 +135,10 @@ junit.runing.info.errors.count.message=E:{0} junit.runing.info.passed.count.message=P:{0} junit.runing.info.ignored.count.message=I:{0} -junit.runing.info.status.completed.from.total.failed={0} of {1} Failed: {2} -junit.runing.info.status.completed.from.total={0} of {1} -junit.runing.info.status.running.number.with.name=Running: {0} {1} -junit.runing.info.failed.to.start.error.message=Failed to start +junit.running.info.status.completed.from.total.failed={0} of {1} Failed: {2} +junit.running.info.status.completed.from.total={0} of {1} +junit.running.info.status.running.number.with.name=Running: {0} {1} +junit.running.info.failed.to.start.error.message=Failed to start junit.runing.info.tests.failed.label=Tests Failed junit.runing.info.tests.passed.label=Tests Passed tests.passed.with.warnings.message=Tests passed (with warnings) @@ -277,8 +277,8 @@ environment.variables.helper.use.arguments.jdk13.label=For JDK 1.3.x environment.variables.helper.use.arguments.jdk14.label=For JDK 1.4.x select.run.configuration.for.item.action.name=Select ''{0}'' save.run.configuration.for.item.action.name=Save ''{0}'' -junit.runing.info.status.done.count=Done: {0} -junit.runing.info.status.terminated.count=Terminated: {0} +junit.running.info.status.done.count=Done: {0} +junit.running.info.status.terminated.count=Terminated: {0} junit.runing.info.tests.in.progress.done.tree.node=Tests in Progress: Done junit.runing.info.tests.in.progress.terminated.tre.node=Tests in Progress: Terminated delete.confirmation.dialog.title=Delete Confirmation diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java index 836635a58b0e..cbb0373f34c1 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java @@ -86,7 +86,7 @@ public class TestsUIUtil { } return false; } - + public static Navigatable getOpenFileDescriptor(final AbstractTestProxy testProxy, final TestFrameworkRunningModel model) { final TestConsoleProperties testConsoleProperties = model.getProperties(); return getOpenFileDescriptor(testProxy, testConsoleProperties, @@ -114,7 +114,7 @@ public class TestsUIUtil { public static void notifyByBalloon(@NotNull final Project project, boolean started, final AbstractTestProxy root, - final TestConsoleProperties properties, + final TestConsoleProperties properties, @Nullable final String comment) { if (project.isDisposed()) return; if (properties == null) return; @@ -231,7 +231,7 @@ public class TestsUIUtil { myType = MessageType.ERROR; } else if (notStartedCount > 0) { - myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.runing.info.failed.to.start.error.message") : "Tests Ignored"; + myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.running.info.failed.to.start.error.message") : "Tests Ignored"; myText = passedCount + " passed, " + notStartedCount + (!notStarted.isEmpty() ? " not started" : " ignored"); myType = notStarted.isEmpty() ? MessageType.WARNING : MessageType.ERROR; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index 8dc06a1b24ec..a2dbd21073f6 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -20,7 +20,6 @@ import com.intellij.execution.Executor; import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.RunContentBuilder; -import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.actions.CloseAction; @@ -193,10 +192,6 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { return framesContent; } - public ExecutionConsole getConsole() { - return myConsole; - } - public void rebuildViews() { AppUIUtil.invokeLaterIfProjectAlive(myProject, new Runnable() { @Override diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java index 88a474cd31ab..c7aef3a9a378 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java @@ -17,7 +17,7 @@ package com.intellij.execution.junit2.ui; import com.intellij.execution.ExecutionBundle; -import com.intellij.execution.junit2.*; +import com.intellij.execution.junit2.TestProxy; import com.intellij.execution.junit2.events.NewChildEvent; import com.intellij.execution.junit2.events.StateChangedEvent; import com.intellij.execution.junit2.events.TestEvent; @@ -47,15 +47,17 @@ class JUnitStatusLine extends TestStatusLine { public void onProcessStarted(final ProcessHandler process) { if (myTestsBuilt) return; process.addProcessListener(new ProcessAdapter() { + @Override public void processTerminated(ProcessEvent event) { process.removeProcessListener(this); ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override public void run() { myStateInfo.setTerminated(myState); if (!myTestsBuilt && myProgressBar.getFraction() == 0.0) { myProgressBar.setColor(ColorProgressBar.RED); myProgressBar.setFraction(1.0); - myState.setText(ExecutionBundle.message("junit.runing.info.failed.to.start.error.message")); + myState.setText(ExecutionBundle.message("junit.running.info.failed.to.start.error.message")); } } }); @@ -83,21 +85,21 @@ class JUnitStatusLine extends TestStatusLine { myCurrentTestName = currentTest == null ? "" : Formatters.printTest(currentTest); } - public double getComplitedPercents() { + public double getCompletedPercents() { return (double)myCompleted/(double)myTotal; } public void updateLabel(final JLabel label) { - final StringBuffer buffer = new StringBuffer(); + final StringBuilder buffer = new StringBuilder(); if (myDoneEvent != null && myTerminated) { String termMessage = generateTermMessage(getTestCount(0)); buffer.append(termMessage); final String comment = myDoneEvent.getComment(); if (comment.length() > 0) { - buffer.append(" (" + comment + ")"); + buffer.append(" (").append(comment).append(")"); } } else { - buffer.append(ExecutionBundle.message("junit.runing.info.status.running.number.with.name", getTestCount(myDoneEvent != null ? 0 : 1), myCurrentTestName)); + buffer.append(ExecutionBundle.message("junit.running.info.status.running.number.with.name", getTestCount(myDoneEvent != null ? 0 : 1), myCurrentTestName)); } label.setText(buffer.toString()); } @@ -105,16 +107,16 @@ class JUnitStatusLine extends TestStatusLine { private String getTestCount(int offset) { String testCount; if (myDefects > 0) - testCount = ExecutionBundle.message("junit.runing.info.status.completed.from.total.failed", myCompleted + offset, myTotal, myDefects); // += " Failed: " + myDefects + " "; + testCount = ExecutionBundle.message("junit.running.info.status.completed.from.total.failed", myCompleted + offset, myTotal, myDefects); // += " Failed: " + myDefects + " "; else - testCount = ExecutionBundle.message("junit.runing.info.status.completed.from.total", myCompleted + offset, myTotal); // myCompleted + " of " + myTotal + testCount = ExecutionBundle.message("junit.running.info.status.completed.from.total", myCompleted + offset, myTotal); // myCompleted + " of " + myTotal return testCount; } private String generateTermMessage(final String testCount) { switch(myDoneEvent.getType()) { - case DONE: return ExecutionBundle.message("junit.runing.info.status.done.count", testCount); - default: return ExecutionBundle.message("junit.runing.info.status.terminated.count", testCount); + case DONE: return ExecutionBundle.message("junit.running.info.status.done.count", testCount); + default: return ExecutionBundle.message("junit.running.info.status.terminated.count", testCount); } } @@ -131,6 +133,7 @@ class JUnitStatusLine extends TestStatusLine { myProgress = progress; } + @Override public void onRunnerStateChanged(final StateEvent event) { if (!event.isRunning()) { final CompletionEvent completionEvent = (CompletionEvent) event; @@ -143,18 +146,20 @@ class JUnitStatusLine extends TestStatusLine { } } + @Override public void onTestChanged(final TestEvent event) { if (event instanceof StateChangedEvent || event instanceof NewChildEvent) updateCounters(); } + @Override public void doDispose() { myProgress = null; } private void updateCounters() { myStateInfo.updateCounters(myProgress); - myProgressBar.setFraction(myStateInfo.getComplitedPercents()); + myProgressBar.setFraction(myStateInfo.getCompletedPercents()); if (myProgress.hasDefects()) { myProgressBar.setColor(ColorProgressBar.RED); } diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java index b311002027b1..4b879594d262 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java @@ -41,17 +41,20 @@ public class JUnitTreeConsoleView extends BaseTestsOutputConsoleView { myEnvironment = environment; } + @Override protected TestResultsPanel createTestResultsPanel() { myConsolePanel = new ConsolePanel(getConsole().getComponent(), getPrinter(), myProperties, myEnvironment, getConsole().createConsoleActions()); return myConsolePanel; } + @Override public void attachToProcess(final ProcessHandler processHandler) { super.attachToProcess(processHandler); myConsolePanel.onProcessStarted(processHandler); } + @Override public void dispose() { super.dispose(); myConsolePanel = null; From f880ab87c0df0c0c47515e7901d27b32ef875738 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 11:42:57 +0200 Subject: [PATCH 44/69] we can pass nullable process handler to addLogConsoles, so, don't be so strict (currently, doesn't matter because all clients call this method when process handler is not null) --- .../src/com/intellij/execution/runners/RunTab.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java index e2263adb1f55..6628c78f1851 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java @@ -114,13 +114,15 @@ public abstract class RunTab implements DataProvider, Disposable { protected final void initLogConsoles(@NotNull RunProfile runConfiguration, @NotNull RunContentDescriptor contentDescriptor, @Nullable ExecutionConsole console) { ProcessHandler processHandler = contentDescriptor.getProcessHandler(); - if (runConfiguration instanceof RunConfigurationBase && processHandler != null) { + if (runConfiguration instanceof RunConfigurationBase) { RunConfigurationBase configuration = (RunConfigurationBase)runConfiguration; if (myManager == null) { myManager = new LogFilesManager(getLogConsoleManager()); } myManager.addLogConsoles(configuration, processHandler); - OutputFileUtil.attachDumpListener(configuration, processHandler, console); + if (processHandler != null) { + OutputFileUtil.attachDumpListener(configuration, processHandler, console); + } } } } From 6b97b8d5b0d1e0468036e71f45aebcd5d2e8c425 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 11:45:45 +0200 Subject: [PATCH 45/69] cleanup --- .../impl/src/com/intellij/debugger/impl/DebuggerSession.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index 4ffe870eca0a..9b3124bc9caa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -251,7 +251,7 @@ public class DebuggerSession implements AbstractDebuggerSession { case STATE_DISPOSED: return DebuggerBundle.message("status.debug.stopped"); } - return myState.myDescription; + return null; } /* Stepping */ @@ -646,7 +646,7 @@ public class DebuggerSession implements AbstractDebuggerSession { public void threadStopped(DebugProcess proc, ThreadReference thread) { notifyThreadsRefresh(); } - + private void notifyThreadsRefresh() { if (!myUpdateAlarm.isDisposed()) { myUpdateAlarm.cancelAllRequests(); From 35816cf6b274d92101c05ce7c2e25e99a0c0c4ca Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 11:52:02 +0200 Subject: [PATCH 46/69] cleanup --- .../debugger/engine/DebugProcessEvents.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java index 4714ca49bd06..7640a959597e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java @@ -29,7 +29,6 @@ import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.DebuggerPanelsManager; import com.intellij.debugger.ui.breakpoints.Breakpoint; -import com.intellij.debugger.ui.breakpoints.BreakpointManager; import com.intellij.debugger.ui.breakpoints.LineBreakpoint; import com.intellij.execution.configurations.RemoteConnection; import com.intellij.openapi.application.ApplicationManager; @@ -57,15 +56,15 @@ import com.sun.jdi.request.ThreadStartRequest; * @author lex */ public class DebugProcessEvents extends DebugProcessImpl { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessEvents"); + private static final Logger LOG = Logger.getInstance(DebugProcessEvents.class); + private DebuggerEventThread myEventThread; - private final BreakpointManager myBreakpointManager; public DebugProcessEvents(Project project) { super(project); - myBreakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager(); } + @Override protected void commitVM(final VirtualMachine vm) { super.commitVM(vm); if(vm != null) { @@ -134,18 +133,19 @@ public class DebugProcessEvents extends DebugProcessImpl { return myIsStopped; } + @Override public void run() { try { EventQueue eventQueue = myVmProxy.eventQueue(); while (!isStopped()) { try { final EventSet eventSet = eventQueue.remove(); - + final boolean methodWatcherActive = myReturnValueWatcher != null && myReturnValueWatcher.isEnabled(); int processed = 0; for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) { final Event event = eventIterator.nextEvent(); - + if (methodWatcherActive) { if (event instanceof MethodExitEvent) { if (myReturnValueWatcher.processMethodExitEvent((MethodExitEvent)event)) { @@ -158,6 +158,7 @@ public class DebugProcessEvents extends DebugProcessImpl { processed++; final ThreadReference thread = ((ThreadStartEvent)event).thread(); getManagerThread().schedule(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { getVirtualMachineProxy().threadStarted(thread); myDebugProcessDispatcher.getMulticaster().threadStarted(DebugProcessEvents.this, thread); @@ -168,6 +169,7 @@ public class DebugProcessEvents extends DebugProcessImpl { processed++; final ThreadReference thread = ((ThreadDeathEvent)event).thread(); getManagerThread().schedule(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { getVirtualMachineProxy().threadStopped(thread); myDebugProcessDispatcher.getMulticaster().threadStopped(DebugProcessEvents.this, thread); @@ -175,15 +177,15 @@ public class DebugProcessEvents extends DebugProcessImpl { }); } } - + if (processed == eventSet.size()) { eventSet.resume(); continue; } getManagerThread().invokeAndWait(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { - if (eventSet.suspendPolicy() == EventRequest.SUSPEND_ALL && !DebuggerSession.enableBreakpointsDuringEvaluation()) { // check if there is already one request with policy SUSPEND_ALL for (SuspendContextImpl context : getSuspendManager().getEventContexts()) { @@ -193,12 +195,10 @@ public class DebugProcessEvents extends DebugProcessImpl { } } } - + final SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(eventSet); - for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) { final Event event = eventIterator.nextEvent(); - //if (LOG.isDebugEnabled()) { // LOG.debug("EVENT : " + event); //} @@ -207,10 +207,7 @@ public class DebugProcessEvents extends DebugProcessImpl { //Sun WTK fails when J2ME when event set is resumed on VMStartEvent processVMStartEvent(suspendContext, (VMStartEvent)event); } - else if (event instanceof VMDeathEvent) { - processVMDeathEvent(suspendContext, event); - } - else if (event instanceof VMDisconnectEvent) { + else if (event instanceof VMDeathEvent || event instanceof VMDisconnectEvent) { processVMDeathEvent(suspendContext, event); } else if (event instanceof ClassPrepareEvent) { @@ -240,7 +237,6 @@ public class DebugProcessEvents extends DebugProcessImpl { } } }); - } catch (InternalException e) { LOG.debug(e); @@ -264,13 +260,15 @@ public class DebugProcessEvents extends DebugProcessImpl { } catch (VMDisconnectedException e) { invokeVMDeathEvent(); - } finally { + } + finally { Thread.interrupted(); // reset interrupted status } } private void invokeVMDeathEvent() { getManagerThread().invokeAndWait(new DebuggerCommandImpl() { + @Override protected void action() throws Exception { SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(EventRequest.SUSPEND_NONE, 1); processVMDeathEvent(suspendContext, null); @@ -307,7 +305,7 @@ public class DebugProcessEvents extends DebugProcessImpl { if(myState.compareAndSet(STATE_INITIAL, STATE_ATTACHED)) { final VirtualMachineProxyImpl machineProxy = getVirtualMachineProxy(); final EventRequestManager requestManager = machineProxy.eventRequestManager(); - + if (machineProxy.canGetMethodReturnValues()) { myReturnValueWatcher = new MethodReturnValueWatcher(requestManager); } @@ -378,7 +376,7 @@ public class DebugProcessEvents extends DebugProcessImpl { RequestHint hint = (RequestHint)event.request().getProperty("hint"); deleteStepRequests(event.thread()); - + boolean shouldResume = false; final Project project = getProject(); @@ -426,8 +424,9 @@ public class DebugProcessEvents extends DebugProcessImpl { preprocessEvent(suspendContext, thread); //we use schedule to allow processing other events during processing this one - //this is especially nesessary if a method is breakpoint condition + //this is especially necessary if a method is breakpoint condition getManagerThread().schedule(new SuspendContextCommandImpl(suspendContext) { + @Override public void contextAction() throws Exception { final SuspendManager suspendManager = getSuspendManager(); SuspendContextImpl evaluatingContext = SuspendManagerUtil.getEvaluatingContext(suspendManager, getSuspendContext().getThread()); @@ -441,7 +440,7 @@ public class DebugProcessEvents extends DebugProcessImpl { final LocatableEventRequestor requestor = (LocatableEventRequestor) getRequestsManager().findRequestor(event.request()); boolean resumePreferred = requestor != null && DebuggerSettings.SUSPEND_NONE.equals(requestor.getSuspendPolicy()); - boolean requestHit = false; + boolean requestHit; try { requestHit = (requestor != null) && requestor.processLocatableEvent(this, event); } @@ -451,6 +450,7 @@ public class DebugProcessEvents extends DebugProcessImpl { } final boolean[] considerRequestHit = new boolean[]{true}; DebuggerInvocationUtil.invokeAndWait(getProject(), new Runnable() { + @Override public void run() { DebuggerPanelsManager.getInstance(getProject()).toFront(mySession); final String displayName = requestor instanceof Breakpoint? ((Breakpoint)requestor).getDisplayName() : requestor.getClass().getSimpleName(); From 915afcd85e39fb5ca85221eecd56b56df062720d Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 13:23:47 +0200 Subject: [PATCH 47/69] fix typo --- .../com/intellij/execution/runners/RunContentBuilder.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java index 792ad6803d8c..77a3aa6b920a 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java @@ -222,11 +222,9 @@ public class RunContentBuilder extends RunTab { public RunContentDescriptor showRunContent(@Nullable RunContentDescriptor reuseContent) { RunContentDescriptor descriptor = createDescriptor(); Disposer.register(descriptor, this); - if (myRunContentDescriptor != null) { - Disposer.register(myProject, myRunContentDescriptor); - } - myRunContentDescriptor = descriptor; + Disposer.register(myProject, descriptor); RunContentManagerImpl.copyContentAndBehavior(descriptor, reuseContent); + myRunContentDescriptor = descriptor; return descriptor; } From 3b7cfeee72b3cbe05f0c4252885661c544a3c1fb Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Fri, 5 Sep 2014 15:34:00 +0400 Subject: [PATCH 48/69] style: rename and delete unnecessary methods --- .../com/intellij/dvcs/push/PushSupport.java | 2 +- ...TargetEditor.java => PushTargetPanel.java} | 13 ++--- .../intellij/dvcs/push/PushController.java | 9 ++-- .../com/intellij/dvcs/push/ui/PushLog.java | 4 +- .../intellij/dvcs/push/ui/RepositoryNode.java | 8 ++-- .../push/ui/RepositoryWithBranchPanel.java | 26 +++++----- .../dvcs/push/ui/SingleRepositoryNode.java | 8 ++-- .../dvcs/push/ui/VcsBranchEditorListener.java | 4 +- .../org/zmlx/hg4idea/push/HgPushSupport.java | 4 +- ...rgetEditor.java => HgPushTargetPanel.java} | 47 +++++++++---------- 10 files changed, 57 insertions(+), 68 deletions(-) rename platform/dvcs-api/src/com/intellij/dvcs/push/{TargetEditor.java => PushTargetPanel.java} (79%) rename plugins/hg4idea/src/org/zmlx/hg4idea/push/{HgTargetEditor.java => HgPushTargetPanel.java} (70%) diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java index d4939070038e..4d4a744eb2e7 100644 --- a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java +++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java @@ -64,5 +64,5 @@ public abstract class PushSupport createTargetEditor(@NotNull Repo repository, @NotNull String defaultTargetName); + public abstract PushTargetPanel createTargetPanel(@NotNull Repo repository, @NotNull String defaultTargetName); } diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/TargetEditor.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java similarity index 79% rename from platform/dvcs-api/src/com/intellij/dvcs/push/TargetEditor.java rename to platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java index 0dfda391f401..ede2f17410ee 100644 --- a/platform/dvcs-api/src/com/intellij/dvcs/push/TargetEditor.java +++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java @@ -15,18 +15,14 @@ */ package com.intellij.dvcs.push; +import com.intellij.openapi.ui.ValidationInfo; import com.intellij.ui.ColoredTreeCellRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.*; -public abstract class TargetEditor extends JPanel { - - protected TargetEditor(BorderLayout layout) { - super(layout); - } +public abstract class PushTargetPanel extends JPanel { abstract public void render(@NotNull ColoredTreeCellRenderer renderer); @@ -38,8 +34,5 @@ public abstract class TargetEditor extends JPanel { public abstract void fireOnChange(); @Nullable - public abstract VcsError verify(); - - @NotNull - public abstract JComponent getVerifiedComponent(); + public abstract ValidationInfo verify(); } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java index e809bcabb354..fcca4a5f0e24 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -162,15 +162,16 @@ public class PushController implements Disposable { if (target == null) { model.setError(VcsError.createEmptyTargetError(repoName)); } - final TargetEditor targetEditor = support.createTargetEditor(repository, target == null ? "" : target.getPresentation()); + final PushTargetPanel pushTargetPanel = support.createTargetPanel(repository, target == null ? "" : target.getPresentation()); RepositoryWithBranchPanel repoPanel = - new RepositoryWithBranchPanel(repoName, support.getSource(repository).getPresentation(), targetEditor); + new RepositoryWithBranchPanel(repoName, support.getSource(repository).getPresentation(), pushTargetPanel); repoPanel.setInputVerifier(new InputVerifier() { @Override public boolean verify(JComponent input) { - VcsError error = targetEditor.verify(); + ValidationInfo error = pushTargetPanel.verify(); if (error != null) { - PopupUtil.showBalloonForComponent(targetEditor.getVerifiedComponent(), error.getText(), MessageType.WARNING, false, myProject); + //noinspection ConstantConditions + PopupUtil.showBalloonForComponent(error.component, error.message, MessageType.WARNING, false, myProject); } return error == null; } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index ed694c3c0b87..ff1779c4b1c2 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -15,7 +15,7 @@ */ package com.intellij.dvcs.push.ui; -import com.intellij.dvcs.push.TargetEditor; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.openapi.actionSystem.CommonShortcuts; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.actionSystem.DataSink; @@ -254,7 +254,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { Object tag = me.getClickCount() >= clickCountToStart ? PushLogTreeUtil.getTagAtForRenderer(myTreeCellRenderer, me) : null; - return tag instanceof TargetEditor; + return tag instanceof PushTargetPanel; } //if keyboard event - then anEvent will be null =( See BasicTreeUi TreePath treePath = myTree.getAnchorSelectionPath(); diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java index 605d3a2be071..1ee4e2e9c695 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java @@ -15,7 +15,7 @@ */ package com.intellij.dvcs.push.ui; -import com.intellij.dvcs.push.TargetEditor; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.ui.CheckedTreeNode; @@ -47,9 +47,9 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, renderer.appendFixedTextFragmentWidth(120); renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - TargetEditor targetEditor = myRepositoryPanel.getTargetEditor(); - targetEditor.render(renderer); - Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(targetEditor); + PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel(); + pushTargetPanel.render(renderer); + Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(pushTargetPanel); renderer.setBorder(new EmptyBorder(insets)); } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java index 8b7fb9e30ecb..29a32237ca3a 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java @@ -16,8 +16,8 @@ package com.intellij.dvcs.push.ui; import com.intellij.dvcs.push.PushTarget; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.dvcs.push.RepositoryNodeListener; -import com.intellij.dvcs.push.TargetEditor; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.components.JBCheckBox; @@ -36,7 +36,7 @@ import java.util.List; public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCellRenderer { private final JBCheckBox myRepositoryCheckbox; - private final TargetEditor myDestTargetEditorComponent; + private final PushTargetPanel myDestPushTargetPanelComponent; private final JBLabel myLocalBranch; private final JLabel myArrowLabel; private final JLabel myRepositoryLabel; @@ -44,7 +44,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePa @NotNull private final List> myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); public RepositoryWithBranchPanel(@NotNull String repoName, - @NotNull String sourceName, @NotNull TargetEditor destTargetEditorComponent) { + @NotNull String sourceName, @NotNull PushTargetPanel destPushTargetPanelComponent) { super(); setLayout(new BorderLayout()); myRepositoryCheckbox = new JBCheckBox(); @@ -59,7 +59,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePa myRepositoryLabel = new JLabel(repoName); myLocalBranch = new JBLabel(sourceName); myArrowLabel = new JLabel(" -> "); - myDestTargetEditorComponent = destTargetEditorComponent; + myDestPushTargetPanelComponent = destPushTargetPanelComponent; myTextRenderer = new ColoredTreeCellRenderer() { public void customizeCellRenderer(@NotNull JTree tree, Object value, @@ -79,7 +79,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePa add(myRepositoryCheckbox, BorderLayout.WEST); JPanel panel = new NonOpaquePanel(new BorderLayout()); panel.add(myTextRenderer, BorderLayout.WEST); - panel.add(myDestTargetEditorComponent, BorderLayout.CENTER); + panel.add(myDestPushTargetPanelComponent, BorderLayout.CENTER); add(panel, BorderLayout.CENTER); } @@ -123,8 +123,8 @@ public class RepositoryWithBranchPanel extends NonOpaquePa if (bounds != null) { setPreferredSize(new Dimension(tree.getWidth() - bounds.x, bounds.height)); } - myDestTargetEditorComponent.grabFocus(); - myDestTargetEditorComponent.requestFocus(); + myDestPushTargetPanelComponent.grabFocus(); + myDestPushTargetPanelComponent.requestFocus(); revalidate(); return this; } @@ -134,9 +134,9 @@ public class RepositoryWithBranchPanel extends NonOpaquePa } public void fireOnChange() { - myDestTargetEditorComponent.fireOnChange(); + myDestPushTargetPanelComponent.fireOnChange(); for (RepositoryNodeListener listener : myListeners) { - listener.onTargetChanged(myDestTargetEditorComponent.getValue()); + listener.onTargetChanged(myDestPushTargetPanelComponent.getValue()); } } @@ -147,15 +147,15 @@ public class RepositoryWithBranchPanel extends NonOpaquePa } public void fireOnCancel() { - myDestTargetEditorComponent.fireOnCancel(); + myDestPushTargetPanelComponent.fireOnCancel(); } - public TargetEditor getTargetEditor() { - return myDestTargetEditorComponent; + public PushTargetPanel getTargetPanel() { + return myDestPushTargetPanelComponent; } public T getEditableValue() { - return myDestTargetEditorComponent.getValue(); + return myDestPushTargetPanelComponent.getValue(); } } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java index 3642e7a04b51..8506e1d50fea 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java @@ -15,7 +15,7 @@ */ package com.intellij.dvcs.push.ui; -import com.intellij.dvcs.push.TargetEditor; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import org.jetbrains.annotations.NotNull; @@ -42,9 +42,9 @@ public class SingleRepositoryNode extends RepositoryNode { public void render(@NotNull ColoredTreeCellRenderer renderer) { renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - TargetEditor targetEditor = myRepositoryPanel.getTargetEditor(); - targetEditor.render(renderer); - Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(targetEditor); + PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel(); + pushTargetPanel.render(renderer); + Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(pushTargetPanel); renderer.setBorder(new EmptyBorder(insets)); } } diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java index 15c2b8ad66d3..0b3df11db78a 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java @@ -15,7 +15,7 @@ */ package com.intellij.dvcs.push.ui; -import com.intellij.dvcs.push.TargetEditor; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase; import com.intellij.ui.CheckboxTree; import org.jetbrains.annotations.NotNull; @@ -35,7 +35,7 @@ public class VcsBranchEditorListener extends LinkMouseListenerBase { public void mouseMoved(MouseEvent e) { Component component = (Component)e.getSource(); Object tag = getTagAt(e); - if (tag != null && tag instanceof TargetEditor) { + if (tag != null && tag instanceof PushTargetPanel) { component.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); } else if (tag != null && tag instanceof TextWithLinkNode) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java index b28703930b6f..02ea9e941839 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java @@ -81,7 +81,7 @@ public class HgPushSupport extends PushSupport createTargetEditor(@NotNull HgRepository repository, @NotNull String defaultTargetName) { - return new HgTargetEditor(repository, defaultTargetName); + public PushTargetPanel createTargetPanel(@NotNull HgRepository repository, @NotNull String defaultTargetName) { + return new HgPushTargetPanel(repository, defaultTargetName); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTargetEditor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java similarity index 70% rename from plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTargetEditor.java rename to plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java index 6e86c054e7d9..964f069486f5 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTargetEditor.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java @@ -16,9 +16,10 @@ package org.zmlx.hg4idea.push; import com.intellij.dvcs.DvcsUtil; -import com.intellij.dvcs.push.TargetEditor; +import com.intellij.dvcs.push.PushTargetPanel; import com.intellij.dvcs.push.VcsError; import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; @@ -31,21 +32,20 @@ import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.util.HgUtil; -import javax.swing.*; import java.awt.*; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.util.List; -public class HgTargetEditor extends TargetEditor { +public class HgPushTargetPanel extends PushTargetPanel { private final static String ENTER_REMOTE = "Enter Remote"; private final HgRepository myRepository; - private final TextFieldWithAutoCompletion myDestTargetEditorComponent; + private final TextFieldWithAutoCompletion myDestTargetPanel; private String myOldText; - public HgTargetEditor(@NotNull HgRepository repository, @NotNull String defaultTargetName) { - super(new BorderLayout()); + public HgPushTargetPanel(@NotNull HgRepository repository, @NotNull String defaultTargetName) { + setLayout(new BorderLayout()); setOpaque(false); myRepository = repository; final List targetVariants = HgUtil.getTargetNames(repository); @@ -56,7 +56,7 @@ public class HgTargetEditor extends TargetEditor { return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2)); } }; - myDestTargetEditorComponent = new TextFieldWithAutoCompletion(repository.getProject(), provider, true, defaultTargetName) { + myDestTargetPanel = new TextFieldWithAutoCompletion(repository.getProject(), provider, true, defaultTargetName) { @Override public boolean shouldHaveBorder() { @@ -68,21 +68,21 @@ public class HgTargetEditor extends TargetEditor { } }; myOldText = defaultTargetName; - myDestTargetEditorComponent.setBorder(UIUtil.getTableFocusCellHighlightBorder()); - myDestTargetEditorComponent.setOneLineMode(true); + myDestTargetPanel.setBorder(UIUtil.getTableFocusCellHighlightBorder()); + myDestTargetPanel.setOneLineMode(true); FocusAdapter focusListener = new FocusAdapter() { @Override public void focusGained(FocusEvent e) { - myDestTargetEditorComponent.selectAll(); + myDestTargetPanel.selectAll(); } }; - myDestTargetEditorComponent.addFocusListener(focusListener); - add(myDestTargetEditorComponent, BorderLayout.CENTER); + myDestTargetPanel.addFocusListener(focusListener); + add(myDestTargetPanel, BorderLayout.CENTER); } @Override public void render(@NotNull ColoredTreeCellRenderer renderer) { - String targetText = myDestTargetEditorComponent.getText(); + String targetText = myDestTargetPanel.getText(); if (StringUtil.isEmptyOrSpaces(targetText)) { renderer.append(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES, this); } @@ -97,29 +97,24 @@ public class HgTargetEditor extends TargetEditor { @NotNull private HgTarget createValidPushTarget() { - return new HgTarget(myDestTargetEditorComponent.getText()); + return new HgTarget(myDestTargetPanel.getText()); } @Override public void fireOnCancel() { - myDestTargetEditorComponent.setText(myOldText); + myDestTargetPanel.setText(myOldText); } @Override public void fireOnChange() { - myOldText = myDestTargetEditorComponent.getText(); + myOldText = myDestTargetPanel.getText(); } @Nullable - public VcsError verify() { - return StringUtil.isEmptyOrSpaces(myDestTargetEditorComponent.getText()) - ? VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(myRepository)) - : null; - } - - @NotNull - @Override - public JComponent getVerifiedComponent() { - return myDestTargetEditorComponent; + public ValidationInfo verify() { + if (StringUtil.isEmptyOrSpaces(myDestTargetPanel.getText())) { + return new ValidationInfo(VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(myRepository)).getText(), this); + } + return null; } } From 778be49e87ba195a194f5171000a58aa51c00ad2 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 5 Sep 2014 16:04:34 +0400 Subject: [PATCH 49/69] fixed build info into PyCharm Edu builds. --- python/edu/build/pycharm_edu_build.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index 8765a69e55e0..8d4acf6b869a 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -223,7 +223,7 @@ private layoutPlugins(layouts) { } private String appInfoFile() { - return "$pythonEduHome/out/pycharm/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml" + return "$home/out/pycharm/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml" } private layoutFull(Map args, String target, Set usedJars) { From a36f54f713380d150b6e1baa65d226957a790bcd Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 5 Sep 2014 16:09:04 +0400 Subject: [PATCH 50/69] fixed build info into PyCharm Edu builds. --- python/edu/build/pycharm_edu_build.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index 8d4acf6b869a..ae892226ba70 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -223,7 +223,7 @@ private layoutPlugins(layouts) { } private String appInfoFile() { - return "$home/out/pycharm/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml" + return "${paths.sandbox}/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml" } private layoutFull(Map args, String target, Set usedJars) { From bb632b404f74713de27207b7a3ae079bd270110c Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 5 Sep 2014 16:20:10 +0400 Subject: [PATCH 51/69] reverting "underline link on mouse over only" because it isn't suitable for desktop app --- .../src/com/intellij/ui/HyperlinkLabel.java | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java b/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java index 1e81eb729e40..6a99624a620b 100644 --- a/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java +++ b/platform/platform-api/src/com/intellij/ui/HyperlinkLabel.java @@ -58,7 +58,6 @@ public class HyperlinkLabel extends HighlightableComponent { private HighlightedText myHighlightedText; private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private boolean myUseIconAsLink; - private final Color myTextEffectColor; private final TextAttributes myAnchorAttributes; private HyperlinkListener myHyperlinkListener = null; @@ -80,8 +79,8 @@ public class HyperlinkLabel extends HighlightableComponent { } public HyperlinkLabel(String text, final Color textForegroundColor, final Color textBackgroundColor, final Color textEffectColor) { - myTextEffectColor = textEffectColor; - myAnchorAttributes = new TextAttributes(textForegroundColor, textBackgroundColor, null, null, Font.PLAIN); + myAnchorAttributes = + new TextAttributes(textForegroundColor, textBackgroundColor, textEffectColor, EffectType.LINE_UNDERSCORE, Font.PLAIN); enforceBackgroundOutsideText(textBackgroundColor); setHyperlinkText(text); enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); @@ -116,7 +115,6 @@ public class HyperlinkLabel extends HighlightableComponent { protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_EXITED) { setCursor(Cursor.getDefaultCursor()); - updateLinkUnderlining(e); } else if (UIUtil.isActionClick(e, MouseEvent.MOUSE_PRESSED) && isOnLink(e.getX())) { fireHyperlinkEvent(); @@ -128,32 +126,10 @@ public class HyperlinkLabel extends HighlightableComponent { protected void processMouseMotionEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_MOVED) { setCursor(isOnLink(e.getX()) ? Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) : Cursor.getDefaultCursor()); - updateLinkUnderlining(e); } super.processMouseMotionEvent(e); } - private void updateLinkUnderlining(MouseEvent e) { - boolean wasUnderlined = myAnchorAttributes.getEffectType() == EffectType.LINE_UNDERSCORE; - if (e.getID() == MouseEvent.MOUSE_EXITED) { - if (wasUnderlined) { - myAnchorAttributes.setEffectColor(null); - myAnchorAttributes.setEffectType(null); - repaint(); - } - } - else if (e.getID() == MouseEvent.MOUSE_MOVED) { - if (!wasUnderlined) { - HighlightedRegion region = findRegionByX(e.getX()); - if (region != null && region.textAttributes == myAnchorAttributes) { - myAnchorAttributes.setEffectColor(myTextEffectColor); - myAnchorAttributes.setEffectType(EffectType.LINE_UNDERSCORE); - repaint(); - } - } - } - } - private boolean isOnLink(int x) { if (myUseIconAsLink && myIcon != null && x < myIcon.getIconWidth()) { return true; From 44328e0c2c221a2d7f1a33bc711c9213fa4baf12 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 5 Sep 2014 16:22:51 +0400 Subject: [PATCH 52/69] [git] trim error message before cleaning it up --- plugins/git4idea/src/git4idea/GitUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index e96d52de8ea0..3f344482f5c6 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -1016,6 +1016,7 @@ public class GitUtil { @NotNull public static String cleanupErrorPrefixes(@NotNull String msg) { final String[] PREFIXES = { "fatal:", "error:" }; + msg = msg.trim(); for (String prefix : PREFIXES) { if (msg.startsWith(prefix)) { return msg.substring(prefix.length()).trim(); From eb308ebef9fb2072f0aefec44fc489a1de075167 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 5 Sep 2014 16:50:22 +0400 Subject: [PATCH 53/69] [git] cleanup: remove duplicating method --- .../git4idea/src/git4idea/reset/GitResetAction.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/git4idea/src/git4idea/reset/GitResetAction.java b/plugins/git4idea/src/git4idea/reset/GitResetAction.java index 749acd7e7c7c..97b5b4ffeae8 100644 --- a/plugins/git4idea/src/git4idea/reset/GitResetAction.java +++ b/plugins/git4idea/src/git4idea/reset/GitResetAction.java @@ -16,7 +16,6 @@ package git4idea.reset; import com.intellij.dvcs.ui.VcsLogOneCommitPerRepoAction; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; @@ -25,18 +24,19 @@ import com.intellij.util.ObjectUtils; import com.intellij.vcs.log.VcsFullCommitDetails; import git4idea.config.GitVcsSettings; import git4idea.repo.GitRepository; -import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; +import static git4idea.GitUtil.getRepositoryManager; + public class GitResetAction extends VcsLogOneCommitPerRepoAction { @Nullable @Override protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { - return getRepoManager(project).getRepositoryForRoot(root); + return getRepositoryManager(project).getRepositoryForRoot(root); } @Override @@ -57,9 +57,4 @@ public class GitResetAction extends VcsLogOneCommitPerRepoAction } } - @NotNull - private static GitRepositoryManager getRepoManager(@NotNull Project project) { - return ServiceManager.getService(project, GitRepositoryManager.class); - } - } From af7b430c81ca33e57b5af32a0cabab1e3054b7e4 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 5 Sep 2014 17:03:57 +0400 Subject: [PATCH 54/69] removed build code from build info. --- python/edu/build/pycharm_edu_build.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant index ae892226ba70..784c2fe7d90b 100644 --- a/python/edu/build/pycharm_edu_build.gant +++ b/python/edu/build/pycharm_edu_build.gant @@ -167,7 +167,7 @@ public layoutEducational(String classesPath, Set usedJars) { def appInfo = appInfoFile() if (!dryRun) { - wireBuildDate("PE-${buildNumber}", appInfo) + wireBuildDate(${buildNumber}, appInfo) } Map args = [ From 92426f9aaa26dd245eaae908888d5cc724b11c38 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 5 Sep 2014 17:42:45 +0400 Subject: [PATCH 55/69] IDEA-129314 Settings: make Scopes look a bit more ordered (use one-pixel in project structure only) --- .../openapi/ui/MasterDetailsComponent.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index a262ea0a3b85..547fa03e438d 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -131,7 +131,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom protected MasterDetailsComponent(MasterDetailsState state) { myState = state; - mySplitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false, .2f) : new JBSplitter(false, .2f); + mySplitter = isNewProjectSettings() ? new OnePixelSplitter(false, .2f) : new JBSplitter(false, .2f); mySplitter.setSplitterProportionKey("ProjectStructure.SecondLevelElements"); mySplitter.setHonorComponentsMinimumSize(true); @@ -139,6 +139,20 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom reInitWholePanelIfNeeded(); } + private boolean isNewProjectSettings() { + if (!Registry.is("ide.new.project.settings")) { + return false; + } + try { + // assume that only project structure dialog uses the following base class for details: + String name = "com.intellij.openapi.roots.ui.configuration.projectRoot.BaseStructureConfigurable"; + return Class.forName(name).isAssignableFrom(getClass()); + } + catch (ClassNotFoundException ignored) { + return false; + } + } + protected void reInitWholePanelIfNeeded() { if (!myToReInitWholePanel) return; @@ -170,7 +184,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom } }; - if (Registry.is("ide.new.project.settings")) { + if (isNewProjectSettings()) { ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree); DefaultActionGroup group = createToolbarActionGroup(); if (group != null) { @@ -281,7 +295,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom } private void initToolbar() { - if (Registry.is("ide.new.project.settings")) return; + if (isNewProjectSettings()) return; DefaultActionGroup group = createToolbarActionGroup(); if (group != null) { final JComponent component = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent(); From 732e24270179574929088bd3d4977e2d9d002938 Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Fri, 5 Sep 2014 17:50:01 +0400 Subject: [PATCH 56/69] EDU-142 update course after task/lesson/task file remove --- .../coursecreator/CCProjectComponent.java | 119 ++++++++++++++++-- .../plugins/coursecreator/format/Lesson.java | 4 + 2 files changed, 111 insertions(+), 12 deletions(-) diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java index 7cec23a9a7d2..d5e3085f0f07 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java @@ -13,14 +13,21 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileAdapter; +import com.intellij.openapi.vfs.VirtualFileEvent; +import com.intellij.openapi.vfs.VirtualFileManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.coursecreator.format.Course; +import org.jetbrains.plugins.coursecreator.format.Lesson; +import org.jetbrains.plugins.coursecreator.format.Task; +import org.jetbrains.plugins.coursecreator.format.TaskFile; import java.io.IOException; public class CCProjectComponent implements ProjectComponent { private static final Logger LOG = Logger.getInstance(CCProjectComponent.class.getName()); private final Project myProject; + private FileDeletedListener myListener; public CCProjectComponent(Project project) { myProject = project; @@ -41,7 +48,7 @@ public class CCProjectComponent implements ProjectComponent { StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { @Override public void run() { - Course course = CCProjectService.getInstance(myProject).getCourse(); + final Course course = CCProjectService.getInstance(myProject).getCourse(); if (course != null) { myProject.getMessageBus().connect(myProject).subscribe( FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { @@ -53,21 +60,22 @@ public class CCProjectComponent implements ProjectComponent { } if (CCProjectService.getInstance(myProject).isTaskFile(oldFile)) { FileEditorManager.getInstance(myProject).closeFile(oldFile); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - try { - oldFile.delete(myProject); - } - catch (IOException e) { - LOG.error(e); - } + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + try { + oldFile.delete(myProject); } - }); + catch (IOException e) { + LOG.error(e); + } + } + }); } } }); - + myListener = new FileDeletedListener(); + VirtualFileManager.getInstance().addVirtualFileListener(myListener); final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener(); EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject); VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles(); @@ -88,5 +96,92 @@ public class CCProjectComponent implements ProjectComponent { } public void projectClosed() { + VirtualFileManager.getInstance().removeVirtualFileListener(myListener); + } + + private class FileDeletedListener extends VirtualFileAdapter { + + @Override + public void fileDeleted(@NotNull VirtualFileEvent event) { + if (myProject.isDisposed() || !myProject.isOpen()) { + return; + } + Course course = CCProjectService.getInstance(myProject).getCourse(); + if (course == null) { + return; + } + VirtualFile removedFile = event.getFile(); + if (removedFile.getName().contains(".answer")) { + deleteTaskFile(course, removedFile); + } + if (removedFile.getName().contains("task")) { + deleteTask(course, removedFile); + } + if (removedFile.getName().contains("lesson")) { + deleteLesson(course, removedFile); + } + } + + private void deleteLesson(Course course, VirtualFile file) { + VirtualFile courseDir = file.getParent(); + if (!courseDir.getName().equals(myProject.getName())) { + return; + } + Lesson lesson = course.getLesson(file.getName()); + if (lesson != null) { + course.getLessons().remove(lesson); + course.getLessonsMap().remove(file.getName()); + } + } + + private void deleteTask(Course course, VirtualFile removedFile) { + VirtualFile lessonDir = removedFile.getParent(); + if (lessonDir == null || !lessonDir.getName().contains("lesson")) { + return; + } + VirtualFile courseDir = lessonDir.getParent(); + if (!courseDir.getName().equals(myProject.getName())) { + return; + } + Lesson lesson = course.getLesson(lessonDir.getName()); + if (lesson == null) { + return; + } + Task task = lesson.getTask(removedFile.getName()); + if (task == null) { + return; + } + lesson.getTasklist().remove(task); + lesson.getTasksMap().remove(removedFile.getName()); + } + + private void deleteTaskFile(Course course, VirtualFile removedFile) { + VirtualFile taskDir = removedFile.getParent(); + if (taskDir == null || !taskDir.getName().contains("task")) { + return; + } + VirtualFile lessonDir = taskDir.getParent(); + if (lessonDir == null || !lessonDir.getName().contains("lesson")) { + return; + } + VirtualFile courseDir = lessonDir.getParent(); + if (!courseDir.getName().equals(myProject.getName())) { + return; + } + Lesson lesson = course.getLesson(lessonDir.getName()); + if (lesson == null) { + return; + } + Task task = lesson.getTask(taskDir.getName()); + if (task == null) { + return; + } + TaskFile taskFile = task.getTaskFile(removedFile.getName()); + if (taskFile == null) { + return; + } + String name = CCProjectService.getRealTaskFileName(removedFile.getName()); + task.getTaskFiles().remove(name); + } } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java index 38720140caf1..69aa748bf873 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java @@ -42,4 +42,8 @@ public class Lesson { public int getIndex() { return myIndex; } + + public Map getTasksMap() { + return myTasksMap; + } } From 59f794e191782c2dac2829ee38b2a5b0eb7bab56 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 5 Sep 2014 18:30:03 +0400 Subject: [PATCH 57/69] capitalization fixed: Jar -> JAR --- .../impl/artifacts/JarArtifactFromModulesDialog.form | 4 ++-- .../impl/artifacts/JarArtifactFromModulesDialog.java | 2 +- .../packaging/impl/artifacts/JarArtifactType.java | 2 +- .../impl/elements/PackagingElementFactoryImpl.java | 2 +- .../execution/jar/JarApplicationConfigurable.java | 2 +- .../execution/jar/JarApplicationConfiguration.java | 2 +- .../facet/impl/ui/libraries/LibraryOptionsPanel.form | 2 +- .../facet/impl/ui/libraries/LibraryOptionsPanel.java | 2 +- .../inferNullity/InferNullityAnnotationsAction.java | 2 +- .../src/com/intellij/jarFinder/FindJarFix.java | 4 ++-- .../jps/incremental/artifacts/impl/JarsBuilder.java | 2 +- .../service/project/manage/LibraryDataService.java | 2 +- .../roots/libraries/ui/impl/RootDetectionUtil.java | 2 +- .../src/messages/FeatureStatisticsBundle.properties | 2 +- .../src/messages/IdeBundle.properties | 10 +++++----- .../src/messages/RefactoringBundle.properties | 2 +- .../openapi/roots/impl/libraries/JarDirectories.java | 2 +- .../src/messages/ProjectBundle.properties | 4 ++-- .../org/jetbrains/idea/devkit/DevKitBundle.properties | 2 +- plugins/gradle/resources/i18n/GradleBundle.properties | 2 +- .../gradle/service/GradleInstallationManager.java | 2 +- .../gradle/importing/GradleImportingTestCase.java | 2 +- .../jetbrains/plugins/groovy/GroovyBundle.properties | 2 +- .../plugins/groovy/dsl/GroovyClassDescriptor.java | 2 +- .../groovy/ivy/AbstractAttachSourceProvider.java | 2 +- .../plugins/terminal/LocalTerminalDirectRunner.java | 2 +- resources-en/src/messages/CompilerBundle.properties | 2 +- updater/src/com/intellij/updater/Runner.java | 8 ++++---- 28 files changed, 38 insertions(+), 38 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form index eed2b888d43f..aeffe083cd9e 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form @@ -67,7 +67,7 @@ - + @@ -75,7 +75,7 @@ - + diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java index 02d9e4228eec..ea2f4a64f622 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java @@ -55,7 +55,7 @@ public class JarArtifactFromModulesDialog extends DialogWrapper { public JarArtifactFromModulesDialog(PackagingElementResolvingContext context) { super(context.getProject()); myContext = context; - setTitle("Create Jar from Modules"); + setTitle("Create JAR from Modules"); myMainClassLabel.setLabelFor(myMainClassField.getTextField()); myManifestDirLabel.setLabelFor(myManifestDirField.getTextField()); diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java index 2a0af9007963..bd4494c6f4a3 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java @@ -33,7 +33,7 @@ import java.util.List; */ public class JarArtifactType extends ArtifactType { public JarArtifactType() { - super("jar", "Jar"); + super("jar", "JAR"); } public static JarArtifactType getInstance() { diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java index 0d1737b07e42..7e8f6016d591 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java @@ -274,7 +274,7 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory { @NotNull @Override public PackagingElement createExtractedDirectory(@NotNull VirtualFile jarEntry) { - LOG.assertTrue(jarEntry.getFileSystem() instanceof JarFileSystem, "Expected file from jar but file from " + jarEntry.getFileSystem() + " found"); + LOG.assertTrue(jarEntry.getFileSystem() instanceof JarFileSystem, "Expected file from JAR but file from " + jarEntry.getFileSystem() + " found"); final String fullPath = jarEntry.getPath(); final int jarEnd = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR); return new ExtractedDirectoryPackagingElement(fullPath.substring(0, jarEnd), fullPath.substring(jarEnd + 1)); diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java index debdb7b9fdc6..03758cd031cb 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java @@ -73,7 +73,7 @@ public class JarApplicationConfigurable extends SettingsEditor(); TextFieldWithBrowseButton textFieldWithBrowseButton = new TextFieldWithBrowseButton(); - textFieldWithBrowseButton.addBrowseFolderListener("Choose Jar File", null, myProject, + textFieldWithBrowseButton.addBrowseFolderListener("Choose JAR File", null, myProject, new FileChooserDescriptor(false, false, true, true, false, false)); myJarPathComponent.setComponent(textFieldWithBrowseButton); } diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java index 970abc055032..c76b5873389a 100644 --- a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java @@ -99,7 +99,7 @@ public class JarApplicationConfiguration extends LocatableConfigurationBase impl ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), null); File jarFile = new File(getJarPath()); if (!jarFile.exists()) { - throw new RuntimeConfigurationWarning("Jar file '" + jarFile.getAbsolutePath() + "' doesn't exist"); + throw new RuntimeConfigurationWarning("JAR file '" + jarFile.getAbsolutePath() + "' doesn't exist"); } JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this); } diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form index a738a96aa50e..9e5dd85f6936 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form @@ -139,7 +139,7 @@ - + diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java index 3bb96adb1141..a890bdad527d 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java @@ -490,7 +490,7 @@ public class LibraryOptionsPanel implements Disposable { else { path = PathUtil.getFileName(downloadPath); } - return MessageFormat.format("{0} {0, choice, 1#jar|2#jars} will be downloaded into {1} directory
" + + return MessageFormat.format("{0} {0, choice, 1#JAR|2#JARs} will be downloaded into {1} directory
" + "{2} library {3} will be created", downloadSettings.getSelectedDownloads().size(), path, diff --git a/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java b/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java index f9127f0b48a5..df49b83ff48d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java +++ b/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java @@ -159,7 +159,7 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction { } else if (Messages.showOkCancelDialog(project, "Infer Nullity Annotations requires that the nullity annotations" + " be available in all your project sources.\n\nYou will need to add annotations.jar as a library. " + - "It is possible to configure custom jar in e.g. Constant Conditions & Exceptions inspection or use JetBrains annotations available in installation. " + + "It is possible to configure custom JAR in e.g. Constant Conditions & Exceptions inspection or use JetBrains annotations available in installation. " + " IntelliJ IDEA nullity annotations are freely usable and redistributable under the Apache 2.0 license. Would you like to do it now?", INFER_NULLITY_ANNOTATIONS, Messages.getErrorIcon()) == Messages.OK) { ApplicationManager.getApplication().invokeLater(new Runnable() { diff --git a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java index ee203e34deac..e82f79652074 100644 --- a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java +++ b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java @@ -69,7 +69,7 @@ public abstract class FindJarFix implements IntentionActio @NotNull @Override public String getText() { - return "Find jar on web"; + return "Find JAR on web"; } @NotNull @@ -190,7 +190,7 @@ public abstract class FindJarFix implements IntentionActio } else { JBPopupFactory.getInstance() .createListPopupBuilder(libNames) - .setTitle("Select a jar file") + .setTitle("Select a JAR file") .setItemChoosenCallback(new Runnable() { @Override public void run() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java index ba43cc7ea05e..c5ce16567be4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java @@ -181,7 +181,7 @@ public class JarsBuilder { packedFilePaths, -1); } else { - LOG.debug("nested jar file " + relativePath + " for " + jar.getPresentableDestination() + " not found"); + LOG.debug("nested JAR file " + relativePath + " for " + jar.getPresentableDestination() + " not found"); } } } diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java index d04d728966bb..873a12fe8eb3 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java @@ -152,7 +152,7 @@ public class LibraryDataService implements ProjectDataService names = new HashMap(); for (LibraryRootType type : root.getTypes()) { final String typeName = detector.getRootTypeName(type); - LOG.assertTrue(typeName != null, "Unexpected root type " + type.getType().name() + (type.isJarDirectory() ? " (jar directory)" : "") + ", detectors: " + detector); + LOG.assertTrue(typeName != null, "Unexpected root type " + type.getType().name() + (type.isJarDirectory() ? " (JAR directory)" : "") + ", detectors: " + detector); names.put(type, typeName); } suggestedRoots.add(new SuggestedChildRootInfo(rootCandidate, root, names)); diff --git a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties index 9a94f1f267bc..346399cfe60e 100644 --- a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties +++ b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties @@ -121,4 +121,4 @@ find.recent.search=Recent searches history find.completion=Completion in Find Bar switcher=Switcher dir.diff=Directory Diff -jar.diff=Jar Files Diff +jar.diff=JAR Files Diff diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 889a1383aa91..720ac40cc1eb 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -942,10 +942,10 @@ predefined.scope.tests.name=Tests scope.editor.legend.recursively.included.label=Recursively included scope.editor.legend.partly.included.label=Partially included toolwindow.palette=Palette -jar.build.on.make=Build jars on &make -jar.build.modules.to.jar=Choose Modules to Jar -jar.build.module.0.jar.settings=Module ''{0}'' Jar Settings -jar.build.include.in.jar.file=Include in jar file: +jar.build.on.make=Build JARs on &make +jar.build.modules.to.jar=Choose Modules to JAR +jar.build.module.0.jar.settings=Module ''{0}'' JAR Settings +jar.build.include.in.jar.file=Include in JAR file: search.textfield.title=&Search: select.in.scope=Scope scope.view.title=Scopes @@ -1019,7 +1019,7 @@ button.fix=Fix\u2026 setup.library.dialog.title=Setup Library label.library.will.be.created.description.text={0} level library {1} with {2} {2, choice, 1#file|2#files} will be created new.library.file.chooser.title=New Library Files -new.library.file.chooser.description=Select jar files in which library classes are located +new.library.file.chooser.description=Select JAR files in which library classes are located create.default.library.type.action.name=Java popup.title.select.library.type=Select Library Type diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index 48d0e63d60c0..72b1cd7ad131 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -671,7 +671,7 @@ static.initializer.description=static initializer of class {0} instance.initializer.description=instance initializer of class {0} file.description=File {0} directory.description=Directory {0} -0.is.located.in.a.jar.file={0} is located in a jar file.\n +0.is.located.in.a.jar.file={0} is located in a JAR file.\n 0.is.read.only={0} is read-only.\n 0.is.not.a.legal.java.identifier=''{0}'' is not a legal java identifier method.0.is.already.defined.in.the.1=Method {0} is already defined in the {1} diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java index e9e4da53dddd..c4903098fa87 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java @@ -106,7 +106,7 @@ public class JarDirectories implements JDOMExternalizable { @Override public String toString() { - return "Jar dirs: " + myDirectories.values(); + return "JAR dirs: " + myDirectories.values(); } diff --git a/platform/projectModel-impl/src/messages/ProjectBundle.properties b/platform/projectModel-impl/src/messages/ProjectBundle.properties index a0fe65ad981a..956bb8a0d2d2 100644 --- a/platform/projectModel-impl/src/messages/ProjectBundle.properties +++ b/platform/projectModel-impl/src/messages/ProjectBundle.properties @@ -112,7 +112,7 @@ module.paths.edit.properties.title=Edit Root Properties module.javadoc.title=JavaDoc module.javadoc.add.url.button=Add JavaDoc URL... module.javadoc.add.path.title=Add Path To JavaDoc -module.javadoc.add.path.prompt=Select jar/zip files or directories in which module javadoc documentation is located +module.javadoc.add.path.prompt=Select JAR/zip files or directories in which module javadoc documentation is located jdk.combo.box.project.item= jdk.combo.box.none.item= jdk.combo.box.invalid.item={0} [Invalid] @@ -134,7 +134,7 @@ library.sources.not.found=Sources not found library.sources.not.attached=Sources not attached library.attach.sources.action=Attach Sources library.attach.sources.action.busy.text=Attaching... -library.attach.sources.description=Select jar/zip files or directories in which library sources are located +library.attach.sources.description=Select JAR/zip files or directories in which library sources are located project.sdk.not.defined=Project SDK is not defined project.sdk.setup=Setup SDK diff --git a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties index 6799f6d2415f..2d1f3de4e3d6 100644 --- a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties +++ b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties @@ -25,7 +25,7 @@ prepare.for.deployment.common=Preparing For Deployment prepare.for.deployment=Prepare Plugin Module ''{0}'' For Deployment prepare.for.deployment.all=Prepare All Plugin Modules For Deployment saved.message.common={0} will be saved in selected directory -saved.message= {0, choice, 1#Zip|2#Jar} for module ''{1}'' was saved to {2} +saved.message= {0, choice, 1#Zip|2#JAR} for module ''{1}'' was saved to {2} success.deployment.message=Plugin Module ''{0}'' Successfully Prepared For Deployment success.deployment.message.all=All Plugins Successfully Prepared For Deployment diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index 88dfd899deed..0f827062fbce 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -12,7 +12,7 @@ gradle.settings.text.service.dir.path=Service directory path: gradle.settings.text.vm.options=Gradle VM options: gradle.settings.text.offline_work=Offline work gradle.settings.title.service.dir.path=Select gradle service directory to use -gradle.generic.text.error.jar.not.found=Gradle jars location is unknown +gradle.generic.text.error.jar.not.found=Gradle JARs location is unknown gradle.home.setting.type.explicit.incorrect=Gradle location is incorrect.\nLocation:{0} gradle.home.setting.type.explicit.empty=Gradle location is not specified diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java index 07521be885d8..b363eb8b3395 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java @@ -360,7 +360,7 @@ public class GradleInstallationManager { filesInfo.setLength(filesInfo.length() - 1); } GradleLog.LOG.info(String.format( - "Gradle sdk check fails. Reason: no one of the given files matches gradle jar pattern (%s). Files: %s", + "Gradle sdk check fails. Reason: no one of the given files matches gradle JAR pattern (%s). Files: %s", GRADLE_JAR_FILE_PATTERN.toString(), filesInfo )); } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java index f59ccee38658..2cf4c7125918 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java @@ -160,7 +160,7 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes throw new RuntimeException(e); } if (!location.getScheme().equals("file")) { - throw new RuntimeException(String.format("Cannot determine classpath for wrapper Jar from codebase '%s'.", location)); + throw new RuntimeException(String.format("Cannot determine classpath for wrapper JAR from codebase '%s'.", location)); } return new File(location.getPath()); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 4e3c0eb17c38..0b97a8fbaa35 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -31,7 +31,7 @@ newscript.menu.action.description=Creates new Groovy Script cannot.compile.groovy.files.no.facet=Cannot find Groovy home for module ''{0}''.\nYou should either:\n\ - invoke 'Add Framework support' action for this module,\n\ or:\n\ -- add Groovy jars to module classpath manually. +- add Groovy JARs to module classpath manually. cannot.compile.groovy.files.no.sdk=Cannot Compile Groovy Files.\nPlease Set up SDK for module ''{0}''. cannot.compile.groovy.files.no.sdk.mult=Cannot Compile Groovy Files.\nPlease Set up SDK for modules ''{0}''. cannot.compile=Cannot Compile diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java index 2281ad12c4dd..33bd366f6261 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java @@ -38,7 +38,7 @@ public class GroovyClassDescriptor { final AtomicInteger integer = GroovyCategorySupport.getCategoryNameUsage("aaa"); } catch (NoSuchMethodError e) { - throw new RuntimeException("Incompatible Groovy jar in classpath: " + GroovyCategorySupport.class.getResource("/") + ", please remove it"); + throw new RuntimeException("Incompatible Groovy JAR in classpath: " + GroovyCategorySupport.class.getResource("/") + ", please remove it"); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java index 53ddae2cc17d..3f2139c174a8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java @@ -152,7 +152,7 @@ public abstract class AbstractAttachSourceProvider implements AttachSourcesProvi final ByteArrayOutputStream out; try { - LOG.info("Downloading sources jar: " + myUrl); + LOG.info("Downloading sources JAR: " + myUrl); indicator.checkCanceled(); diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java index f67f84412a02..8a5f75b36594 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java @@ -59,7 +59,7 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner Date: Fri, 5 Sep 2014 18:32:53 +0400 Subject: [PATCH 58/69] Extracted ExecUtil.exec() that returns a Process --- .../com/intellij/execution/util/ExecUtil.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java index 00c20735da1b..dbc9b3255d2b 100644 --- a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java +++ b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java @@ -83,16 +83,35 @@ public class ExecUtil { private ExecUtil() { } + /** + * Run the command using safe escaping and quoting when appropriate. + * + * @param command the command and its arguments, can contain any characters + * @param workDir working directory + * @param environment environment variables + * @return the running process + */ + @NotNull + public static Process exec(@NotNull final List command, @Nullable final String workDir, + @Nullable final Map environment) throws ExecutionException { + assert command.size() > 0; + final GeneralCommandLine commandLine = new GeneralCommandLine(command); + if (workDir != null) { + commandLine.setWorkDirectory(workDir); + } + if (environment != null) { + commandLine.getEnvironment().putAll(environment); + } + return commandLine.createProcess(); + } + public static int execAndGetResult(final String... command) throws ExecutionException, InterruptedException { assert command != null && command.length > 0; return execAndGetResult(Arrays.asList(command)); } public static int execAndGetResult(@NotNull final List command) throws ExecutionException, InterruptedException { - assert command.size() > 0; - final GeneralCommandLine commandLine = new GeneralCommandLine(command); - final Process process = commandLine.createProcess(); - return process.waitFor(); + return exec(command, null, null).waitFor(); } @NotNull @@ -151,10 +170,7 @@ public class ExecUtil { @NotNull public static ProcessOutput execAndGetOutput(@NotNull final List command, @Nullable final String workDir) throws ExecutionException { - assert command.size() > 0; - final GeneralCommandLine commandLine = new GeneralCommandLine(command); - commandLine.setWorkDirectory(workDir); - final Process process = commandLine.createProcess(); + final Process process = exec(command, workDir, null); final CapturingProcessHandler processHandler = new CapturingProcessHandler(process); return processHandler.runProcess(); } @@ -167,7 +183,7 @@ public class ExecUtil { @Nullable public static String execAndReadLine(@Nullable Charset charset, final String... command) { try { - return readFirstLine(new GeneralCommandLine(command).createProcess().getInputStream(), charset); + return readFirstLine(exec(Arrays.asList(command), null, null).getInputStream(), charset); } catch (Exception ignored) { return null; From 1b60f2666f37a582dd611c6107b45c494e780ba9 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 5 Sep 2014 16:06:57 +0200 Subject: [PATCH 59/69] new "Double brace initialization" inspection & quickfix --- .../src/META-INF/InspectionGadgets.xml | 4 + .../siyeh/InspectionGadgetsBundle.properties | 2 + .../DoubleBraceInitializationInspection.java | 216 ++++++++++++++++++ .../DoubleBraceInitialization.html | 13 ++ .../double_brace_initialization/Argument.java | 12 + .../Field.after.java | 12 + .../double_brace_initialization/Field.java | 10 + .../LocalVariable.after.java | 13 ++ .../LocalVariable.java | 14 ++ .../DoubleBraceInitialization.java | 32 +++ .../DoubleBraceInitializationFixTest.java | 38 +++ ...ubleBraceInitializationInspectionTest.java | 34 +++ 12 files changed, 400 insertions(+) create mode 100644 plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index 81cc13aea292..e7e866b0d3e7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -1046,6 +1046,10 @@ key="abstract.method.call.in.constructor.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.initialization.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.initialization.AbstractMethodCallInConstructorInspection"/> + #ref is too long ({0} > {1}) #loc junit3.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 3 test method name #ref doesn''t match regex ''{0}'' #loc introduce.holder.class.quickfix=Introduce holder class +double.brace.initialization.display.name=Double brace initialization +double.brace.initialization.quickfix=Replace with regular initialization diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java new file mode 100644 index 000000000000..bdf58e720d8d --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java @@ -0,0 +1,216 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.initialization; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class DoubleBraceInitializationInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("double.brace.initialization.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("double.brace.initialization.display.name"); + } + + @Nullable + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + final PsiClass aClass = (PsiClass)infos[0]; + final PsiElement parent = PsiTreeUtil.skipParentsOfType(aClass, PsiNewExpression.class, ParenthesesUtils.class); + if (!(parent instanceof PsiVariable) && !(parent instanceof PsiAssignmentExpression)) { + return null; + } + return new DoubleBraceInitializationFix(); + } + + private static class DoubleBraceInitializationFix extends InspectionGadgetsFix { + + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message("double.brace.initialization.quickfix"); + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement().getParent(); + if (!(element instanceof PsiAnonymousClass)) { + return; + } + final PsiAnonymousClass aClass = (PsiAnonymousClass)element; + final PsiElement parent = aClass.getParent(); + if (!(parent instanceof PsiNewExpression)) { + return; + } + final PsiNewExpression newExpression = (PsiNewExpression)parent; + final PsiElement ancestor = PsiTreeUtil.skipParentsOfType(newExpression, ParenthesesUtils.class); + final String qualifierText; + if (ancestor instanceof PsiVariable) { + qualifierText = ((PsiVariable)ancestor).getName(); + } + else if (ancestor instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)ancestor; + final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression()); + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiVariable)) { + return; + } + qualifierText = referenceExpression.getText(); + } + else { + return; + } + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + final PsiJavaCodeReferenceElement baseClassReference = aClass.getBaseClassReference(); + final PsiElement baseClassTarget = baseClassReference.resolve(); + if (!(baseClassTarget instanceof PsiClass)) { + return; + } + final PsiExpressionList argumentList = aClass.getArgumentList(); + if (argumentList == null) { + return; + } + qualifyReferences(aClass, (PsiClass) baseClassTarget, qualifierText); + final PsiClassInitializer initializer = aClass.getInitializers()[0]; + final PsiCodeBlock body = initializer.getBody(); + PsiElement child = body.getLastBodyElement(); + final PsiElement stop = body.getFirstBodyElement(); + final PsiElement anchor = PsiTreeUtil.getParentOfType(aClass, PsiMember.class, PsiStatement.class); + if (anchor == null) { + return; + } + if (anchor instanceof PsiMember) { + final PsiMember member = (PsiMember)anchor; + final PsiClassInitializer newInitializer = factory.createClassInitializer(); + if (member.hasModifierProperty(PsiModifier.STATIC)) { + final PsiModifierList modifierList = newInitializer.getModifierList(); + if (modifierList != null) { + modifierList.setModifierProperty(PsiModifier.STATIC, true); + } + } + final PsiCodeBlock initializerBody = newInitializer.getBody(); + while (child != null && !child.equals(stop)) { + initializerBody.add(child); + child = child.getPrevSibling(); + } + member.getParent().addAfter(newInitializer, member); + } + else { + final PsiElement container = anchor.getParent(); + while (child != null && !child.equals(stop)) { + container.addAfter(child, anchor); + child = child.getPrevSibling(); + } + } + final PsiExpression newNewExpression = + factory.createExpressionFromText("new " + baseClassReference.getText() + argumentList.getText(), aClass); + newExpression.replace(newNewExpression); + } + + private static void qualifyReferences(PsiElement element, final PsiClass target, final String qualifierText) { + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject()); + element.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.getQualifierExpression() != null) { + return; + } + final PsiElement expressionTarget = expression.resolve(); + if (!(expressionTarget instanceof PsiMember)) { + return; + } + final PsiMember member = (PsiMember)expressionTarget; + final PsiClass containingClass = member.getContainingClass(); + if (!target.equals(containingClass)) { + return; + } + final PsiExpression newExpression = factory.createExpressionFromText(qualifierText + '.' + expression.getText(), expression); + expression.replace(newExpression); + } + }); + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new DoubleBraceInitializationVisitor(); + } + + private static class DoubleBraceInitializationVisitor extends BaseInspectionVisitor { + + @Override + public void visitAnonymousClass(PsiAnonymousClass aClass) { + super.visitAnonymousClass(aClass); + final PsiClassInitializer[] initializers = aClass.getInitializers(); + if (initializers.length != 1) { + return; + } + final PsiClassInitializer initializer = initializers[0]; + if (initializer.hasModifierProperty(PsiModifier.STATIC)) { + // don't warn on broken code + return; + } + final PsiField[] fields = aClass.getFields(); + if (fields.length != 0) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + if (methods.length != 0) { + return; + } + final PsiClass[] innerClasses = aClass.getInnerClasses(); + if (innerClasses.length != 0) { + return; + } + final PsiJavaCodeReferenceElement reference = aClass.getBaseClassReference(); + if (reference.resolve() == null) { + return; + } + registerClassError(aClass, aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html new file mode 100644 index 000000000000..e2cf8b607f66 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html @@ -0,0 +1,13 @@ + + +Reports Double Brace Initialization. +Double brace initialization can cause memory leaks when used from a non-static context, +because the anonymous class created will maintain a reference to the surrounding object. +It has worse performance than regular initialization because of the additional class loading required. +It can cause equals() comparisons to fail, if the equals() method does not accept subclasses as parameter (see link above). +And finally, it cannot be combined with Java 7 diamond operator, because that cannot be used with anonymous classes. + +

+ New in 14 + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java new file mode 100644 index 000000000000..766ea62ea51d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java @@ -0,0 +1,12 @@ +public class Argument { + + void m(A a) {} + void n() { + m(new A() {{ setI(1); setJ(2); }}); + } + + class A { + void setI(int i) {} + void setJ(int j) {} + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java new file mode 100644 index 000000000000..804a5e59d66b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java @@ -0,0 +1,12 @@ +import java.util.ArrayList; +import java.util.List; + +public class Field { + static final List list = new ArrayList(); + + static { + for (int i = 0; i < 10; i++) { + list.add(i); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java new file mode 100644 index 000000000000..4f75edf20f18 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java @@ -0,0 +1,10 @@ +import java.util.ArrayList; +import java.util.List; + +public class Field { + static final List list = new ArrayList() {{ + for (int i = 0; i < 10; i++) { + add(i); + } + }}; +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java new file mode 100644 index 000000000000..92f47c31f39c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java @@ -0,0 +1,13 @@ +import java.util.HashMap; + +public class LocalVariable { + + void m() { + final HashMap map = new HashMap();// comment + map.put("a", "b"); + map.put("a", "b"); + map.put("a", "b"); + map.put("a", "b"); + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java new file mode 100644 index 000000000000..12b6f415a4a9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java @@ -0,0 +1,14 @@ +import java.util.HashMap; + +public class LocalVariable { + + void m() { + final HashMap map = new HashMap() {{ + // comment + put("a", "b"); + put("a", "b"); + put("a", "b"); + put("a", "b"); + }}; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java new file mode 100644 index 000000000000..f216f84e2f67 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java @@ -0,0 +1,32 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class DoubleBraceInitialization { + + void foo() { + final HashMap map = new HashMap() {{ + // comment + put("a", "b"); + put("a", "b"); + put("a", "b"); + put("a", "b"); + }}; + } + + static final List list = new ArrayList() {{ + for (int i = 0; i < 10; i++) { + add(i); + } + }}; + + void m(A a) {} + void n() { + m(new A() {{ setI(1); setJ(2); }}); + } + + class A { + void setI(int i) {} + void setJ(int j) {} + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java new file mode 100644 index 000000000000..afce138a7a82 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.fixes.initialization; + +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.initialization.DoubleBraceInitializationInspection; + +/** + * @author Bas Leijdekkers + */ +public class DoubleBraceInitializationFixTest extends IGQuickFixesTestCase { + + public void testLocalVariable() { doTest(); } + public void testField() { doTest(); } + public void testArgument() { assertQuickfixNotAvailable(); } + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(new DoubleBraceInitializationInspection()); + myRelativePath = "initialization/double_brace_initialization"; + myDefaultHint = InspectionGadgetsBundle.message("double.brace.initialization.quickfix"); + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java new file mode 100644 index 000000000000..532018d5c26e --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 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.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class DoubleBraceInitializationInspectionTest extends LightInspectionTestCase { + + public void testDoubleBraceInitialization() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new DoubleBraceInitializationInspection(); + } +} From be3529c7625707d74354d1777b79460eb0e72082 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 5 Sep 2014 18:46:51 +0400 Subject: [PATCH 60/69] Extracted ExecUtil.sudo() that returns a Process --- .../com/intellij/execution/util/ExecUtil.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java index dbc9b3255d2b..ca99fca910f8 100644 --- a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java +++ b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java @@ -215,12 +215,12 @@ public class ExecUtil { * @param command the command and its arguments, can contain any characters * @param prompt the prompt string for the users * @param workDir working directory + * @param environment environment variables * @return the results of running the process */ @NotNull - public static ProcessOutput sudoAndGetOutput(@NotNull List command, - @NotNull String prompt, - @Nullable String workDir) throws IOException, ExecutionException { + public static Process sudo(@NotNull final List command, @NotNull final String prompt, @Nullable final String workDir, + @Nullable final Map environment) throws ExecutionException, IOException { if (SystemInfo.isMac) { final String escapedCommandLine = StringUtil.join(command, new Function() { @Override @@ -229,28 +229,28 @@ public class ExecUtil { } }, " & \" \" & "); final String escapedScript = "do shell script " + escapedCommandLine + " with administrator privileges"; - return execAndGetOutput(Arrays.asList(getOsascriptPath(), "-e", escapedScript), workDir); + return exec(Arrays.asList(getOsascriptPath(), "-e", escapedScript), workDir, environment); } else if ("root".equals(System.getenv("USER"))) { - return execAndGetOutput(command, workDir); + return exec(command, workDir, environment); } else if (hasGkSudo.getValue()) { final List sudoCommand = new ArrayList(); sudoCommand.addAll(Arrays.asList("gksudo", "--message", prompt, "--")); sudoCommand.addAll(command); - return execAndGetOutput(sudoCommand, workDir); + return exec(sudoCommand, workDir, environment); } else if (hasKdeSudo.getValue()) { final List sudoCommand = new ArrayList(); sudoCommand.addAll(Arrays.asList("kdesudo", "--comment", prompt, "--")); sudoCommand.addAll(command); - return execAndGetOutput(sudoCommand, workDir); + return exec(sudoCommand, workDir, environment); } else if (hasPkExec.getValue()) { final List sudoCommand = new ArrayList(); sudoCommand.add("pkexec"); sudoCommand.addAll(command); - return execAndGetOutput(sudoCommand, workDir); + return exec(sudoCommand, workDir, environment); } else if (SystemInfo.isUnix && hasTerminalApp()) { final String escapedCommandLine = StringUtil.join(command, new Function() { @@ -269,12 +269,20 @@ public class ExecUtil { "echo\n" + "read -p \"Press Enter to close this window...\" TEMP\n" + "exit $STATUS\n"); - return execAndGetOutput(getTerminalCommand("Install", script.getAbsolutePath()), workDir); + return exec(getTerminalCommand("Install", script.getAbsolutePath()), workDir, environment); } throw new UnsupportedSystemException(); } + @NotNull + public static ProcessOutput sudoAndGetOutput(@NotNull List command, @NotNull String prompt, + @Nullable String workDir) throws IOException, ExecutionException { + final Process process = sudo(command, prompt, workDir, null); + final CapturingProcessHandler processHandler = new CapturingProcessHandler(process); + return processHandler.runProcess(); + } + @NotNull private static String escapeAppleScriptArgument(@NotNull String arg) { return "quoted form of \"" + arg.replace("\"", "\\\"") + "\""; From e43f934e27fdf7a2755d9187e16f2f4b7b3d1dac Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 17:07:02 +0400 Subject: [PATCH 61/69] class hierarchy scope: treat escape as empty scope selection (IDEA-129518) --- .../ClassHierarchyScopeDescriptor.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java index 356933823226..05b2578e5df1 100644 --- a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java +++ b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java @@ -69,23 +69,25 @@ public class ClassHierarchyScopeDescriptor extends ScopeDescriptor { chooser.showDialog(); PsiClass aClass = chooser.getSelected(); - if (aClass == null) return null; + if (aClass == null) { + myCachedScope = GlobalSearchScope.EMPTY_SCOPE; + } else { + final List classesToSearch = new LinkedList(); + classesToSearch.add(aClass); - final List classesToSearch = new LinkedList(); - classesToSearch.add(aClass); + classesToSearch.addAll(ClassInheritorsSearch.search(aClass, true).findAll()); - classesToSearch.addAll(ClassInheritorsSearch.search(aClass, true).findAll()); + FunctionalExpressionSearch.search(aClass).forEach(new Processor() { + @Override + public boolean process(PsiFunctionalExpression expression) { + classesToSearch.add(expression); + return true; + } + }); - FunctionalExpressionSearch.search(aClass).forEach(new Processor() { - @Override - public boolean process(PsiFunctionalExpression expression) { - classesToSearch.add(expression); - return true; - } - }); - - myCachedScope = new LocalSearchScope(PsiUtilCore.toPsiElementArray(classesToSearch), - IdeBundle.message("scope.hierarchy", ClassPresentationUtil.getNameForClass(aClass, true))); + myCachedScope = new LocalSearchScope(PsiUtilCore.toPsiElementArray(classesToSearch), + IdeBundle.message("scope.hierarchy", ClassPresentationUtil.getNameForClass(aClass, true))); + } } return myCachedScope; From 40d32ba16c7a52449401001d23fece4ad8327685 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 17:54:58 +0400 Subject: [PATCH 62/69] testng ref providers working in groovy (IDEA-129448) --- plugins/testng/src/META-INF/plugin.xml | 1 + .../testng/TestNGReferenceContributor.java | 28 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/plugins/testng/src/META-INF/plugin.xml b/plugins/testng/src/META-INF/plugin.xml index 5fe0fb55b60f..711ace8ad744 100644 --- a/plugins/testng/src/META-INF/plugin.xml +++ b/plugins/testng/src/META-INF/plugin.xml @@ -14,6 +14,7 @@ + diff --git a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java index 6e483fb97c3d..74bb548fcbbf 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java +++ b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java @@ -50,41 +50,41 @@ import java.util.ArrayList; import java.util.List; public class TestNGReferenceContributor extends PsiReferenceContributor { - private static PsiElementPattern.Capture getElementPattern(String annotation) { - return PlatformPatterns.psiElement(PsiLiteralExpression.class).and(new FilterPattern(new TestAnnotationFilter(annotation))); + private static PsiElementPattern.Capture getElementPattern(String annotation) { + return PlatformPatterns.psiElement(PsiLiteral.class).and(new FilterPattern(new TestAnnotationFilter(annotation))); } public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { registrar.registerReferenceProvider(getElementPattern("dependsOnMethods"), new PsiReferenceProvider() { @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new MethodReference[]{new MethodReference((PsiLiteralExpression)element)}; + return new MethodReference[]{new MethodReference((PsiLiteral)element)}; } }); registrar.registerReferenceProvider(getElementPattern("dataProvider"), new PsiReferenceProvider() { @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new DataProviderReference[]{new DataProviderReference((PsiLiteralExpression)element)}; + return new DataProviderReference[]{new DataProviderReference((PsiLiteral)element)}; } }); registrar.registerReferenceProvider(getElementPattern("groups"), new PsiReferenceProvider() { @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteralExpression)element)}; + return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteral)element)}; } }); registrar.registerReferenceProvider(getElementPattern("dependsOnGroups"), new PsiReferenceProvider() { @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) { - return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteralExpression)element)}; + return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteral)element)}; } }); } - private static class DataProviderReference extends PsiReferenceBase { + private static class DataProviderReference extends PsiReferenceBase { - public DataProviderReference(PsiLiteralExpression element) { + public DataProviderReference(PsiLiteral element) { super(element, false); } @@ -156,9 +156,9 @@ public class TestNGReferenceContributor extends PsiReferenceContributor { } } - private static class MethodReference extends PsiReferenceBase { + private static class MethodReference extends PsiReferenceBase { - public MethodReference(PsiLiteralExpression element) { + public MethodReference(PsiLiteral element) { super(element, false); } @@ -181,7 +181,7 @@ public class TestNGReferenceContributor extends PsiReferenceContributor { @Nullable private PsiClass getDependsClass(String val) { final String className = StringUtil.getPackageName(val); - final PsiLiteralExpression element = getElement(); + final PsiLiteral element = getElement(); return StringUtil.isEmpty(className) ? PsiUtil.getTopLevelClass(element) : JavaPsiFacade.getInstance(element.getProject()).findClass(className, element.getResolveScope()); } @@ -213,10 +213,10 @@ public class TestNGReferenceContributor extends PsiReferenceContributor { } } - private static class GroupReference extends PsiReferenceBase { + private static class GroupReference extends PsiReferenceBase { private final Project myProject; - public GroupReference(Project project, PsiLiteralExpression element) { + public GroupReference(Project project, PsiLiteral element) { super(element, false); myProject = project; } @@ -264,7 +264,7 @@ public class TestNGReferenceContributor extends PsiReferenceContributor { } public boolean isClassAcceptable(Class hintClass) { - return PsiLiteralExpression.class.isAssignableFrom(hintClass); + return PsiLiteral.class.isAssignableFrom(hintClass); } } } From a755c8491b5823f11fdfa66f76334bf64283b097 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 18:47:58 +0400 Subject: [PATCH 63/69] scopes: accept everything in module name, escape to regexp (IDEA-129127) --- .../psi/search/scope/packageSet/FilePatternPackageSet.java | 6 +++--- .../psi/search/scope/packageSet/PackageSetFactoryImpl.java | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java index 4fed9ea06538..db0c71b9f99a 100644 --- a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java +++ b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java @@ -56,12 +56,12 @@ public class FilePatternPackageSet extends PatternBasedPackageSet { if (modulePattern.startsWith("group:")) { int idx = modulePattern.indexOf(':', 6); if (idx == -1) idx = modulePattern.length(); - myModuleGroupPattern = Pattern.compile(StringUtil.replace(modulePattern.substring(6, idx), "*", ".*")); + myModuleGroupPattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(6, idx))); if (idx < modulePattern.length() - 1) { - myModulePattern = Pattern.compile(StringUtil.replace(modulePattern.substring(idx + 1), "*", ".*")); + myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(idx + 1))); } } else { - myModulePattern = Pattern.compile(StringUtil.replace(modulePattern, "*", ".*")); + myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern)); } } myFilePattern = filePattern != null ? Pattern.compile(convertToRegexp(filePattern, '/')) : null; diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java index 1a3e45d72df7..10f1ec94555e 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java @@ -137,8 +137,7 @@ public class PackageSetFactoryImpl extends PackageSetFactory { else if (myLexer.getTokenType() == ScopeTokenTypes.COLON) { pattern.append(":"); } else { - error(AnalysisScopeBundle.message("error.packageset.token.expectations", getTokenText())); - break; + pattern.append(getTokenText()); } myLexer.advance(); } From 7ab59b3c969f04f45296e66932c88d7e74c130d0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 5 Sep 2014 19:02:25 +0400 Subject: [PATCH 64/69] show number of tests to start if abstract test was selected (IDEA-129268) --- .../src/com/intellij/execution/junit/InheritorChooser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java index 74c919537d45..fc0e65f9742b 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java +++ b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java @@ -115,6 +115,7 @@ public class InheritorChooser { } } } + final int numberOfInheritors = classes.size(); final PsiClassListCellRenderer renderer = new PsiClassListCellRenderer() { @Override protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer, @@ -124,7 +125,7 @@ public class InheritorChooser { boolean selected, boolean hasFocus) { if (value == null) { - renderer.append("All"); + renderer.append("All (" + numberOfInheritors + ")"); return true; } return super.customizeNonPsiElementLeftRenderer(renderer, list, value, index, selected, hasFocus); From 7694d668b3bd72759a6d386e7b4d5ac7cb0c2c64 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 14:24:23 +0200 Subject: [PATCH 65/69] =?UTF-8?q?get=20rid=20of=20"DebuggerSettings"=20hac?= =?UTF-8?q?k=20=E2=80=94=20add=20param=20to=20registerAdditionalActions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reason — it is not just cleanup, I want to reduce XDebugSessionTab GC roots, and now we don't create inner DefaultActionGroup class (java is not Kotlin and such class holds tab in any case) --- .../debugger/engine/JavaDebugProcess.java | 15 ++++-------- .../com/intellij/xdebugger/XDebugProcess.java | 18 ++++++++++++-- .../xdebugger/impl/ui/XDebugSessionTab.java | 24 +++++-------------- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java index 34b18bbc4da7..64a04e889269 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java @@ -311,23 +311,16 @@ public class JavaDebugProcess extends XDebugProcess { } @Override - public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar) { + public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar, @NotNull DefaultActionGroup settings) { Constraints beforeRunner = new Constraints(Anchor.BEFORE, "Runner.Layout"); leftToolbar.add(Separator.getInstance(), beforeRunner); leftToolbar.add(ActionManager.getInstance().getAction(DebuggerActions.EXPORT_THREADS), beforeRunner); leftToolbar.add(ActionManager.getInstance().getAction(DebuggerActions.DUMP_THREADS), beforeRunner); leftToolbar.add(Separator.getInstance(), beforeRunner); - for (AnAction action : leftToolbar.getChildren(null)) { - //TODO: maybe introduce API for extra settings? - if (action instanceof DefaultActionGroup && "DebuggerSettings".equals(action.getTemplatePresentation().getText())) { - DefaultActionGroup settings = (DefaultActionGroup)action; - addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP); - settings.addAction(new AutoVarsSwitchAction(), Constraints.FIRST); - settings.addAction(new WatchLastMethodReturnValueAction(), Constraints.FIRST); - break; - } - } + addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP); + settings.addAction(new AutoVarsSwitchAction(), Constraints.FIRST); + settings.addAction(new WatchLastMethodReturnValueAction(), Constraints.FIRST); } private static class AutoVarsSwitchAction extends ToggleAction { diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java index 9cfe6e4e7605..ee949a2ae9ce 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java @@ -193,16 +193,29 @@ public abstract class XDebugProcess { } /** - * @deprecated override {@link #createTabLayouter()} and {@link com.intellij.xdebugger.ui.XDebugTabLayouter#registerAdditionalContent} instead + * @deprecated Override {@link #createTabLayouter()} and {@link com.intellij.xdebugger.ui.XDebugTabLayouter#registerAdditionalContent} instead + * to remove in IDEA 15 */ + @SuppressWarnings("UnusedParameters") @Deprecated public void registerAdditionalContent(@NotNull RunnerLayoutUi ui) { } + @SuppressWarnings("UnusedParameters") + @Deprecated + /** + * @deprecated Override {@link #registerAdditionalActions(com.intellij.openapi.actionSystem.ActionGroup, com.intellij.openapi.actionSystem.ActionGroup, com.intellij.openapi.actionSystem.ActionGroup)} instead + * to remove in IDEA 15 + */ + public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar) { + } + /** * Override this method to provide additional actions in 'Debug' tool window */ - public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar) { + public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar, @NotNull DefaultActionGroup settings) { + //noinspection deprecation + registerAdditionalActions(leftToolbar, topToolbar); } /** @@ -225,6 +238,7 @@ public abstract class XDebugProcess { return new XDebugTabLayouter() { @Override public void registerAdditionalContent(@NotNull RunnerLayoutUi ui) { + //noinspection deprecation XDebugProcess.this.registerAdditionalContent(ui); } }; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java index a2dbd21073f6..881ed56bad3d 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java @@ -246,24 +246,12 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { leftToolbar.add(myUi.getOptions().getLayoutActions()); final AnAction[] commonSettings = myUi.getOptions().getSettingsActionsList(); - final AnAction commonSettingsList = myUi.getOptions().getSettingsActions(); - - final DefaultActionGroup settings = new DefaultActionGroup("DebuggerSettings", commonSettings.length > 0) { - @Override - public void update(AnActionEvent e) { - e.getPresentation().setText(ActionsBundle.message("group.XDebugger.settings.text")); - e.getPresentation().setIcon(commonSettingsList.getTemplatePresentation().getIcon()); - } - - @Override - public boolean isDumbAware() { - return true; - } - }; - for (AnAction each : commonSettings) { - settings.add(each); - } + DefaultActionGroup settings = new DefaultActionGroup(ActionsBundle.message("group.XDebugger.settings.text"), true); + settings.getTemplatePresentation().setIcon(myUi.getOptions().getSettingsActions().getTemplatePresentation().getIcon()); if (commonSettings.length > 0) { + for (AnAction each : commonSettings) { + settings.add(each); + } settings.addSeparator(); } if (!session.getDebugProcess().isValuesCustomSorted()) { @@ -281,7 +269,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase { DefaultActionGroup topToolbar = new DefaultActionGroup(); topToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP)); - session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar); + session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar, settings); myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR); myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR); From 33b830308464537cac9c60072a131baba0efd992 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 15:40:36 +0200 Subject: [PATCH 66/69] cleanup --- .../execution/testframework/Filter.java | 10 +++++ .../AbstractRerunFailedTestsAction.java | 41 +++++++++++-------- .../ui/actions/RerunFailedTestsAction.java | 8 ++-- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java index 7d43fcd2a7e1..8dd6363c5940 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java @@ -61,42 +61,49 @@ public abstract class Filter { } public static final Filter NO_FILTER = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return true; } }; public static final Filter DEFECT = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isDefect(); } }; public static final Filter IGNORED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isIgnored(); } }; public static final Filter NOT_PASSED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return !test.isPassed(); } }; public static final Filter PASSED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isPassed(); } }; public static final Filter FAILED_OR_INTERRUPTED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isInterrupted() || test.isDefect(); } }; public static final Filter LEAF = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isLeaf(); } @@ -122,6 +129,7 @@ public abstract class Filter { myFilter2 = filter2; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return myFilter1.shouldAccept(test) && myFilter2.shouldAccept(test); } @@ -134,6 +142,7 @@ public abstract class Filter { myFilter = filter; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return !myFilter.shouldAccept(test); } @@ -148,6 +157,7 @@ public abstract class Filter { myFilter2 = filter2; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return myFilter1.shouldAccept(test) || myFilter2.shouldAccept(test); } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java index 6d87bbb2fec3..5f7bfc22c8fd 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java @@ -61,8 +61,10 @@ import java.util.*; import java.util.List; public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable { - private static final List registry = ContainerUtil.createLockFreeCopyOnWriteList(); private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction"); + + private static final List REGISTRY = ContainerUtil.createLockFreeCopyOnWriteList(); + private TestFrameworkRunningModel myModel; private Getter myModelProvider; protected TestConsoleProperties myConsoleProperties; @@ -77,7 +79,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction protected AbstractRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { myParent = componentContainer.getComponent(); - registry.add(this); + REGISTRY.add(this); Disposer.register(componentContainer, this); copyFrom(ActionManager.getInstance().getAction("RerunFailedTests")); registerCustomShortcutSet(getShortcutSet(), myParent); @@ -85,7 +87,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction @Override public void dispose() { - registry.remove(this); + REGISTRY.remove(this); } public void init(final TestConsoleProperties consoleProperties, @@ -104,12 +106,12 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction @NotNull private AbstractRerunFailedTestsAction findActualAction() { - if (myParent != null || registry.isEmpty()) + if (myParent != null || REGISTRY.isEmpty()) return this; - List candidates = new ArrayList(registry); + List candidates = new ArrayList(REGISTRY); Collections.sort(candidates, new Comparator() { @Override - public int compare(AbstractRerunFailedTestsAction action1, AbstractRerunFailedTestsAction action2) { + public int compare(@NotNull AbstractRerunFailedTestsAction action1, @NotNull AbstractRerunFailedTestsAction action2) { Window window1 = SwingUtilities.windowForComponent(action1.myParent); Window window2 = SwingUtilities.windowForComponent(action2.myParent); if (window1 == null) @@ -129,7 +131,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction } @Override - public final void update(AnActionEvent e) { + public final void update(@NotNull AnActionEvent e) { AbstractRerunFailedTestsAction action = findActualAction(); e.getPresentation().setEnabled(action.isActive(e)); } @@ -140,10 +142,12 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction if (project == null) return false; TestFrameworkRunningModel model = getModel(); if (model == null || model.getRoot() == null) return false; - final List myAllTests = model.getRoot().getAllTests(); - final Filter filter = getFailuresFilter(); - for (Object test : myAllTests) { - if (filter.shouldAccept((AbstractTestProxy)test)) return true; + Filter filter = getFailuresFilter(); + for (AbstractTestProxy test : model.getRoot().getAllTests()) { + //noinspection unchecked + if (filter.shouldAccept(test)) { + return true; + } } return false; } @@ -151,10 +155,10 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction @NotNull protected List getFailedTests(Project project) { TestFrameworkRunningModel model = getModel(); - final List myAllTests = model != null - ? model.getRoot().getAllTests() - : Collections.emptyList(); - return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(myAllTests); + //noinspection unchecked + return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(model != null + ? model.getRoot().getAllTests() + : Collections.emptyList()); } @NotNull @@ -162,7 +166,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction return getFailuresFilter(); } - protected Filter getFailuresFilter() { + protected Filter getFailuresFilter() { if (TestConsoleProperties.INCLUDE_NON_STARTED_IN_RERUN_FAILED.value(myConsoleProperties)) { return Filter.NOT_PASSED.and(Filter.IGNORED.not()).or(Filter.FAILED_OR_INTERRUPTED); } @@ -170,7 +174,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction } @Override - public void actionPerformed(AnActionEvent e) { + public void actionPerformed(@NotNull AnActionEvent e) { findActualAction().showPopup(e); } @@ -212,8 +216,9 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setSelectedValue(executor, true); list.setCellRenderer(new DefaultListCellRenderer() { + @NotNull @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(@NotNull JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { final Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof Executor) { setText(UIUtil.removeMnemonic(((Executor)value).getStartActionText())); diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java index 04c13aa9e6fa..3fbc127a48ee 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,7 +16,6 @@ package com.intellij.execution.junit2.ui.actions; -import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.actions.JavaRerunFailedTestsAction; import com.intellij.execution.configurations.RunProfileState; @@ -31,7 +30,6 @@ import org.jetbrains.annotations.NotNull; * @author Alexey */ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { - public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { super(componentContainer); } @@ -41,12 +39,14 @@ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { final JUnitConfiguration configuration = (JUnitConfiguration)getModel().getProperties().getConfiguration(); final TestMethods testMethods = new TestMethods(configuration.getProject(), configuration, myEnvironment, getFailedTests(configuration.getProject())); return new MyRunProfile(configuration) { + @Override @NotNull public Module[] getModules() { return testMethods.getModulesToCompile(); } - public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) { testMethods.clear(); return testMethods; } From aaacc0055a2024ba30e9cc1e1c3e7c140af91c6b Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 16:44:50 +0200 Subject: [PATCH 67/69] cleanup --- .../src/com/intellij/execution/junit/TestMethods.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java index a526abb6a7ea..234240e8726e 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java @@ -52,6 +52,7 @@ public class TestMethods extends TestMethod { myFailedTests = failedTests; } + @Override protected void initialize() throws ExecutionException { defaultInitialize(); final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); @@ -59,6 +60,7 @@ public class TestMethods extends TestMethod { final Project project = module.getProject(); final ExecutionException[] exception = new ExecutionException[1]; ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override public void run() { try { myConfiguration.configureClasspath(myJavaParameters); @@ -76,17 +78,17 @@ public class TestMethods extends TestMethod { if (location instanceof PsiMemberParameterizedLocation) { final PsiElement element = location.getPsiElement(); if (element instanceof PsiMethod) { - location = MethodLocation.elementInClass(((PsiMethod)element), + location = MethodLocation.elementInClass(((PsiMethod)element), ((PsiMemberParameterizedLocation)location).getContainingClass()); } } if (!(location instanceof MethodLocation)) continue; PsiElement psiElement = location.getPsiElement(); LOG.assertTrue(psiElement instanceof PsiMethod); - PsiMethod method = (PsiMethod)psiElement; methods.add(((TestProxy)failedTest).getInfo()); } addClassesListToJavaParameters(methods, new Function() { + @Override public String fun(TestInfo testInfo) { if (testInfo != null) { final MethodLocation location = (MethodLocation)testInfo.getLocation(project, searchScope); @@ -99,6 +101,7 @@ public class TestMethods extends TestMethod { } + @Override public String suggestActionName() { return ActionsBundle.message("action.RerunFailedTests.text"); } From 00e84d38e50afb8e6b0573bc15791d1bd395de80 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 16:45:48 +0200 Subject: [PATCH 68/69] cleanup --- .../junit/src/com/intellij/execution/junit/TestMethod.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java index 23d798314197..287e1571ed64 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java @@ -37,6 +37,7 @@ class TestMethod extends TestObject { super(project, configuration, environment); } + @Override protected void initialize() throws ExecutionException { defaultInitialize(); final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); @@ -66,16 +67,19 @@ class TestMethod extends TestObject { myJavaParameters.getProgramParametersList().add(JUnitStarter.JUNIT3_PARAMETER); } + @Override public String suggestActionName() { return ProgramRunnerUtil.shortenName(myConfiguration.getPersistentData().METHOD_NAME, 2) + "()"; } + @Override public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) { if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod)element; if (!method.getName().equals(configuration.getPersistentData().getMethodName())) return null; if (!method.getContainingClass().equals(configuration.myClass.getPsiElement())) return null; class Listener extends RefactoringElementAdapter implements UndoRefactoringElementListener { + @Override public void elementRenamedOrMoved(@NotNull final PsiElement newElement) { final boolean generatedName = configuration.isGeneratedName(); configuration.getPersistentData().setTestMethod(PsiLocation.fromPsiElement((PsiMethod)newElement)); @@ -99,6 +103,7 @@ class TestMethod extends TestObject { } + @Override public boolean isConfiguredByElement(final JUnitConfiguration configuration, PsiClass testClass, PsiMethod testMethod, @@ -118,6 +123,7 @@ class TestMethod extends TestObject { Comparing.equal(testMethod.getName(), data.getMethodName()); } + @Override public void checkConfiguration() throws RuntimeConfigurationException { super.checkConfiguration(); final JavaRunConfigurationModule configurationModule = myConfiguration.getConfigurationModule(); From 5d13f8997ea1ff77a38ace9f143a9e68ff170bac Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Sep 2014 18:11:58 +0200 Subject: [PATCH 69/69] =?UTF-8?q?AbstractRerunFailedTestsAction=20?= =?UTF-8?q?=E2=80=94=20get=20rid=20of=20static=20registry=20of=20actions,?= =?UTF-8?q?=20don't=20hold=20execution=20environment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actions/JavaRerunFailedTestsAction.java | 7 +- .../execution/ui/RunContentDescriptor.java | 3 + .../AbstractRerunFailedTestsAction.java | 141 +++++++----------- .../actions/RerunFailedTestsAction.java | 12 ++ .../xdebugger/impl/XDebugSessionImpl.java | 6 + .../execution/junit/JUnitConfiguration.java | 61 ++++++-- .../execution/junit/TestCategory.java | 14 +- .../intellij/execution/junit/TestClass.java | 12 +- .../execution/junit/TestDirectory.java | 21 +-- .../intellij/execution/junit/TestMethod.java | 7 +- .../intellij/execution/junit/TestMethods.java | 13 +- .../intellij/execution/junit/TestObject.java | 51 +++---- .../intellij/execution/junit/TestPackage.java | 8 +- .../execution/junit/TestsPattern.java | 8 +- .../ui/actions/RerunFailedTestsAction.java | 14 +- .../configuration/TestNGRunnableState.java | 26 ++-- .../ui/actions/RerunFailedTestsAction.java | 15 +- python/src/META-INF/pycharm-core.xml | 2 +- .../testing/PyRerunFailedTestsAction.java | 14 +- .../PythonTestCommandLineStateBase.java | 4 +- resources/src/idea/RichPlatformActions.xml | 2 +- 21 files changed, 208 insertions(+), 233 deletions(-) create mode 100644 platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java diff --git a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java index 76e7175b87ff..3be2960bfcf7 100644 --- a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java +++ b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java @@ -22,6 +22,7 @@ package com.intellij.execution.actions; import com.intellij.execution.testframework.Filter; import com.intellij.execution.testframework.JavaAwareFilter; +import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentContainer; @@ -29,9 +30,10 @@ import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; public class JavaRerunFailedTestsAction extends AbstractRerunFailedTestsAction { - - protected JavaRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { + public JavaRerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) { super(componentContainer); + + init(consoleProperties); } @NotNull @@ -39,5 +41,4 @@ public class JavaRerunFailedTestsAction extends AbstractRerunFailedTestsAction { protected Filter getFilter(Project project, GlobalSearchScope searchScope) { return super.getFilter(project, searchScope).and(JavaAwareFilter.METHOD(project, searchScope)); } - } diff --git a/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java b/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java index 60e7f03d54db..71000f41f661 100644 --- a/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java +++ b/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java @@ -81,6 +81,8 @@ public class RunContentDescriptor implements Disposable { } myComponent = null; myRestarter = null; + myProcessHandler = null; + myContent = null; } /** @@ -127,6 +129,7 @@ public class RunContentDescriptor implements Disposable { myContent = content; } + @SuppressWarnings("UnusedDeclaration") @Nullable @Deprecated /** diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java index 5f7bfc22c8fd..efbfa4175814 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java @@ -34,20 +34,20 @@ import com.intellij.execution.testframework.Filter; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.TestFrameworkRunningModel; import com.intellij.idea.ActionsBundle; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentContainer; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.components.JBList; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -57,42 +57,23 @@ import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; -public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction"); - - private static final List REGISTRY = ContainerUtil.createLockFreeCopyOnWriteList(); +public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate { + private static final Logger LOG = Logger.getInstance(AbstractRerunFailedTestsAction.class); private TestFrameworkRunningModel myModel; private Getter myModelProvider; protected TestConsoleProperties myConsoleProperties; - protected ExecutionEnvironment myEnvironment; - private final JComponent myParent; - - @SuppressWarnings("UnusedDeclaration") - public AbstractRerunFailedTestsAction() { - //We call this constructor with a little help from reflection. - myParent = null; - } protected AbstractRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { - myParent = componentContainer.getComponent(); - REGISTRY.add(this); - Disposer.register(componentContainer, this); copyFrom(ActionManager.getInstance().getAction("RerunFailedTests")); - registerCustomShortcutSet(getShortcutSet(), myParent); + registerCustomShortcutSet(getShortcutSet(), componentContainer.getComponent()); } - @Override - public void dispose() { - REGISTRY.remove(this); - } - - public void init(final TestConsoleProperties consoleProperties, - final ExecutionEnvironment environment) { - myEnvironment = environment; + public void init(TestConsoleProperties consoleProperties) { myConsoleProperties = consoleProperties; } @@ -104,44 +85,21 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction myModelProvider = modelProvider; } - @NotNull - private AbstractRerunFailedTestsAction findActualAction() { - if (myParent != null || REGISTRY.isEmpty()) - return this; - List candidates = new ArrayList(REGISTRY); - Collections.sort(candidates, new Comparator() { - @Override - public int compare(@NotNull AbstractRerunFailedTestsAction action1, @NotNull AbstractRerunFailedTestsAction action2) { - Window window1 = SwingUtilities.windowForComponent(action1.myParent); - Window window2 = SwingUtilities.windowForComponent(action2.myParent); - if (window1 == null) - return 1; - if (window2 == null) - return -1; - boolean showing1 = action1.myParent.isShowing(); - boolean showing2 = action2.myParent.isShowing(); - if (showing1 && !showing2) - return -1; - if (showing2 && !showing1) - return 1; - return (window1.isActive() ? -1 : 1); - } - }); - return candidates.get(0); - } - @Override public final void update(@NotNull AnActionEvent e) { - AbstractRerunFailedTestsAction action = findActualAction(); - e.getPresentation().setEnabled(action.isActive(e)); + e.getPresentation().setEnabled(isActive(e)); } private boolean isActive(AnActionEvent e) { - DataContext dataContext = e.getDataContext(); - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) return false; + Project project = e.getProject(); + if (project == null) { + return false; + } + TestFrameworkRunningModel model = getModel(); - if (model == null || model.getRoot() == null) return false; + if (model == null || model.getRoot() == null) { + return false; + } Filter filter = getFailuresFilter(); for (AbstractTestProxy test : model.getRoot().getAllTests()) { //noinspection unchecked @@ -175,29 +133,26 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction @Override public void actionPerformed(@NotNull AnActionEvent e) { - findActualAction().showPopup(e); - } + ExecutionEnvironment environment = e.getData(LangDataKeys.EXECUTION_ENVIRONMENT); + if (environment == null) { + return; + } - private void showPopup(AnActionEvent e) { - boolean isDebug = myConsoleProperties.isDebug(); - final MyRunProfile profile = getRunProfile(); + MyRunProfile profile = getRunProfile(environment); if (profile == null) { return; } - final Executor executor = isDebug ? DefaultDebugExecutor.getDebugExecutorInstance() : DefaultRunExecutor.getRunExecutorInstance(); + final ExecutionEnvironmentBuilder environmentBuilder = new ExecutionEnvironmentBuilder(environment).runProfile(profile); final InputEvent event = e.getInputEvent(); if (!(event instanceof MouseEvent) || !event.isShiftDown()) { - final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executor.getId(), profile); - LOG.assertTrue(runner != null); - performAction(runner, profile, myEnvironment.getExecutor()); + performAction(environmentBuilder); return; } final LinkedHashMap availableRunners = new LinkedHashMap(); - final Executor[] executors = new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()}; - for (Executor ex : executors) { + for (Executor ex : new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()}) { final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(ex.getId(), profile); if (runner != null) { availableRunners.put(ex, runner); @@ -205,16 +160,16 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction } if (availableRunners.isEmpty()) { - LOG.error(executor.getActionName() + " is not available now"); - return; + LOG.error(environment.getExecutor().getActionName() + " is not available now"); } - - if (availableRunners.size() == 1) { - performAction(availableRunners.get(executor), profile, executor); - } else { + else if (availableRunners.size() == 1) { + //noinspection ConstantConditions + performAction(environmentBuilder.runner(availableRunners.get(environment.getExecutor()))); + } + else { final JBList list = new JBList(availableRunners.keySet()); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.setSelectedValue(executor, true); + list.setSelectedValue(environment.getExecutor(), true); list.setCellRenderer(new DefaultListCellRenderer() { @NotNull @Override @@ -227,6 +182,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction return component; } }); + //noinspection ConstantConditions JBPopupFactory.getInstance().createListPopupBuilder(list) .setTitle("Restart Failed Tests") .setMovable(false) @@ -237,34 +193,38 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction public void run() { final Object value = list.getSelectedValue(); if (value instanceof Executor) { - performAction(availableRunners.get(value), profile, (Executor)value); + //noinspection ConstantConditions + performAction(environmentBuilder.runner(availableRunners.get(value)).executor((Executor)value)); } } }).createPopup().showUnderneathOf(event.getComponent()); } } - private void performAction(ProgramRunner runner, MyRunProfile profile, Executor executor) { + private static void performAction(@NotNull ExecutionEnvironmentBuilder builder) { + ExecutionEnvironment environment = builder.build(); try { - new ExecutionEnvironmentBuilder(myEnvironment) - .runner(runner) - .executor(executor) - .runProfile(profile) - .buildAndExecute(); + environment.getRunner().execute(environment); } - catch (ExecutionException e1) { - LOG.error(e1); + catch (ExecutionException e) { + LOG.error(e); } finally { - profile.clear(); + ((MyRunProfile)environment.getRunProfile()).clear(); } } - @Nullable + @Deprecated public MyRunProfile getRunProfile() { return null; } + @Nullable + protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) { + //noinspection deprecation + return getRunProfile(); + } + @Nullable public TestFrameworkRunningModel getModel() { if (myModel != null) { @@ -298,7 +258,6 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction public void clear() { } - @Override public void checkConfiguration() throws RuntimeConfigurationException { } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java new file mode 100644 index 000000000000..af15e3c14ce1 --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java @@ -0,0 +1,12 @@ +package com.intellij.execution.testframework.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; + +class RerunFailedTestsAction extends AnAction { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + throw new IllegalStateException("Action only as template"); + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index ddc28745934a..6b114f655d17 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -73,6 +73,7 @@ import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.*; import javax.swing.event.HyperlinkEvent; @@ -217,6 +218,11 @@ public class XDebugSessionImpl implements XDebugSession { return myEnvironment != null ? myEnvironment.getRunProfile() : null; } + @TestOnly + public ExecutionEnvironment getEnvironment() { + return myEnvironment; + } + public boolean isPauseActionSupported() { return myPauseActionSupported; } diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index 28cd670446e9..0b7ab14a151d 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -20,19 +20,23 @@ import com.intellij.diagnostic.logging.LogConfigurationPanel; import com.intellij.execution.*; import com.intellij.execution.configuration.EnvironmentVariablesComponent; import com.intellij.execution.configurations.*; +import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.junit2.configuration.JUnitConfigurable; import com.intellij.execution.junit2.info.MethodLocation; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ExecutionEnvironmentBuilder; import com.intellij.execution.testframework.TestSearchScope; import com.intellij.execution.util.JavaParametersUtil; import com.intellij.openapi.components.PathMacroManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.options.SettingsEditorGroup; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.DefaultJDOMExternalizer; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -45,7 +49,6 @@ import java.util.*; public class JUnitConfiguration extends ModuleBasedConfiguration implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.JUnitConfiguration"); public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name"); @NonNls public static final String TEST_CLASS = "class"; @@ -75,11 +78,12 @@ public class JUnitConfiguration extends ModuleBasedConfiguration getConfigurationEditor() { SettingsEditorGroup group = new SettingsEditorGroup(); @@ -93,22 +97,25 @@ public class JUnitConfiguration extends ModuleBasedConfiguration getValidModules() { if (TEST_PACKAGE.equals(myData.TEST_OBJECT) || TEST_PATTERN.equals(myData.TEST_OBJECT)) { return Arrays.asList(ModuleManager.getInstance(getProject()).getModules()); } try { - myData.getTestObject(getProject(), this).checkConfiguration(); + myData.getTestObject(this).checkConfiguration(); } catch (RuntimeConfigurationError e) { return Arrays.asList(ModuleManager.getInstance(getProject()).getModules()); @@ -120,10 +127,12 @@ public class JUnitConfiguration extends ModuleBasedConfiguration envs) { myData.setEnvs(envs); } + @Override @NotNull public Map getEnvs() { return myData.getEnvs(); } + @Override public void setPassParentEnvs(boolean passParentEnvs) { myData.PASS_PARENT_ENVS = passParentEnvs; } + @Override public boolean isPassParentEnvs() { return myData.PASS_PARENT_ENVS; } + @Override public boolean isAlternativeJrePathEnabled() { return ALTERNATIVE_JRE_PATH_ENABLED; } + @Override public void setAlternativeJrePathEnabled(boolean enabled) { - this.ALTERNATIVE_JRE_PATH_ENABLED = enabled; + ALTERNATIVE_JRE_PATH_ENABLED = enabled; } + @Override public String getAlternativeJrePath() { return ALTERNATIVE_JRE_PATH; } + @Override public void setAlternativeJrePath(String path) { - this.ALTERNATIVE_JRE_PATH = path; + ALTERNATIVE_JRE_PATH = path; } + @Override public String getRunClass() { final Data data = getPersistentData(); return data.TEST_OBJECT != TEST_CLASS && data.TEST_OBJECT != TEST_METHOD ? null : data.getMainClassName(); } + @Override public String getPackage() { final Data data = getPersistentData(); return !Comparing.strEqual(data.TEST_OBJECT, TEST_PACKAGE) ? null : data.getPackageName(); @@ -218,6 +243,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration myPackage = new RefactoringListeners.Accessor() { + @Override public void setName(final String qualifiedName) { final boolean generatedName = isGeneratedName(); myData.PACKAGE_NAME = qualifiedName; if (generatedName) setGeneratedName(); } + @Override public PsiPackage getPsiElement() { final String qualifiedName = myData.getPackageName(); return qualifiedName != null ? JavaPsiFacade.getInstance(getProject()).findPackage(qualifiedName) : null; } + @Override public void setPsiElement(final PsiPackage psiPackage) { setName(psiPackage.getQualifiedName()); } }; final RefactoringListeners.Accessor myClass = new RefactoringListeners.Accessor() { + @Override public void setName(@NotNull final String qualifiedName) { final boolean generatedName = isGeneratedName(); myData.MAIN_CLASS_NAME = qualifiedName; if (generatedName) setGeneratedName(); } + @Override public PsiClass getPsiElement() { return getConfigurationModule().findClass(myData.getMainClassName()); } + @Override public void setPsiElement(final PsiClass psiClass) { final Module originalModule = getConfigurationModule().getModule(); setMainClass(psiClass); @@ -264,9 +296,10 @@ public class JUnitConfiguration extends ModuleBasedConfiguration myFailedTests; - public TestMethods(final Project project, - final JUnitConfiguration configuration, - ExecutionEnvironment environment, - Collection failedTests) { - super(project, configuration, environment); + public TestMethods(@NotNull JUnitConfiguration configuration, + @NotNull ExecutionEnvironment environment, + @NotNull Collection failedTests) { + super(configuration, environment); + myFailedTests = failedTests; } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index cc7c0ee66b74..114bd0122b73 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -39,7 +39,6 @@ import com.intellij.execution.testframework.*; import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil; import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties; import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView; -import com.intellij.execution.testframework.ui.BaseTestsOutputConsoleView; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.util.JavaParametersUtil; @@ -49,7 +48,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.ex.JavaSdkUtil; @@ -81,13 +79,12 @@ import java.io.PrintWriter; import java.util.*; public abstract class TestObject implements JavaCommandLine { - protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject"); + protected static final Logger LOG = Logger.getInstance(TestObject.class); private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message"); @NonNls private static final String JUNIT_TEST_FRAMEWORK_NAME = "JUnit"; protected JavaParameters myJavaParameters; - private final Project myProject; protected final JUnitConfiguration myConfiguration; protected final ExecutionEnvironment myEnvironment; protected File myTempFile = null; @@ -95,26 +92,25 @@ public abstract class TestObject implements JavaCommandLine { public File myListenersFile; public static TestObject fromString(final String id, - final Project project, final JUnitConfiguration configuration, - ExecutionEnvironment environment) { + @NotNull ExecutionEnvironment environment) { if (JUnitConfiguration.TEST_METHOD.equals(id)) { - return new TestMethod(project, configuration, environment); + return new TestMethod(configuration, environment); } if (JUnitConfiguration.TEST_CLASS.equals(id)) { - return new TestClass(project, configuration, environment); + return new TestClass(configuration, environment); } if (JUnitConfiguration.TEST_PACKAGE.equals(id)){ - return new TestPackage(project, configuration, environment); + return new TestPackage(configuration, environment); } if (JUnitConfiguration.TEST_DIRECTORY.equals(id)) { - return new TestDirectory(project, configuration, environment); + return new TestDirectory(configuration, environment); } if (JUnitConfiguration.TEST_CATEGORY.equals(id)) { - return new TestCategory(project, configuration, environment); + return new TestCategory(configuration, environment); } if (JUnitConfiguration.TEST_PATTERN.equals(id)) { - return new TestsPattern(project, configuration, environment); + return new TestsPattern(configuration, environment); } return NOT_CONFIGURED; } @@ -124,10 +120,7 @@ public abstract class TestObject implements JavaCommandLine { return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY; } - protected TestObject(final Project project, - final JUnitConfiguration configuration, - ExecutionEnvironment environment) { - myProject = project; + protected TestObject(JUnitConfiguration configuration, ExecutionEnvironment environment) { myConfiguration = configuration; myEnvironment = environment; } @@ -143,7 +136,7 @@ public abstract class TestObject implements JavaCommandLine { public abstract boolean isConfiguredByElement(JUnitConfiguration configuration, PsiClass testClass, PsiMethod testMethod, - PsiPackage testPackage, + PsiPackage testPackage, PsiDirectory testDir); protected void configureModule(final JavaParameters parameters, final RunConfigurationModule configurationModule, final String mainClassName) @@ -153,7 +146,7 @@ public abstract class TestObject implements JavaCommandLine { myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null); } - private static final TestObject NOT_CONFIGURED = new TestObject(null, null, null) { + private static final TestObject NOT_CONFIGURED = new TestObject(null, null) { @Override public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) { return null; @@ -212,7 +205,7 @@ public abstract class TestObject implements JavaCommandLine { if (myJavaParameters.getJdk() == null){ myJavaParameters.setJdk(module != null ? ModuleRootManager.getInstance(module).getSdk() - : ProjectRootManager.getInstance(myProject).getProjectSdk()); + : ProjectRootManager.getInstance(myEnvironment.getProject()).getProjectSdk()); } myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath()); @@ -368,8 +361,7 @@ public abstract class TestObject implements JavaCommandLine { } }); - final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView); - rerunFailedTestsAction.init(consoleProperties, myEnvironment); + final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView, consoleProperties); rerunFailedTestsAction.setModelProvider(new Getter() { @Override public TestFrameworkRunningModel get() { @@ -384,22 +376,15 @@ public abstract class TestObject implements JavaCommandLine { private ExecutionResult useSmRunner(Executor executor, JUnitProcessHandler handler) { TestConsoleProperties testConsoleProperties = new SMTRunnerConsoleProperties(myConfiguration, JUNIT_TEST_FRAMEWORK_NAME, executor); - testConsoleProperties.setIfUndefined(TestConsoleProperties.HIDE_PASSED_TESTS, false); - BaseTestsOutputConsoleView smtConsoleView = SMTestRunnerConnectionUtil.createConsoleWithCustomLocator( + final ConsoleView consoleView = SMTestRunnerConnectionUtil.createConsoleWithCustomLocator( JUNIT_TEST_FRAMEWORK_NAME, testConsoleProperties, myEnvironment, null); - - - Disposer.register(myProject, smtConsoleView); - - final ConsoleView consoleView = smtConsoleView; consoleView.attachToProcess(handler); - final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView); - rerunFailedTestsAction.init(testConsoleProperties, myEnvironment); + RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView, testConsoleProperties); rerunFailedTestsAction.setModelProvider(new Getter() { @Override public TestFrameworkRunningModel get() { @@ -421,12 +406,12 @@ public abstract class TestObject implements JavaCommandLine { else { comment = null; } - TestsUIUtil.notifyByBalloon(myProject, started, model != null ? model.getRoot() : null, consoleProperties, comment); + TestsUIUtil.notifyByBalloon(myEnvironment.getProject(), started, model != null ? model.getRoot() : null, consoleProperties, comment); } protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException { appendForkInfo(executor); - return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myProject, true)); + return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myEnvironment.getProject(), true)); } private boolean forkPerModule() { @@ -449,7 +434,7 @@ public abstract class TestObject implements JavaCommandLine { if (getRunnerSettings() != null) { final String actionName = executor.getActionName(); - throw new CantRunException(actionName + " is disabled in fork mode.
Please change fork mode to <none> to " + actionName.toLowerCase() + "."); + throw new CantRunException(actionName + " is disabled in fork mode.
Please change fork mode to <none> to " + actionName.toLowerCase(Locale.ENGLISH) + "."); } final JavaParameters javaParameters = getJavaParameters(); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java index 3d3c2da89143..6bde0b4419dd 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java @@ -27,7 +27,6 @@ import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ExecutionEnvironmentBuilder; -import com.intellij.execution.runners.ExecutionUtil; import com.intellij.execution.testframework.SourceScope; import com.intellij.execution.testframework.TestSearchScope; import com.intellij.openapi.application.ApplicationManager; @@ -71,13 +70,10 @@ public class TestPackage extends TestObject { protected ServerSocket myServerSocket; private boolean myFoundTests = true; - public TestPackage(final Project project, - final JUnitConfiguration configuration, - ExecutionEnvironment environment) { - super(project, configuration, environment); + public TestPackage(JUnitConfiguration configuration, ExecutionEnvironment environment) { + super(configuration, environment); } - @Override public SourceScope getSourceScope() { final JUnitConfiguration.Data data = myConfiguration.getPersistentData(); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java index 7277c5e5369d..a017cb1b8e9d 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java @@ -48,10 +48,8 @@ import java.util.LinkedHashSet; import java.util.Set; public class TestsPattern extends TestPackage { - public TestsPattern(final Project project, - final JUnitConfiguration configuration, - ExecutionEnvironment environment) { - super(project, configuration, environment); + public TestsPattern(JUnitConfiguration configuration, ExecutionEnvironment environment) { + super(configuration, environment); } @Override @@ -119,7 +117,7 @@ public class TestsPattern extends TestPackage { ? className.substring(0, className.indexOf(',')) : className).trim(), GlobalSearchScope.allScope(project)); } - + protected void configureClasspath() throws CantRunException { final String jreHome = myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null; diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java index 3fbc127a48ee..332566b1b3f2 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.execution.junit2.ui.actions; import com.intellij.execution.Executor; @@ -22,22 +21,21 @@ import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.junit.JUnitConfiguration; import com.intellij.execution.junit.TestMethods; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.ComponentContainer; import org.jetbrains.annotations.NotNull; -/** - * @author Alexey - */ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { - public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { - super(componentContainer); + public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) { + super(componentContainer, consoleProperties); } @Override - public MyRunProfile getRunProfile() { + protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) { + //noinspection ConstantConditions final JUnitConfiguration configuration = (JUnitConfiguration)getModel().getProperties().getConfiguration(); - final TestMethods testMethods = new TestMethods(configuration.getProject(), configuration, myEnvironment, getFailedTests(configuration.getProject())); + final TestMethods testMethods = new TestMethods(configuration, environment, getFailedTests(configuration.getProject())); return new MyRunProfile(configuration) { @Override @NotNull diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 0c73ae5f5761..6579990d4184 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -14,12 +14,6 @@ * limitations under the License. */ -/* - * Created by IntelliJ IDEA. - * User: amrk - * Date: Jul 2, 2005 - * Time: 12:22:07 AM - */ package com.theoryinpractice.testng.configuration; import com.intellij.ExtensionPoints; @@ -40,7 +34,7 @@ import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.util.JavaParametersUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.module.LanguageLevelUtil; +import com.intellij.openapi.module.EffectiveLanguageLevelUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; @@ -77,7 +71,6 @@ import org.testng.remote.RemoteArgs; import org.testng.remote.RemoteTestNG; import org.testng.remote.strprotocol.SerializedMessageSender; -import javax.swing.*; import java.io.File; import java.io.IOException; import java.net.InetAddress; @@ -98,7 +91,7 @@ public class TestNGRunnableState extends JavaCommandLineState { public TestNGRunnableState(ExecutionEnvironment environment, TestNGConfiguration config) { super(environment); - this.runnerSettings = environment.getRunnerSettings(); + runnerSettings = environment.getRunnerSettings(); this.config = config; //TODO need to narrow this down a bit //setModulesToCompile(ModuleManager.getInstance(config.getProject()).getModules()); @@ -120,6 +113,7 @@ public class TestNGRunnableState extends JavaCommandLineState { } } + @NotNull @Override public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { final boolean smRunner = Registry.is("testng_sm_runner"); @@ -173,6 +167,7 @@ public class TestNGRunnableState extends JavaCommandLineState { final String text = event.getText(); final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType); final Printable printable = new Printable() { + @Override public void printOn(final Printer printer) { printer.print(text, consoleViewType); } @@ -188,9 +183,9 @@ public class TestNGRunnableState extends JavaCommandLineState { }); console.attachToProcess(processHandler); - RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console); - rerunFailedTestsAction.init(console.getProperties(), getEnvironment()); + RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console, console.getProperties()); rerunFailedTestsAction.setModelProvider(new Getter() { + @Override public TestFrameworkRunningModel get() { return console.getResultsView(); } @@ -218,8 +213,7 @@ public class TestNGRunnableState extends JavaCommandLineState { Disposer.register(getEnvironment().getProject(), smtConsoleView); smtConsoleView.attachToProcess(handler); - final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(smtConsoleView); - rerunFailedTestsAction.init(testConsoleProperties, getEnvironment()); + final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(smtConsoleView, testConsoleProperties); rerunFailedTestsAction.setModelProvider(new Getter() { @Override public TestFrameworkRunningModel get() { @@ -264,7 +258,7 @@ public class TestNGRunnableState extends JavaCommandLineState { Module module = config.getConfigurationModule().getModule(); LanguageLevel effectiveLanguageLevel = module == null ? LanguageLevelProjectExtension.getInstance(project).getLanguageLevel() - : LanguageLevelUtil.getEffectiveLanguageLevel(module); + : EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(module); final boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel != LanguageLevel.JDK_1_3; LOG.info("Language level is " + effectiveLanguageLevel.toString()); @@ -311,7 +305,7 @@ public class TestNGRunnableState extends JavaCommandLineState { javaParameters.getProgramParametersList().add(supportSerializationProtocol(config) ? RemoteArgs.PORT : CommandLineArgs.PORT, String.valueOf(port)); - if (data.getOutputDirectory() != null && !"".equals(data.getOutputDirectory())) { + if (data.getOutputDirectory() != null && !data.getOutputDirectory().isEmpty()) { javaParameters.getProgramParametersList().add(CommandLineArgs.OUTPUT_DIRECTORY, data.getOutputDirectory()); } @@ -379,7 +373,7 @@ public class TestNGRunnableState extends JavaCommandLineState { try { hostname = InetAddress.getLocalHost().getHostName(); } - catch (UnknownHostException e) { + catch (UnknownHostException ignored) { } params.add("-Xdebug"); params.add("-Xrunjdwp:transport=dt_socket,address=" + hostname + ':' + debugPort + ",suspend=y,server=n"); diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java index 597bb5983876..200983a2f1c6 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java @@ -1,13 +1,13 @@ package com.theoryinpractice.testng.ui.actions; import com.intellij.execution.CantRunException; -import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.Location; import com.intellij.execution.actions.JavaRerunFailedTestsAction; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testframework.AbstractTestProxy; +import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -30,23 +30,23 @@ import java.net.ServerSocket; import java.util.*; public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { - - public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { - super(componentContainer); + public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) { + super(componentContainer, consoleProperties); } @Override - public MyRunProfile getRunProfile() { + protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) { final TestNGConfiguration configuration = (TestNGConfiguration)getModel().getProperties().getConfiguration(); final List failedTests = getFailedTests(configuration.getProject()); return new MyRunProfile(configuration) { + @Override @NotNull public Module[] getModules() { return Module.EMPTY_ARRAY; } - public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { - + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) { return new TestNGRunnableState(env, configuration) { @Override protected SearchingForTestsTask createSearchingForTestsTask(ServerSocket serverSocket, @@ -99,5 +99,4 @@ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction { } }; } - } diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml index a9f7824b5340..cd2022b4036b 100644 --- a/python/src/META-INF/pycharm-core.xml +++ b/python/src/META-INF/pycharm-core.xml @@ -104,7 +104,7 @@ - diff --git a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java index 0b922514e52e..53cffdf0ee41 100644 --- a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java +++ b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java @@ -36,25 +36,21 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -/* - * User: ktisha - */ public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction { - protected PyRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { super(componentContainer); } @Override @Nullable - public MyRunProfile getRunProfile() { + protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) { final TestFrameworkRunningModel model = getModel(); - if (model == null) return null; - final AbstractPythonRunConfiguration configuration = (AbstractPythonRunConfiguration)model.getProperties().getConfiguration(); - return new MyTestRunProfile(configuration); + if (model == null) { + return null; + } + return new MyTestRunProfile((AbstractPythonRunConfiguration)model.getProperties().getConfiguration()); } - private class MyTestRunProfile extends MyRunProfile { public MyTestRunProfile(RunConfigurationBase configuration) { diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java index 1a5aafe59051..c73a488dc7f5 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java +++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java @@ -63,6 +63,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt myConfiguration = configuration; } + @Override @NotNull protected ConsoleView createAndAttachConsole(Project project, ProcessHandler processHandler, Executor executor) throws ExecutionException { @@ -89,6 +90,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt return new PythonTRunnerConsoleProperties(myConfiguration, executor, false); } + @Override public GeneralCommandLine generateCommandLine() throws ExecutionException { GeneralCommandLine cmd = super.generateCommandLine(); @@ -135,7 +137,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt PyRerunFailedTestsAction rerunFailedTestsAction = new PyRerunFailedTestsAction(console); if (console instanceof SMTRunnerConsoleView) { - rerunFailedTestsAction.init(((BaseTestsOutputConsoleView)console).getProperties(), getEnvironment()); + rerunFailedTestsAction.init(((BaseTestsOutputConsoleView)console).getProperties()); rerunFailedTestsAction.setModelProvider(new Getter() { @Override public TestFrameworkRunningModel get() { diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml index 324f2fe29c6e..9ca96101df82 100644 --- a/resources/src/idea/RichPlatformActions.xml +++ b/resources/src/idea/RichPlatformActions.xml @@ -28,7 +28,7 @@ -