[eclipse-pydev] 03/05: Imported Upstream version 3.9.2

Markus Koschany apo-guest at moszumanska.debian.org
Sat Mar 7 06:20:39 UTC 2015


This is an automated email from the git hooks/post-receive script.

apo-guest pushed a commit to branch master
in repository eclipse-pydev.

commit 230947145eeaa6b568b9f8e0bfcb75f78a9be468
Author: Markus Koschany <apo at gambaru.de>
Date:   Sat Mar 7 07:09:38 2015 +0100

    Imported Upstream version 3.9.2
---
 features/org.python.pydev.feature/feature.xml      |   40 +-
 features/org.python.pydev.feature/pom.xml          |    2 +-
 features/org.python.pydev.mylyn.feature/pom.xml    |    2 +-
 features/org.python.pydev.p2-repo/pom.xml          |    2 +-
 features/pom.xml                                   |    2 +-
 .../com.python.pydev.analysis/META-INF/MANIFEST.MF |    2 +-
 plugins/com.python.pydev.analysis/pom.xml          |    2 +-
 .../analysis/AbstractAnalysisPreferences.java      |   39 +-
 .../analysis/AnalysisPreferenceInitializer.java    |    2 +-
 .../python/pydev/analysis/AnalysisPreferences.java |   98 +-
 .../CtxInsensitiveImportComplProposal.java         |   14 +-
 .../pydev/analysis/IAnalysisPreferences.java       |    9 +-
 .../analysis/PyAnalysisScopedPreferences.java      |   41 +
 .../analysis/builder/AnalysisBuilderRunnable.java  |    8 +-
 .../analysis/builder/AnalysisParserObserver.java   |    2 +-
 .../AbstractAnalysisMarkersParticipants.java       |    2 +-
 .../pydev/analysis/ui/AnalysisPreferencesPage.java |   29 +-
 .../org/python/pydev/builder/pep8/Pep8Visitor.java |   12 +-
 .../pydev/analysis/AnalysisPreferencesStub.java    |    9 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 plugins/com.python.pydev.codecompletion/pom.xml    |    2 +-
 .../ctxinsensitive/PyConsoleCompletion.java        |    3 +-
 .../simpleassist/SimpleAssistProposal.java         |   20 +-
 .../com.python.pydev.debug/META-INF/MANIFEST.MF    |    2 +-
 plugins/com.python.pydev.debug/pom.xml             |    2 +-
 .../console/EvaluationConsoleInputListener.java    |   11 +-
 .../pydev/debug/ui/DebugPreferencesPageExt.java    |    2 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 plugins/com.python.pydev.fastparser/pom.xml        |    2 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 plugins/com.python.pydev.refactoring/pom.xml       |    2 +-
 .../wizards/rename/MatchImportsVisitor.java        |    7 +-
 .../wizards/rename/PyRenameEntryPoint.java         |   87 +-
 .../wizards/rename/PyRenameImportProcess.java      |   10 +
 .../wizards/rename/PyRenameRefactoringWizard.java  |  150 +-
 .../changes/PyRenameResourceChangeTest.java        |    6 +-
 .../rename/RefactoringRenameTestBase.java          |   17 +-
 .../rename/RenameBuiltinRefactoringTest.java       |    2 +-
 .../rename/RenameFunctionRefactoringTest2.java     |    4 +-
 .../rename/RenameModuleRefactoringTest.java        |    2 +
 .../pysrcrefactoring/reflib/renamemodule4/mymod.py |    5 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 .../RUN ON RELEASE AllWorkbenchTests.launch        |    9 +-
 plugins/com.python.pydev.runalltests/pom.xml       |    2 +-
 plugins/com.python.pydev/META-INF/MANIFEST.MF      |    2 +-
 plugins/com.python.pydev/pom.xml                   |    2 +-
 .../interactiveconsole/EvaluateActionSetter.java   |    9 +-
 plugins/org.python.pydev.ast/META-INF/MANIFEST.MF  |    2 +-
 plugins/org.python.pydev.ast/pom.xml               |    2 +-
 plugins/org.python.pydev.core/META-INF/MANIFEST.MF |    5 +-
 plugins/org.python.pydev.core/pom.xml              |    2 +-
 .../src/org/python/pydev/core/IIndentPrefs.java    |   10 +-
 .../python/pydev/core/IPyFormatStdProvider.java    |    4 +-
 .../src/org/python/pydev/core/IPythonNature.java   |    3 +-
 .../org/python/pydev/core/ITabChangedListener.java |   12 +
 .../pydev/core/docutils/PyImportsIterator.java     |    4 +-
 .../pydev/core/docutils/PyImportsHandlingTest.java |   34 +
 .../core/docutils/StringSubstitutionTest.java      |    5 +
 .../META-INF/MANIFEST.MF                           |    2 +-
 plugins/org.python.pydev.customizations/pom.xml    |    2 +-
 .../org.python.pydev.debug/META-INF/MANIFEST.MF    |    2 +-
 .../icons/python_profile.png                       |  Bin 0 -> 559 bytes
 plugins/org.python.pydev.debug/plugin.xml          |   30 +
 plugins/org.python.pydev.debug/pom.xml             |    2 +-
 .../debug/codecoverage/PyCodeCoverageView.java     |   35 +-
 .../console/ConsoleCompletionsPageParticipant.java |   92 +-
 .../python/pydev/debug/console/PromptOverlay.java  |  327 ++
 .../PromptOverlayConsolePageParticipant.java       |   75 +
 .../PromptOverlayReplaceGlobalActionHandlers.java  |  168 +
 .../debug/console/SetBufferedOutputAction.java     |  115 +
 .../pydev/debug/console/SetLayoutAction.java       |   90 +
 .../debug/console/ShowPromptOverlayAction.java     |  140 +
 .../core/PydevDebugPreferencesInitializer.java     |   11 +
 .../debug/curr_exception/CurrentExceptionView.java |    2 +-
 .../CurrentExceptionViewContentProvider.java       |    2 +-
 .../EditIgnoredCaughtExceptions.java               |    2 +-
 .../EditIgnoredCaughtExceptionsDialog.java         |    2 +-
 .../IgnoreCaughtExceptionCommandHandler.java       |    2 +-
 .../python/pydev/debug/model/CaughtException.java  |    2 +-
 .../IgnoreCaughtExceptionsWhenThrownFrom.java      |    2 +-
 .../org/python/pydev/debug/model/PyStackFrame.java |   11 +-
 .../model/remote/AddIgnoreThrownExceptionIn.java   |    2 +-
 .../pydev/debug/model/remote/ListenConnector.java  |    2 +-
 .../python/pydev/debug/profile/ProfileView.java    |   96 +
 .../pydev/debug/profile/PyProfilePreferences.java  |  169 +
 .../python/pydev/debug/pyunit/PyUnitServer.java    |   39 +-
 .../pydev/debug/pyunit/PyUnitTestResult.java       |    7 +-
 .../python/pydev/debug/ui/PythonSourceViewer.java  |    2 +-
 .../pydev/debug/ui/SourceLocatorPrefsPage.java     |    2 +-
 .../debug/ui/launching/AbstractLaunchShortcut.java |    2 +-
 .../debug/ui/launching/PythonRunnerConfig.java     |   10 +
 .../debug/newconsole/AnyPyStackFrameSelected.java  |  106 +
 .../newconsole/CurrentPyStackFrameForConsole.java  |   41 +
 .../newconsole/EvaluateDebugConsoleExpression.java |   23 +-
 .../debug/newconsole/HandleBackspaceAction.java    |    2 +-
 .../debug/newconsole/IPyStackFrameProvider.java    |   10 +
 .../pydev/debug/newconsole/PydevConsole.java       |   11 +-
 .../newconsole/PydevConsoleCommunication.java      |   17 +-
 .../debug/newconsole/PydevConsoleConstants.java    |    6 +
 .../debug/newconsole/PydevConsoleFactory.java      |   64 +-
 .../debug/newconsole/PydevConsoleInterpreter.java  |   27 +
 .../PydevConsolePreferencesInitializer.java        |    6 +
 .../newconsole/PydevDebugConsoleCommunication.java |   30 +-
 .../debug/newconsole/PydevDebugConsoleFrame.java   |   82 -
 ...ydevScriptConsoleSourceViewerConfiguration.java |  141 +-
 .../newconsole/actions/DebugConsoleAction.java     |   10 +-
 .../debug/newconsole/env/PydevIProcessFactory.java |   77 +-
 .../env/PydevSpawnedInterpreterProcess.java        |   10 +-
 .../pydev/debug/newconsole/prefs/ColorManager.java |   10 +-
 ...ctiveConsoleInitialCommandsPreferencesPage.java |   36 +
 .../newconsole/prefs/InteractiveConsolePrefs.java  |   35 +-
 .../newconsole/PydevConsoleDebugCommsTest.java     |   29 +-
 .../org.python.pydev.django/META-INF/MANIFEST.MF   |    2 +-
 plugins/org.python.pydev.django/plugin.xml         |   20 +-
 plugins/org.python.pydev.django/pom.xml            |    2 +-
 .../debug/ui/actions/DjangoMakeMigrations.java     |   39 +
 .../{DjangoSyncDB.java => DjangoMigrate.java}      |    5 +-
 .../pydev/django/debug/ui/actions/DjangoShell.java |   18 +-
 .../django/debug/ui/actions/DjangoSyncDB.java      |    1 +
 plugins/org.python.pydev.help/META-INF/MANIFEST.MF |    2 +-
 plugins/org.python.pydev.help/pom.xml              |    2 +-
 .../org.python.pydev.jython/META-INF/MANIFEST.MF   |    2 +-
 plugins/org.python.pydev.jython/pom.xml            |    2 +-
 plugins/org.python.pydev.mylyn/pom.xml             |    2 +-
 .../org.python.pydev.parser/META-INF/MANIFEST.MF   |    2 +-
 plugins/org.python.pydev.parser/pom.xml            |    2 +-
 .../python/pydev/parser/fastparser/FastParser.java |   83 +-
 .../parser/jython/ast/factory/AdapterPrefs.java    |    7 +
 .../python/pydev/parser/visitors/NodeUtils.java    |   57 +
 .../parser/PyParserEditorIntegrationTest.java      |    5 +
 .../org/python/pydev/parser/PythonNatureStub.java  |    8 +-
 .../pydev/parser/fastparser/FastParserTest.java    |   90 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 plugins/org.python.pydev.refactoring/pom.xml       |    2 +-
 .../refactoring/ast/adapters/ClassDefAdapter.java  |    5 +-
 .../ast/adapters/FunctionDefAdapter.java           |    6 +-
 .../ast/visitors/rewriter/Rewriter.java            |    2 +-
 .../refactoring/core/base/RefactoringInfo.java     |    2 +-
 .../tests/adapter/PythonNatureStub.java            |    5 +
 plugins/org.python.pydev.shared_core/.classpath    |    1 +
 .../META-INF/MANIFEST.MF                           |   20 +-
 .../org.python.pydev.shared_core/build.properties  |    4 +-
 plugins/org.python.pydev.shared_core/pom.xml       |    2 +-
 .../python/pydev/shared_core/net/SocketUtil.java   |  111 +-
 .../preferences/IScopedPreferences.java            |   82 +
 .../shared_core/preferences}/NullPrefsStore.java   |   14 +-
 .../shared_core/preferences/ScopedPreferences.java |  521 +++
 .../resource_stubs/AbstractIContainerStub.java     |    2 +-
 .../resource_stubs/AbstractIFileStub.java          |    4 +-
 .../resource_stubs/AbstractIFolderStub.java        |    2 +-
 .../resource_stubs/AbstractIProjectStub.java       |    2 +-
 .../resource_stubs/AbstractIResourceStub.java      |    4 +-
 .../resource_stubs/AbstractIWorkspaceRootStub.java |    2 +-
 .../shared_core}/resource_stubs/FileMock.java      |    2 +-
 .../pydev/shared_core/resource_stubs/FileStub.java |  145 +
 .../shared_core}/resource_stubs/FolderMock.java    |    2 +-
 .../shared_core/resource_stubs}/FolderStub.java    |   17 +-
 .../shared_core}/resource_stubs/ProjectMock.java   |    7 +-
 .../shared_core/resource_stubs}/ProjectStub.java   |   33 +-
 .../resource_stubs}/WorkingSetStub.java            |    2 +-
 .../resource_stubs}/WorkspaceRootStub.java         |    6 +-
 .../shared_core/resource_stubs}/WorkspaceStub.java |    2 +-
 .../preferences/ScopedPreferencesTest.java         |  126 +
 .../META-INF/MANIFEST.MF                           |    2 +-
 .../pom.xml                                        |    2 +-
 .../console/IScriptConsoleCommunication.java       |    5 +
 .../console/IScriptConsoleInterpreter.java         |    2 +
 .../ScriptConsolePreferenceInitializer.java        |    2 +-
 .../console/ui/IScriptConsoleListener.java         |    4 +-
 .../console/ui/ScriptConsole.java                  |   54 +-
 .../console/ui/internal/ICommandHandler.java       |    2 +
 .../ui/internal/ScriptConsoleDocumentListener.java |   11 +
 .../console/ui/internal/ScriptConsolePage.java     |    2 +-
 .../console/ui/internal/ScriptConsoleViewer.java   |   17 +-
 .../META-INF/MANIFEST.MF                           |    2 +-
 .../icons/console_disabled.png                     |  Bin 0 -> 556 bytes
 .../icons/console_enabled.png                      |  Bin 0 -> 609 bytes
 plugins/org.python.pydev.shared_ui/pom.xml         |    2 +-
 .../src/org/python/pydev/shared_ui/ColorCache.java |    6 +-
 .../org/python/pydev/shared_ui/EditorUtils.java    |   28 +
 .../src/org/python/pydev/shared_ui/ImageCache.java |  229 +-
 .../org/python/pydev/shared_ui/SharedUiPlugin.java |   15 +-
 .../org/python/pydev/shared_ui/UIConstants.java    |    3 +
 .../debug/ConsoleRestartLaunchPageParticipant.java |    3 +
 .../pydev/shared_ui/dialogs/DialogHelpers.java     |   27 +
 .../shared_ui}/dialogs/ProjectSelectionDialog.java |   52 +-
 .../shared_ui/dialogs/SelectElementDialog.java     |    6 +-
 .../field_editors/BooleanFieldEditorCustom.java    |   16 +
 .../shared_ui/field_editors}/ComboFieldEditor.java |   17 +-
 .../field_editors/FileFieldEditorCustom.java       |   54 +
 .../field_editors/RadioGroupFieldEditor.java       |  357 ++
 .../ScopedFieldEditorPreferencePage.java           |  303 ++
 .../ScopedPreferencesFieldEditor.java              |  325 ++
 .../org/python/pydev/shared_ui/utils/UIUtils.java  |   10 +-
 .../pydev/overview_ruler/MinimapOverviewRuler.java |    4 +
 .../MinimapPreferenceInitializer.java              |    2 +-
 .../StyledTextWithoutVerticalBar.java              |    2 +-
 .../org.python.pydev.shared_ui/win32/listtasks.exe |  Bin 102400 -> 0 bytes
 plugins/org.python.pydev/META-INF/MANIFEST.MF      |    2 +-
 plugins/org.python.pydev/icons/python_file.gif     |  Bin 571 -> 552 bytes
 plugins/org.python.pydev/plugin.xml                |   13 +-
 plugins/org.python.pydev/pom.xml                   |    2 +-
 .../pysrc/_pydev_imps/_pydev_pluginbase.py         |   67 +-
 plugins/org.python.pydev/pysrc/_pydev_threading.py |    6 +-
 plugins/org.python.pydev/pysrc/interpreterInfo.py  |   28 +-
 .../org.python.pydev/pysrc/pydev_console_utils.py  |   76 +-
 .../org.python.pydev/pysrc/pydev_import_hook.py    |   37 +
 .../pysrc/pydev_ipython/matplotlibtools.py         |  130 +
 .../pysrc/pydev_ipython_console_011.py             |   20 +-
 plugins/org.python.pydev/pysrc/pydev_monkey.py     |  168 +-
 plugins/org.python.pydev/pysrc/pydev_monkey_qt.py  |   39 +-
 .../org.python.pydev/pysrc/pydev_run_in_console.py |    2 +
 .../pysrc/pydev_runfiles_pytest2.py                |   23 +-
 .../pysrc/pydev_runfiles_xml_rpc.py                |    4 +
 plugins/org.python.pydev/pysrc/pydevconsole.py     |   53 +-
 plugins/org.python.pydev/pysrc/pydevd.py           |  182 +-
 .../add_code_to_python_process.py                  | 1146 +++---
 .../pydevd_attach_to_process/attach_script.py      |    2 +
 .../pydevd_attach_to_process/attach_x86.dylib      |  Bin 0 -> 18000 bytes
 .../pydevd_attach_to_process/attach_x86_64.dylib   |  Bin 0 -> 18092 bytes
 .../pysrc/pydevd_attach_to_process/linux/Makefile  |   64 +
 .../pydevd_attach_to_process/linux/attach_linux.c  |   49 +-
 .../pydevd_attach_to_process/linux/compile_mac.sh  |    8 +
 .../pydevd_attach_to_process/linux/lldb_prepare.py |   54 +
 .../linux/lldb_threads_settrace.py                 |   52 +
 .../pysrc/pydevd_attach_to_process/linux/python.h  | 1151 +++---
 plugins/org.python.pydev/pysrc/pydevd_comm.py      |   68 +-
 plugins/org.python.pydev/pysrc/pydevd_console.py   |   42 +-
 plugins/org.python.pydev/pysrc/pydevd_constants.py |   37 +-
 .../org.python.pydev/pysrc/pydevd_file_utils.py    |    4 +-
 plugins/org.python.pydev/pysrc/pydevd_frame.py     |   17 +-
 plugins/org.python.pydev/pysrc/pydevd_io.py        |    2 +
 plugins/org.python.pydev/pysrc/pydevd_referrers.py |    2 +
 plugins/org.python.pydev/pysrc/pydevd_resolver.py  |   42 +-
 plugins/org.python.pydev/pysrc/pydevd_utils.py     |   16 +-
 plugins/org.python.pydev/pysrc/pydevd_vars.py      |  189 +-
 plugins/org.python.pydev/pysrc/pydevd_xml.py       |    7 +
 plugins/org.python.pydev/pysrc/runfiles.py         |   93 +-
 .../pysrc/tests/test_check_pydevconsole.py         |   47 +-
 .../pysrc/tests/test_get_referrers.py              |    8 +-
 .../pysrc/tests/test_pydev_ipython_011.py          |   76 +-
 .../pysrc/tests/test_pydevconsole.py               |   64 +-
 .../org.python.pydev/pysrc/tests/test_pyserver.py  |    7 +-
 .../pysrc/tests/test_simpleTipper.py               |   97 +-
 .../pysrc/tests_python/_debugger_case17a.py        |   15 +
 .../pysrc/tests_python/test_debugger.py            |  135 +-
 .../pysrc/tests_python/test_pydev_monkey.py        |  100 +-
 .../pysrc/third_party/pep8/autopep8.py             | 3687 ++++++++++++++++++++
 .../src/org/python/pydev/builder/PyDevBuilder.java |   19 +-
 .../python/pydev/builder/PyDevBuilderPrefPage.java |    2 +-
 .../python/pydev/builder/PyDevBuilderVisitor.java  |   50 +-
 .../python/pydev/builder/PyDevDeltaCounter.java    |   15 +-
 .../python/pydev/builder/PydevGrouperVisitor.java  |   89 +-
 .../builder/PydevInternalResourceDeltaVisitor.java |   73 +-
 .../org/python/pydev/compare/PyMergeViewer.java    |   30 +-
 .../src/org/python/pydev/editor/PyEdit.java        |  127 +-
 .../editor/PyEditConfigurationWithoutEditor.java   |   45 +-
 .../pydev/editor/actions/PyAddBlockComment.java    |    2 +-
 .../python/pydev/editor/actions/PyBackspace.java   |   16 +-
 .../pydev/editor/actions/PyConvertSpaceToTab.java  |   33 +-
 .../pydev/editor/actions/PyConvertTabToSpace.java  |   17 +-
 .../python/pydev/editor/actions/PyFormatStd.java   |   30 +-
 .../pydev/editor/actions/PyMoveLineAction.java     |   62 +-
 .../pydev/editor/actions/PyOrganizeImports.java    |   13 +-
 .../python/pydev/editor/actions/PyPeerLinker.java  |   15 +-
 .../pydev/editor/actions/PyRemoveBlockComment.java |    2 +-
 .../actions/organize_imports/ImportArranger.java   |   33 +-
 .../organize_imports/Pep8ImportArranger.java       |    9 +-
 .../pydev/editor/autoedit/DefaultIndentPrefs.java  |  148 +-
 .../editor/autoedit/PyAutoIndentStrategy.java      |    8 +-
 .../pydev/editor/autoedit/TestIndentPrefs.java     |   12 +
 .../IgnoreCompletionProposalInSameLine.java        |    5 +-
 .../docstrings/AssistDocString.java                |    5 +-
 .../heuristics/AssistSurroundWith.java             |   29 +-
 .../org/python/pydev/editor/hover/PyTextHover.java |   22 +-
 .../editor/preferences/PyScopedPreferences.java    |   39 +
 .../editor/preferences/PyTabPreferencesPage.java   |   45 +
 .../pydev/editor/preferences/PydevEditorPrefs.java |   29 +-
 .../pydev/editor/preferences/PydevTypingPrefs.java |  186 +-
 .../editor/refactoring/IPyRefactoringRequest.java  |   11 +-
 .../ModuleRenameRefactoringRequest.java            |    2 +-
 .../editor/refactoring/PyRefactoringRequest.java   |   53 +-
 .../editor/refactoring/RefactoringRequest.java     |   66 +-
 .../saveactions/PydevSaveActionsPrefPage.java      |   72 +-
 .../pydev/editorinput/PySourceLocatorBase.java     |  198 +-
 .../python/pydev/plugin/nature/PythonNature.java   |    8 +
 .../pydev/plugin/nature/SystemPythonNature.java    |    5 +
 .../plugin/preferences/AbstractPydevPrefs.java     |   80 +-
 .../plugin/preferences/PyCodeFormatterPage.java    |  136 +-
 .../plugin/preferences/PydevPrefsInitializer.java  |   29 +-
 .../pydev/pyunit/preferences/PyUnitPrefsPage2.java |    2 +-
 .../src/org/python/pydev/runners/SimpleRunner.java |    2 +
 .../actions/container/PyOrganizeImportsAction.java |   25 +-
 .../python/pydev/ui/dialogs/PyDialogHelpers.java   |    4 +
 .../ui/importsconf/ImportsPreferencesPage.java     |   91 +-
 .../OverrideMethodCompletionProposal.java          |    2 +-
 .../codecompletion/revisited/PythonPathHelper.java |   19 +
 .../templates/PyDocumentTemplateContext.java       |    2 +-
 .../navigator/actions/PyRenameResourceAction.java  |   38 +-
 .../navigator/actions/copied/PasteAction.java      |    2 +-
 .../eclipseresourcestubs/FileResourceStub.java     |    2 +-
 .../pydev/editor/PyAutoIndentStrategyTest.java     |   11 +-
 .../editor/actions/PyOrganizeImportsTest.java      |    5 +
 .../heuristics/AssistSurroundWithTest.java         |   54 +
 .../pydev/ironpythontests/IronpythonTest.java      |    2 +-
 .../org/python/pydev/plugin/nature/FileStub2.java  |    2 +-
 .../python/pydev/plugin/nature/ProjectStub2.java   |    2 +-
 .../PythonCompletionWithoutBuiltinsTest.java       |   12 +
 .../codecompletion/revisited/ProjectStub.java      |    2 +-
 .../revisited/PyCodeCompletionVisitorTest.java     |    6 +-
 .../ScriptConsoleDocumentListenerTest.java         |   45 +-
 .../org/python/pydev/navigator/FileStub.java       |   79 -
 .../pydev/navigator/PythonModelProviderTest.java   |    5 +
 plugins/pom.xml                                    |    2 +-
 pom.xml                                            |   36 +-
 315 files changed, 13190 insertions(+), 3307 deletions(-)

diff --git a/features/org.python.pydev.feature/feature.xml b/features/org.python.pydev.feature/feature.xml
index 33059d2..94dc59d 100644
--- a/features/org.python.pydev.feature/feature.xml
+++ b/features/org.python.pydev.feature/feature.xml
@@ -6,7 +6,7 @@ build matches when doing a replace (so, the version of the xml has some extra sp
 <feature
       id="org.python.pydev.feature"
       label="PyDev for Eclipse"
-      version="3.9.0.qualifier"
+      version="3.9.2.qualifier"
       provider-name="Aptana"
       plugin="org.python.pydev">
 
@@ -130,114 +130,114 @@ This Agreement is governed by the laws of the State of New York and the intellec
          id="org.python.pydev.core"
          download-size="188"
          install-size="188"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.parser"
          download-size="444"
          install-size="444"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.ast"
          download-size="20"
          install-size="20"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.jython"
          download-size="4280"
          install-size="4280"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.help"
          download-size="300"
          install-size="300"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev"
          download-size="2440"
          install-size="2440"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.debug"
          download-size="1350"
          install-size="1350"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.refactoring"
          download-size="504"
          install-size="504"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.customizations"
          download-size="300"
          install-size="300"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.django"
          download-size="300"
          install-size="300"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev"
          download-size="824"
          install-size="824"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev.analysis"
          download-size="240"
          install-size="240"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev.fastparser"
          download-size="40"
          install-size="40"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev.codecompletion"
          download-size="60"
          install-size="60"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev.debug"
          download-size="56"
          install-size="56"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="com.python.pydev.refactoring"
          download-size="160"
          install-size="160"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.shared_interactive_console"
          download-size="160"
          install-size="160"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.shared_ui"
          download-size="160"
          install-size="160"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
    <plugin
          id="org.python.pydev.shared_core"
          download-size="160"
          install-size="160"
-         version="3.9.0.qualifier"/>
+         version="3.9.2.qualifier"/>
 
 </feature>
diff --git a/features/org.python.pydev.feature/pom.xml b/features/org.python.pydev.feature/pom.xml
index 853b438..70ab85b 100644
--- a/features/org.python.pydev.feature/pom.xml
+++ b/features/org.python.pydev.feature/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>features</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/features/org.python.pydev.mylyn.feature/pom.xml b/features/org.python.pydev.mylyn.feature/pom.xml
index 56a503a..caef085 100644
--- a/features/org.python.pydev.mylyn.feature/pom.xml
+++ b/features/org.python.pydev.mylyn.feature/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>features</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/features/org.python.pydev.p2-repo/pom.xml b/features/org.python.pydev.p2-repo/pom.xml
index e5e107a..a938d2e 100644
--- a/features/org.python.pydev.p2-repo/pom.xml
+++ b/features/org.python.pydev.p2-repo/pom.xml
@@ -19,7 +19,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>features</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
 
diff --git a/features/pom.xml b/features/pom.xml
index c88ab18..27dd130 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -16,7 +16,7 @@
   <parent>
    <groupId>org.python.pydev</groupId>
    <artifactId>parent</artifactId>
-   <version>3.9.0-SNAPSHOT</version>
+   <version>3.9.2-SNAPSHOT</version>
    <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>features</artifactId>
diff --git a/plugins/com.python.pydev.analysis/META-INF/MANIFEST.MF b/plugins/com.python.pydev.analysis/META-INF/MANIFEST.MF
index be8e722..a6f5b80 100644
--- a/plugins/com.python.pydev.analysis/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.analysis/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Analysis Plug-in
 Bundle-SymbolicName: com.python.pydev.analysis; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.analysis.AnalysisPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev.analysis/pom.xml b/plugins/com.python.pydev.analysis/pom.xml
index ceeadc1..7147d1a 100644
--- a/plugins/com.python.pydev.analysis/pom.xml
+++ b/plugins/com.python.pydev.analysis/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AbstractAnalysisPreferences.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AbstractAnalysisPreferences.java
index 84f161e..b9a8699 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AbstractAnalysisPreferences.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AbstractAnalysisPreferences.java
@@ -11,28 +11,27 @@ import java.util.Map;
 
 public abstract class AbstractAnalysisPreferences implements IAnalysisPreferences {
 
-    private volatile Map<Integer, String> typeToIgnoreMessage;
+    private static final Map<Integer, String> typeToIgnoreMessage = new HashMap<Integer, String>();
+    static {
+        typeToIgnoreMessage.put(TYPE_UNUSED_IMPORT, MSG_TO_IGNORE_TYPE_UNUSED_IMPORT);
+        typeToIgnoreMessage.put(TYPE_UNUSED_VARIABLE, MSG_TO_IGNORE_TYPE_UNUSED_VARIABLE);
+        typeToIgnoreMessage.put(TYPE_UNUSED_PARAMETER, MSG_TO_IGNORE_TYPE_UNUSED_PARAMETER);
+        typeToIgnoreMessage.put(TYPE_UNDEFINED_VARIABLE, MSG_TO_IGNORE_TYPE_UNDEFINED_VARIABLE);
+        typeToIgnoreMessage.put(TYPE_DUPLICATED_SIGNATURE, MSG_TO_IGNORE_TYPE_DUPLICATED_SIGNATURE);
+        typeToIgnoreMessage.put(TYPE_REIMPORT, MSG_TO_IGNORE_TYPE_REIMPORT);
+        typeToIgnoreMessage.put(TYPE_UNRESOLVED_IMPORT, MSG_TO_IGNORE_TYPE_UNRESOLVED_IMPORT);
+        typeToIgnoreMessage.put(TYPE_NO_SELF, MSG_TO_IGNORE_TYPE_NO_SELF);
+        typeToIgnoreMessage.put(TYPE_UNUSED_WILD_IMPORT, MSG_TO_IGNORE_TYPE_UNUSED_WILD_IMPORT);
+        typeToIgnoreMessage.put(TYPE_UNDEFINED_IMPORT_VARIABLE, MSG_TO_IGNORE_TYPE_UNDEFINED_IMPORT_VARIABLE);
+        typeToIgnoreMessage.put(TYPE_NO_EFFECT_STMT, MSG_TO_IGNORE_TYPE_NO_EFFECT_STMT);
+        typeToIgnoreMessage.put(TYPE_INDENTATION_PROBLEM, MSG_TO_IGNORE_TYPE_INDENTATION_PROBLEM);
+        typeToIgnoreMessage.put(TYPE_ASSIGNMENT_TO_BUILT_IN_SYMBOL,
+                MSG_TO_IGNORE_TYPE_ASSIGNMENT_TO_BUILT_IN_SYMBOL);
+        typeToIgnoreMessage.put(TYPE_PEP8, MSG_TO_IGNORE_TYPE_PEP8);
+        typeToIgnoreMessage.put(TYPE_ARGUMENTS_MISATCH, MSG_TO_IGNORE_TYPE_ARGUMENTS_MISATCH);
+    }
 
     public String getRequiredMessageToIgnore(int type) {
-        if (typeToIgnoreMessage == null) {
-            typeToIgnoreMessage = new HashMap<Integer, String>();
-            typeToIgnoreMessage.put(TYPE_UNUSED_IMPORT, MSG_TO_IGNORE_TYPE_UNUSED_IMPORT);
-            typeToIgnoreMessage.put(TYPE_UNUSED_VARIABLE, MSG_TO_IGNORE_TYPE_UNUSED_VARIABLE);
-            typeToIgnoreMessage.put(TYPE_UNUSED_PARAMETER, MSG_TO_IGNORE_TYPE_UNUSED_PARAMETER);
-            typeToIgnoreMessage.put(TYPE_UNDEFINED_VARIABLE, MSG_TO_IGNORE_TYPE_UNDEFINED_VARIABLE);
-            typeToIgnoreMessage.put(TYPE_DUPLICATED_SIGNATURE, MSG_TO_IGNORE_TYPE_DUPLICATED_SIGNATURE);
-            typeToIgnoreMessage.put(TYPE_REIMPORT, MSG_TO_IGNORE_TYPE_REIMPORT);
-            typeToIgnoreMessage.put(TYPE_UNRESOLVED_IMPORT, MSG_TO_IGNORE_TYPE_UNRESOLVED_IMPORT);
-            typeToIgnoreMessage.put(TYPE_NO_SELF, MSG_TO_IGNORE_TYPE_NO_SELF);
-            typeToIgnoreMessage.put(TYPE_UNUSED_WILD_IMPORT, MSG_TO_IGNORE_TYPE_UNUSED_WILD_IMPORT);
-            typeToIgnoreMessage.put(TYPE_UNDEFINED_IMPORT_VARIABLE, MSG_TO_IGNORE_TYPE_UNDEFINED_IMPORT_VARIABLE);
-            typeToIgnoreMessage.put(TYPE_NO_EFFECT_STMT, MSG_TO_IGNORE_TYPE_NO_EFFECT_STMT);
-            typeToIgnoreMessage.put(TYPE_INDENTATION_PROBLEM, MSG_TO_IGNORE_TYPE_INDENTATION_PROBLEM);
-            typeToIgnoreMessage.put(TYPE_ASSIGNMENT_TO_BUILT_IN_SYMBOL,
-                    MSG_TO_IGNORE_TYPE_ASSIGNMENT_TO_BUILT_IN_SYMBOL);
-            typeToIgnoreMessage.put(TYPE_PEP8, MSG_TO_IGNORE_TYPE_PEP8);
-            typeToIgnoreMessage.put(TYPE_ARGUMENTS_MISATCH, MSG_TO_IGNORE_TYPE_ARGUMENTS_MISATCH);
-        }
         return typeToIgnoreMessage.get(type);
     }
 }
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferenceInitializer.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferenceInitializer.java
index 968a542..c1b255e 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferenceInitializer.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferenceInitializer.java
@@ -91,7 +91,7 @@ public class AnalysisPreferenceInitializer extends AbstractPreferenceInitializer
 
     @Override
     public void initializeDefaultPreferences() {
-        Preferences node = new DefaultScope().getNode(DEFAULT_SCOPE);
+        Preferences node = DefaultScope.INSTANCE.getNode(DEFAULT_SCOPE);
 
         for (int i = 0; i < AnalysisPreferences.completeSeverityMap.length; i++) {
             Object[] s = AnalysisPreferences.completeSeverityMap[i];
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferences.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferences.java
index f7815c9..15529e8 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferences.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/AnalysisPreferences.java
@@ -15,28 +15,21 @@ import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.python.pydev.shared_core.preferences.IScopedPreferences;
 
 public class AnalysisPreferences extends AbstractAnalysisPreferences {
 
-    /**
-     * singleton
-     */
-    private static IAnalysisPreferences analysisPreferences;
+    private final IAdaptable projectAdaptable;
 
-    /**
-     * lock
-     */
-    public static final Object lock = new Object();
+    public AnalysisPreferences(IAdaptable projectAdaptable) {
+        this.projectAdaptable = projectAdaptable;
+    }
 
-    /**
-     * @return get the preferences for analysis based on the preferences
-     */
-    public static IAnalysisPreferences getAnalysisPreferences() {
-        if (analysisPreferences == null) {
-            analysisPreferences = new AnalysisPreferences();
-        }
-        return analysisPreferences;
+    @Override
+    public IAdaptable getProjectAdaptable() {
+        return projectAdaptable;
     }
 
     /**
@@ -82,30 +75,31 @@ public class AnalysisPreferences extends AbstractAnalysisPreferences {
             { IAnalysisPreferences.TYPE_ARGUMENTS_MISATCH, AnalysisPreferenceInitializer.SEVERITY_ARGUMENTS_MISMATCH,
                     AnalysisPreferenceInitializer.DEFAULT_SEVERITY_ARGUMENTS_MISMATCH }, };
 
-    public void clearCaches() {
-        synchronized (lock) {
-            severityTypeMapCache = null;
-        }
-    }
-
-    HashMap<Integer, Integer> severityTypeMapCache = null;
+    private HashMap<Integer, Integer> severityTypeMapCache;
+    private final Object lock = new Object();
 
     private Map<Integer, Integer> getSeverityTypeMap() {
-        synchronized (lock) {
-            if (severityTypeMapCache == null) {
-                severityTypeMapCache = new HashMap<Integer, Integer>();
-                Preferences pluginPreferences = AnalysisPlugin.getDefault().getPluginPreferences();
-
-                for (int i = 0; i < completeSeverityMap.length; i++) {
-                    Object[] s = completeSeverityMap[i];
-                    severityTypeMapCache.put((Integer) s[0], pluginPreferences.getInt((String) s[1]));
+        if (severityTypeMapCache == null) {
+            synchronized (lock) {
+                if (severityTypeMapCache == null) {
+                    //Do it lazily as it's possible we don't need it...
+                    HashMap<Integer, Integer> temp = new HashMap<Integer, Integer>();
+                    IPreferenceStore pluginPreferences = AnalysisPlugin.getDefault().getPreferenceStore();
+                    IScopedPreferences iScopedPreferences = PyAnalysisScopedPreferences.get();
+
+                    for (int i = 0; i < completeSeverityMap.length; i++) {
+                        Object[] s = completeSeverityMap[i];
+                        int v = iScopedPreferences.getInt(pluginPreferences, (String) s[1], projectAdaptable);
+                        temp.put((Integer) s[0], v);
+                    }
+
+                    //TODO: Add ARGUMENTS_MISMATCH again later on
+                    temp.put(IAnalysisPreferences.TYPE_ARGUMENTS_MISATCH, IMarker.SEVERITY_INFO); //Force it to be disabled for now!
+                    severityTypeMapCache = temp;
                 }
-
-                //TODO: Add ARGUMENTS_MISMATCH again later on
-                severityTypeMapCache.put(IAnalysisPreferences.TYPE_ARGUMENTS_MISATCH, IMarker.SEVERITY_INFO); //Force it to be disabled for now!
             }
-            return severityTypeMapCache;
         }
+        return severityTypeMapCache;
     }
 
     /**
@@ -114,14 +108,12 @@ public class AnalysisPreferences extends AbstractAnalysisPreferences {
      * @see com.python.pydev.analysis.IAnalysisPreferences#getSeverityForType(int)
      */
     public int getSeverityForType(int type) {
-        synchronized (lock) {
-            Map<Integer, Integer> severityTypeMap = getSeverityTypeMap();
-            Integer sev = severityTypeMap.get(type);
-            if (sev == null) {
-                throw new RuntimeException("Unable to get severity for: " + type);
-            }
-            return sev;
+        Map<Integer, Integer> severityTypeMap = getSeverityTypeMap();
+        Integer sev = severityTypeMap.get(type);
+        if (sev == null) {
+            throw new RuntimeException("Unable to get severity for: " + type);
         }
+        return sev;
     }
 
     /**
@@ -130,14 +122,12 @@ public class AnalysisPreferences extends AbstractAnalysisPreferences {
      * @see com.python.pydev.analysis.IAnalysisPreferences#makeCodeAnalysis()
      */
     public boolean makeCodeAnalysis() {
-        synchronized (lock) {
-            AnalysisPlugin plugin = AnalysisPlugin.getDefault();
-            if (plugin == null) {
-                return false;//in shutdown
-            }
-            Preferences pluginPreferences = plugin.getPluginPreferences();
-            return pluginPreferences.getBoolean(AnalysisPreferenceInitializer.DO_CODE_ANALYSIS);
+        AnalysisPlugin plugin = AnalysisPlugin.getDefault();
+        if (plugin == null) {
+            return false;//in shutdown
         }
+        return PyAnalysisScopedPreferences.getBoolean(AnalysisPreferenceInitializer.DO_CODE_ANALYSIS,
+                projectAdaptable);
     }
 
     /**
@@ -157,9 +147,7 @@ public class AnalysisPreferences extends AbstractAnalysisPreferences {
      */
     private Set<String> getSetOfNames(String preferencesName) {
         HashSet<String> names = new HashSet<String>();
-        Preferences pluginPreferences = AnalysisPlugin.getDefault().getPluginPreferences();
-
-        String string = pluginPreferences.getString(preferencesName);
+        String string = PyAnalysisScopedPreferences.getString(preferencesName, projectAdaptable);
         if (string != null) {
             String[] strings = string.split(",");
             for (int i = 0; i < strings.length; i++) {
@@ -187,8 +175,8 @@ public class AnalysisPreferences extends AbstractAnalysisPreferences {
      * @see com.python.pydev.analysis.IAnalysisPreferences#getWhenAnalyze()
      */
     public int getWhenAnalyze() {
-        Preferences pluginPreferences = AnalysisPlugin.getDefault().getPluginPreferences();
-        return pluginPreferences.getInt(AnalysisPreferenceInitializer.WHEN_ANALYZE);
+        return PyAnalysisScopedPreferences.getInt(AnalysisPreferenceInitializer.WHEN_ANALYZE,
+                projectAdaptable, 0);
     }
 
 }
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/CtxInsensitiveImportComplProposal.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/CtxInsensitiveImportComplProposal.java
index f97dab7..c4b6eec 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/CtxInsensitiveImportComplProposal.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/CtxInsensitiveImportComplProposal.java
@@ -11,6 +11,7 @@ package com.python.pydev.analysis;
 
 import java.util.List;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
@@ -97,13 +98,16 @@ public class CtxInsensitiveImportComplProposal extends AbstractPyCompletionPropo
      */
     public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
         IDocument document = viewer.getDocument();
+        IAdaptable projectAdaptable;
         if (viewer instanceof PySourceViewer) {
             PySourceViewer pySourceViewer = (PySourceViewer) viewer;
             PyEdit pyEdit = pySourceViewer.getEdit();
             this.indentString = pyEdit.getIndentPrefs().getIndentationString();
+            projectAdaptable = pyEdit;
         } else {
             //happens on compare editor
-            this.indentString = new DefaultIndentPrefs().getIndentationString();
+            this.indentString = new DefaultIndentPrefs(null).getIndentationString();
+            projectAdaptable = null;
         }
         //If the completion is applied with shift pressed, do a local import. Note that the user is only actually
         //able to do that if the popup menu is focused (i.e.: request completion and do a tab to focus it, instead
@@ -111,7 +115,7 @@ public class CtxInsensitiveImportComplProposal extends AbstractPyCompletionPropo
         if ((stateMask & SWT.SHIFT) != 0) {
             this.setAddLocalImport(true);
         }
-        apply(document, trigger, stateMask, offset);
+        apply(document, trigger, stateMask, offset, projectAdaptable);
     }
 
     /**
@@ -128,6 +132,10 @@ public class CtxInsensitiveImportComplProposal extends AbstractPyCompletionPropo
      * (and it could be a multi-line import)
      */
     public void apply(IDocument document, char trigger, int stateMask, int offset) {
+        apply(document, trigger, stateMask, offset, null);
+    }
+
+    public void apply(IDocument document, char trigger, int stateMask, int offset, IAdaptable projectAdaptable) {
         if (this.indentString == null) {
             throw new RuntimeException("Indent string not set (not called with a PyEdit as viewer?)");
         }
@@ -143,7 +151,7 @@ public class CtxInsensitiveImportComplProposal extends AbstractPyCompletionPropo
             ImportHandleInfo groupInto = null;
             ImportHandleInfo realImportHandleInfo = null;
 
-            boolean groupImports = ImportsPreferencesPage.getGroupImports();
+            boolean groupImports = ImportsPreferencesPage.getGroupImports(projectAdaptable);
 
             LineStartingScope previousLineThatStartsScope = null;
             PySelection ps = null;
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/IAnalysisPreferences.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/IAnalysisPreferences.java
index f537551..6cc71aa 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/IAnalysisPreferences.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/IAnalysisPreferences.java
@@ -11,6 +11,7 @@ package com.python.pydev.analysis;
 
 import java.util.Set;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.python.pydev.core.IMiscConstants;
 
 public interface IAnalysisPreferences {
@@ -99,14 +100,10 @@ public interface IAnalysisPreferences {
     Set<String> getTokensAlwaysInGlobals();
 
     /**
-     * The analysis preferences may have caches, so that we don't get all from the cache, but we must be able to clear them
-     * if something changes (if user changes the preferences).
-     */
-    void clearCaches();
-
-    /**
      * @return the message that should be in a line so that a warning of a given type is ignored. 
      * I.e.: @UnusedImport
      */
     String getRequiredMessageToIgnore(int type);
+
+    IAdaptable getProjectAdaptable();
 }
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/PyAnalysisScopedPreferences.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/PyAnalysisScopedPreferences.java
new file mode 100644
index 0000000..02ebca9
--- /dev/null
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/PyAnalysisScopedPreferences.java
@@ -0,0 +1,41 @@
+package com.python.pydev.analysis;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.python.pydev.shared_core.preferences.IScopedPreferences;
+import org.python.pydev.shared_core.preferences.ScopedPreferences;
+
+public class PyAnalysisScopedPreferences {
+
+    public static final String ANALYSIS_SCOPE = "org.python.pydev.analysis";
+
+    public static boolean getBoolean(String setting, IAdaptable projectAdaptable) {
+        return get().getBoolean(AnalysisPlugin.getDefault().getPreferenceStore(), setting, projectAdaptable);
+    }
+
+    public static String getString(String setting, IAdaptable projectAdaptable) {
+        return get().getString(AnalysisPlugin.getDefault().getPreferenceStore(), setting, projectAdaptable);
+    }
+
+    public static int getInt(String setting, IAdaptable projectAdaptable, int minVal) {
+        int ret = get().getInt(AnalysisPlugin.getDefault().getPreferenceStore(), setting, projectAdaptable);
+        if (ret < minVal) {
+            return minVal;
+        }
+        return ret;
+    }
+
+    public static String getString(String setting, IAdaptable projectAdaptable, String defaultReturn) {
+        String ret = getString(setting, projectAdaptable);
+        if (ret.isEmpty()) {
+            return defaultReturn;
+        }
+        return ret;
+    }
+
+    public static IScopedPreferences get() {
+        // Note: our bundle is com.python.pydev.analysis, but for the user it can be presented as 
+        // org.python.pydev.analysis as it's like that only because of historical reasons.
+        return ScopedPreferences.get(ANALYSIS_SCOPE);
+    }
+
+}
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisBuilderRunnable.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisBuilderRunnable.java
index 77f7a2c..72fca2d 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisBuilderRunnable.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisBuilderRunnable.java
@@ -105,6 +105,7 @@ public class AnalysisBuilderRunnable extends AbstractAnalysisBuilderRunnable {
         this.module = module;
     }
 
+    @Override
     protected void dispose() {
         super.dispose();
         this.document = null;
@@ -112,6 +113,7 @@ public class AnalysisBuilderRunnable extends AbstractAnalysisBuilderRunnable {
         this.module = null;
     }
 
+    @Override
     protected void doAnalysis() {
 
         if (!nature.startRequests()) {
@@ -137,9 +139,7 @@ public class AnalysisBuilderRunnable extends AbstractAnalysisBuilderRunnable {
             AnalysisRunner runner = new AnalysisRunner();
             checkStop();
 
-            IAnalysisPreferences analysisPreferences = AnalysisPreferences.getAnalysisPreferences();
-            //update the severities, etc.
-            analysisPreferences.clearCaches();
+            IAnalysisPreferences analysisPreferences = new AnalysisPreferences(r);
 
             boolean makeAnalysis = runner.canDoAnalysis(document) && PyDevBuilderVisitor.isInPythonPath(r) && //just get problems in resources that are in the pythonpath
                     analysisPreferences.makeCodeAnalysis();
@@ -232,7 +232,7 @@ public class AnalysisBuilderRunnable extends AbstractAnalysisBuilderRunnable {
             OccurrencesAnalyzer analyzer = new OccurrencesAnalyzer();
             checkStop();
             IMessage[] messages = analyzer.analyzeDocument(nature, module, analysisPreferences, document,
-                    this.internalCancelMonitor, DefaultIndentPrefs.get());
+                    this.internalCancelMonitor, DefaultIndentPrefs.get(this.resource));
 
             checkStop();
             if (DebugSettings.DEBUG_ANALYSIS_REQUESTS) {
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisParserObserver.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisParserObserver.java
index 5a8f0af..d0002c8 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisParserObserver.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/builder/AnalysisParserObserver.java
@@ -125,7 +125,7 @@ public class AnalysisParserObserver implements IParserObserver, IParserObserver3
             }
         }
 
-        int whenAnalyze = AnalysisPreferences.getAnalysisPreferences().getWhenAnalyze();
+        int whenAnalyze = new AnalysisPreferences(fileAdapter).getWhenAnalyze();
         if (whenAnalyze == IAnalysisPreferences.ANALYZE_ON_SUCCESFUL_PARSE || force) {
 
             //create the module
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ctrl_1/AbstractAnalysisMarkersParticipants.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ctrl_1/AbstractAnalysisMarkersParticipants.java
index db61d5f..70de87d 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ctrl_1/AbstractAnalysisMarkersParticipants.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ctrl_1/AbstractAnalysisMarkersParticipants.java
@@ -59,7 +59,7 @@ public abstract class AbstractAnalysisMarkersParticipants implements IAssistProp
         ArrayList<ICompletionProposal> props = new ArrayList<ICompletionProposal>();
 
         if (markersAtLine != null) {
-            IAnalysisPreferences analysisPreferences = AnalysisPreferences.getAnalysisPreferences();
+            IAnalysisPreferences analysisPreferences = new AnalysisPreferences(edit);
             String currLine = ps.getLine();
             for (MarkerAnnotationAndPosition marker : markersAtLine) {
                 for (IAnalysisMarkersParticipant participant : participants) {
diff --git a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ui/AnalysisPreferencesPage.java b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ui/AnalysisPreferencesPage.java
index a85a810..e83b8ef 100644
--- a/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ui/AnalysisPreferencesPage.java
+++ b/plugins/com.python.pydev.analysis/src/com/python/pydev/analysis/ui/AnalysisPreferencesPage.java
@@ -10,10 +10,9 @@
 package com.python.pydev.analysis.ui;
 
 import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.preference.BooleanFieldEditor;
-import org.eclipse.jface.preference.FieldEditorPreferencePage;
 import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.preference.RadioGroupFieldEditor;
 import org.eclipse.jface.preference.StringFieldEditor;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionEvent;
@@ -29,12 +28,16 @@ import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.python.pydev.debug.ui.launching.PythonRunnerConfig;
 import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LinkFieldEditor;
+import org.python.pydev.shared_ui.field_editors.RadioGroupFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
 
 import com.python.pydev.analysis.AnalysisPlugin;
 import com.python.pydev.analysis.AnalysisPreferenceInitializer;
 import com.python.pydev.analysis.IAnalysisPreferences;
+import com.python.pydev.analysis.PyAnalysisScopedPreferences;
 
-public class AnalysisPreferencesPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+public class AnalysisPreferencesPage extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
 
     public static final String USE_PEP8_CONSOLE = "USE_PEP8_CONSOLE";
     public static final boolean DEFAULT_USE_PEP8_CONSOLE = false;
@@ -58,7 +61,8 @@ public class AnalysisPreferencesPage extends FieldEditorPreferencePage implement
 
     @Override
     public void createFieldEditors() {
-        Composite p = getFieldEditorParent();
+        final Composite initialParent = getFieldEditorParent();
+        Composite p = initialParent;
 
         addField(new LabelFieldEditor(
                 "Analysis_pref_note",
@@ -192,6 +196,7 @@ public class AnalysisPreferencesPage extends FieldEditorPreferencePage implement
             }
         });
 
+        addField(new ScopedPreferencesFieldEditor(initialParent, PyAnalysisScopedPreferences.ANALYSIS_SCOPE, this));
     }
 
     /**
@@ -210,22 +215,22 @@ public class AnalysisPreferencesPage extends FieldEditorPreferencePage implement
     public void init(IWorkbench workbench) {
     }
 
-    public static String[] getPep8CommandLine() {
-        return PythonRunnerConfig.parseStringIntoList(getPep8CommandLineAsStr());
+    public static String[] getPep8CommandLine(IAdaptable projectAdaptable) {
+        return PythonRunnerConfig.parseStringIntoList(getPep8CommandLineAsStr(projectAdaptable));
     }
 
-    public static String getPep8CommandLineAsStr() {
-        return AnalysisPlugin.getDefault().getPreferenceStore().getString(PEP8_COMMAND_LINE);
+    public static String getPep8CommandLineAsStr(IAdaptable projectAdaptable) {
+        return PyAnalysisScopedPreferences.getString(PEP8_COMMAND_LINE, projectAdaptable);
     }
 
-    public static boolean useConsole() {
+    public static boolean useConsole(IAdaptable projectAdaptable) {
         if (SHOW_IN_PEP8_FEATURE_ENABLED) {
-            return AnalysisPlugin.getDefault().getPreferenceStore().getBoolean(USE_PEP8_CONSOLE);
+            return PyAnalysisScopedPreferences.getBoolean(USE_PEP8_CONSOLE, projectAdaptable);
         }
         return false;
     }
 
-    public static boolean useSystemInterpreter() {
-        return AnalysisPlugin.getDefault().getPreferenceStore().getBoolean(PEP8_USE_SYSTEM);
+    public static boolean useSystemInterpreter(IAdaptable projectAdaptable) {
+        return PyAnalysisScopedPreferences.getBoolean(PEP8_USE_SYSTEM, projectAdaptable);
     }
 }
diff --git a/plugins/com.python.pydev.analysis/src/org/python/pydev/builder/pep8/Pep8Visitor.java b/plugins/com.python.pydev.analysis/src/org/python/pydev/builder/pep8/Pep8Visitor.java
index 85ae25f..429e30e 100644
--- a/plugins/com.python.pydev.analysis/src/org/python/pydev/builder/pep8/Pep8Visitor.java
+++ b/plugins/com.python.pydev.analysis/src/org/python/pydev/builder/pep8/Pep8Visitor.java
@@ -11,6 +11,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
@@ -101,8 +102,9 @@ public class Pep8Visitor {
                 return messages;
             }
 
-            if (AnalysisPreferencesPage.useSystemInterpreter()) {
-                String parameters = AnalysisPreferencesPage.getPep8CommandLineAsStr();
+            IAdaptable projectAdaptable = prefs.getProjectAdaptable();
+            if (AnalysisPreferencesPage.useSystemInterpreter(projectAdaptable)) {
+                String parameters = AnalysisPreferencesPage.getPep8CommandLineAsStr(projectAdaptable);
                 String output = PyFormatStd.runWithPep8BaseScript(document.get(), parameters, "pep8.py", "");
                 List<String> splitInLines = StringUtils.splitInLines(output, false);
 
@@ -110,7 +112,7 @@ public class Pep8Visitor {
                     try {
                         List<String> lst = StringUtils.split(line, ':', 4);
                         int lineNumber = Integer.parseInt(lst.get(1));
-                        int offset = Integer.parseInt(lst.get(2));
+                        int offset = Integer.parseInt(lst.get(2)) - 1;
                         String text = lst.get(3);
                         this.reportError(lineNumber, offset, text, null);
                     } catch (Exception e) {
@@ -120,7 +122,7 @@ public class Pep8Visitor {
                 return messages;
             }
 
-            String[] pep8CommandLine = AnalysisPreferencesPage.getPep8CommandLine();
+            String[] pep8CommandLine = AnalysisPreferencesPage.getPep8CommandLine(projectAdaptable);
             FastStringBuffer args = new FastStringBuffer(pep8CommandLine.length * 20);
             for (String string : pep8CommandLine) {
                 args.append(',').append("r'").append(string).append('\'');
@@ -128,7 +130,7 @@ public class Pep8Visitor {
 
             //It's important that the interpreter is created in the Thread and not outside the thread (otherwise
             //it may be that the output ends up being shared, which is not what we want.)
-            boolean useConsole = AnalysisPreferencesPage.useConsole();
+            boolean useConsole = AnalysisPreferencesPage.useConsole(projectAdaptable);
             IPythonInterpreter interpreter = JythonPlugin.newPythonInterpreter(useConsole, false);
             String file = StringUtils.replaceAllSlashes(module.getFile().getAbsolutePath());
             interpreter.set("visitor", this);
diff --git a/plugins/com.python.pydev.analysis/tests/com/python/pydev/analysis/AnalysisPreferencesStub.java b/plugins/com.python.pydev.analysis/tests/com/python/pydev/analysis/AnalysisPreferencesStub.java
index 55fb0b2..18387ef 100644
--- a/plugins/com.python.pydev.analysis/tests/com/python/pydev/analysis/AnalysisPreferencesStub.java
+++ b/plugins/com.python.pydev.analysis/tests/com/python/pydev/analysis/AnalysisPreferencesStub.java
@@ -13,6 +13,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IAdaptable;
 
 public final class AnalysisPreferencesStub extends AbstractAnalysisPreferences {
     public int severityForUnusedImport;
@@ -124,12 +125,12 @@ public final class AnalysisPreferencesStub extends AbstractAnalysisPreferences {
         return names;
     }
 
-    public void clearCaches() {
-        //no caches here
-    }
-
     public int getWhenAnalyze() {
         return IAnalysisPreferences.ANALYZE_ON_SUCCESFUL_PARSE;
     }
 
+    @Override
+    public IAdaptable getProjectAdaptable() {
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/plugins/com.python.pydev.codecompletion/META-INF/MANIFEST.MF b/plugins/com.python.pydev.codecompletion/META-INF/MANIFEST.MF
index cb17259..8f86ee5 100644
--- a/plugins/com.python.pydev.codecompletion/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.codecompletion/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Codecompletion Plug-in
 Bundle-SymbolicName: com.python.pydev.codecompletion; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.codecompletion.CodecompletionPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev.codecompletion/pom.xml b/plugins/com.python.pydev.codecompletion/pom.xml
index 5977425..62db252 100644
--- a/plugins/com.python.pydev.codecompletion/pom.xml
+++ b/plugins/com.python.pydev.codecompletion/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/ctxinsensitive/PyConsoleCompletion.java b/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/ctxinsensitive/PyConsoleCompletion.java
index a95d415..3b5cbc9 100644
--- a/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/ctxinsensitive/PyConsoleCompletion.java
+++ b/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/ctxinsensitive/PyConsoleCompletion.java
@@ -6,6 +6,7 @@
  */
 package com.python.pydev.codecompletion.ctxinsensitive;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.contentassist.IContextInformation;
@@ -51,7 +52,7 @@ public class PyConsoleCompletion extends CtxInsensitiveImportComplProposal {
      * Applies the completion to the document and also updates the caret offset.
      */
     @Override
-    public void apply(IDocument document, char trigger, int stateMask, int offset) {
+    public void apply(IDocument document, char trigger, int stateMask, int offset, IAdaptable projectAdaptable) {
         if (!triggerCharAppliesCurrentCompletion(trigger, document, offset)) {
             //note: no need to walk the offset as in the other cases.
             return;
diff --git a/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/simpleassist/SimpleAssistProposal.java b/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/simpleassist/SimpleAssistProposal.java
index c857a4b..837aeb8 100644
--- a/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/simpleassist/SimpleAssistProposal.java
+++ b/plugins/com.python.pydev.codecompletion/src/com/python/pydev/codecompletion/simpleassist/SimpleAssistProposal.java
@@ -9,6 +9,7 @@ package com.python.pydev.codecompletion.simpleassist;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DocumentEvent;
 import org.eclipse.jface.text.IDocument;
@@ -80,6 +81,7 @@ public class SimpleAssistProposal extends PyCompletionProposal implements ICompl
 
     private int changeInCursorPos = 0;
 
+    @Override
     public Point getSelection(IDocument document) {
         return new Point(fReplacementOffset + fCursorPosition + changeInCursorPos, 0);
     }
@@ -88,11 +90,25 @@ public class SimpleAssistProposal extends PyCompletionProposal implements ICompl
         try {
             IDocument doc = viewer.getDocument();
             int dif = offset - fReplacementOffset;
+
+            IAdaptable projectAdaptable;
+            if (viewer instanceof IAdaptable) {
+                projectAdaptable = (IAdaptable) viewer;
+            } else {
+                projectAdaptable = new IAdaptable() {
+
+                    @Override
+                    public Object getAdapter(Class adapter) {
+                        return null;
+                    }
+                };
+            }
+
             if (fReplacementString.equals("elif")) {
                 doc.replace(offset, 0, fReplacementString.substring(dif));
 
                 //check if we should dedent
-                PyAutoIndentStrategy strategy = new PyAutoIndentStrategy();
+                PyAutoIndentStrategy strategy = new PyAutoIndentStrategy(projectAdaptable);
                 DocCmd cmd = new DocCmd(offset + fReplacementString.length() - dif, 0, " ");
                 Tuple<String, Integer> dedented = PyAutoIndentStrategy.autoDedentElif(doc, cmd,
                         strategy.getIndentPrefs());
@@ -109,7 +125,7 @@ public class SimpleAssistProposal extends PyCompletionProposal implements ICompl
                 doc.replace(offset, 0, replacementString.substring(dif));
 
                 //dedent if needed
-                PyAutoIndentStrategy strategy = new PyAutoIndentStrategy();
+                PyAutoIndentStrategy strategy = new PyAutoIndentStrategy(projectAdaptable);
                 DocCmd cmd = new DocCmd(offset + replacementString.length() - dif, 0, ":");
                 Tuple<String, Integer> dedented = PyAutoIndentStrategy.autoDedentAfterColon(doc, cmd,
                         strategy.getIndentPrefs());
diff --git a/plugins/com.python.pydev.debug/META-INF/MANIFEST.MF b/plugins/com.python.pydev.debug/META-INF/MANIFEST.MF
index d51834f..092368b 100644
--- a/plugins/com.python.pydev.debug/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Extensions Debug Plug-in
 Bundle-SymbolicName: com.python.pydev.debug; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.debug.DebugPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev.debug/pom.xml b/plugins/com.python.pydev.debug/pom.xml
index 6d3c7c1..34a3ef4 100644
--- a/plugins/com.python.pydev.debug/pom.xml
+++ b/plugins/com.python.pydev.debug/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev.debug/src/com/python/pydev/debug/console/EvaluationConsoleInputListener.java b/plugins/com.python.pydev.debug/src/com/python/pydev/debug/console/EvaluationConsoleInputListener.java
index 08b6cc0..26fb53d 100644
--- a/plugins/com.python.pydev.debug/src/com/python/pydev/debug/console/EvaluationConsoleInputListener.java
+++ b/plugins/com.python.pydev.debug/src/com/python/pydev/debug/console/EvaluationConsoleInputListener.java
@@ -38,8 +38,15 @@ public class EvaluationConsoleInputListener implements IConsoleInputListener {
                     System.out.println("Evaluating:\n" + toEval);
                 }
                 if (context instanceof PyStackFrame) {
-                    target.postCommand(new EvaluateExpressionCommand(target, toEval, ((PyStackFrame) context)
-                            .getLocalsLocator().getPyDBLocation(), true));
+                    final PyStackFrame frame = (PyStackFrame) context;
+                    target.postCommand(new EvaluateExpressionCommand(target, toEval, frame
+                            .getLocalsLocator().getPyDBLocation(), true) {
+                        @Override
+                        public void processOKResponse(int cmdCode, String payload) {
+                            frame.forceGetNewVariables();
+                            super.processOKResponse(cmdCode, payload);
+                        }
+                    });
                 }
             }
             buf = new StringBuffer();
diff --git a/plugins/com.python.pydev.debug/src/com/python/pydev/debug/ui/DebugPreferencesPageExt.java b/plugins/com.python.pydev.debug/src/com/python/pydev/debug/ui/DebugPreferencesPageExt.java
index b748263..4a07f6a 100644
--- a/plugins/com.python.pydev.debug/src/com/python/pydev/debug/ui/DebugPreferencesPageExt.java
+++ b/plugins/com.python.pydev.debug/src/com/python/pydev/debug/ui/DebugPreferencesPageExt.java
@@ -10,7 +10,7 @@ import org.eclipse.jface.preference.IntegerFieldEditor;
 import org.eclipse.swt.widgets.Composite;
 import org.python.pydev.debug.ui.DebugPrefsPage;
 import org.python.pydev.debug.ui.IDebugPreferencesPageParticipant;
-import org.python.pydev.utils.ComboFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
 
 import com.python.pydev.debug.DebugPluginPrefsInitializer;
 
diff --git a/plugins/com.python.pydev.fastparser/META-INF/MANIFEST.MF b/plugins/com.python.pydev.fastparser/META-INF/MANIFEST.MF
index 763dac7..8aae7d3 100644
--- a/plugins/com.python.pydev.fastparser/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.fastparser/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Fastparser Plug-in
 Bundle-SymbolicName: com.python.pydev.fastparser; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.fastparser.FastparserPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev.fastparser/pom.xml b/plugins/com.python.pydev.fastparser/pom.xml
index c168c5c..dfddce3 100644
--- a/plugins/com.python.pydev.fastparser/pom.xml
+++ b/plugins/com.python.pydev.fastparser/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev.refactoring/META-INF/MANIFEST.MF b/plugins/com.python.pydev.refactoring/META-INF/MANIFEST.MF
index 4462bbd..d0250d8 100644
--- a/plugins/com.python.pydev.refactoring/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.refactoring/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Refactoring Plug-in
 Bundle-SymbolicName: com.python.pydev.refactoring; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.refactoring.RefactoringPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev.refactoring/pom.xml b/plugins/com.python.pydev.refactoring/pom.xml
index 589bdab..4077e75 100644
--- a/plugins/com.python.pydev.refactoring/pom.xml
+++ b/plugins/com.python.pydev.refactoring/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/MatchImportsVisitor.java b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/MatchImportsVisitor.java
index 59d587a..6657b3d 100644
--- a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/MatchImportsVisitor.java
+++ b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/MatchImportsVisitor.java
@@ -48,6 +48,7 @@ import org.python.pydev.parser.prettyprinterv2.PrettyPrinterV2;
 import org.python.pydev.parser.visitors.NodeUtils;
 import org.python.pydev.parser.visitors.scope.ASTEntry;
 import org.python.pydev.shared_core.string.StringUtils;
+import org.python.pydev.shared_core.string.TextSelectionUtils;
 import org.python.pydev.shared_core.structure.FastStack;
 import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.shared_core.utils.ArrayUtils;
@@ -180,7 +181,7 @@ public class MatchImportsVisitor extends VisitorBase {
 
             //We'll change all
             String delimiter = PySelection.getDelimiter(doc);
-            PrettyPrinterPrefsV2 prefsV2 = PrettyPrinterV2.createDefaultPrefs(nature, DefaultIndentPrefs.get(),
+            PrettyPrinterPrefsV2 prefsV2 = PrettyPrinterV2.createDefaultPrefs(nature, DefaultIndentPrefs.get(nature),
                     delimiter);
 
             PrettyPrinterV2 prettyPrinterV2 = new PrettyPrinterV2(prefsV2);
@@ -205,6 +206,10 @@ public class MatchImportsVisitor extends VisitorBase {
                 } catch (BadLocationException e) {
                     throw new RuntimeException(e);
                 }
+                int firstCharPosition = TextSelectionUtils.getFirstCharPosition(line);
+                if (firstCharPosition > 0) {
+                    str = line.substring(0, firstCharPosition) + str;
+                }
                 TextEdit replaceEdit = new ReplaceEdit(offset, line.length(), str);
                 ret.add(replaceEdit);
             }
diff --git a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameEntryPoint.java b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameEntryPoint.java
index 7d185a4..1b69d7d 100644
--- a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameEntryPoint.java
+++ b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameEntryPoint.java
@@ -35,6 +35,7 @@ import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
 import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
 import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
 import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
+import org.eclipse.ltk.core.refactoring.resource.RenameResourceChange;
 import org.eclipse.text.edits.MultiTextEdit;
 import org.python.pydev.core.IModule;
 import org.python.pydev.core.docutils.PyStringUtils;
@@ -56,48 +57,48 @@ import com.python.pydev.refactoring.wizards.IRefactorRenameProcess;
 
 /**
  * Rename to a local variable...
- * 
+ *
  * Straightforward 'way': - find the definition and assert it is not a global - rename all occurences within that scope
- * 
+ *
  * 'Blurred things': - if we have something as:
- * 
- * case 1: 
- * 
- * def m1(): 
- *     a = 1 
- *     def m2(): 
- *         a = 3 
- *         print a 
+ *
+ * case 1:
+ *
+ * def m1():
+ *     a = 1
+ *     def m2():
+ *         a = 3
+ *         print a
  *     print a
- * 
- * case 2: 
- * 
- * def m1(): 
- *     a = 1 
- *     def m2(): 
- *         print a 
- *         a = 3 
- *         print a 
+ *
+ * case 2:
+ *
+ * def m1():
+ *     a = 1
+ *     def m2():
+ *         print a
+ *         a = 3
+ *         print a
  *     print a
- * 
- * case 3: 
- * 
- * def m1(): 
- *     a = 1 
- *     def m2(): 
- *         if foo: 
- *             a = 3 
- *         print a 
+ *
+ * case 3:
+ *
+ * def m1():
+ *     a = 1
+ *     def m2():
+ *         if foo:
+ *             a = 3
+ *         print a
  *     print a
- * 
+ *
  * if we rename it inside of m2, do we have to rename it in scope m1 too? what about renaming it in m1?
- * 
+ *
  * The solution that will be implemented will be:
- * 
- *  - if we rename it inside of m2, it will only rename inside of its scope in any case 
+ *
+ *  - if we rename it inside of m2, it will only rename inside of its scope in any case
  *  (the problem is when the rename request commes from an 'upper' scope).
- *  
- *  - if we rename it inside of m1, it will rename it in m1 and m2 only if it is used inside 
+ *
+ *  - if we rename it inside of m1, it will rename it in m1 and m2 only if it is used inside
  *  that scope before an assign this means that it will rename in m2 in case 2 and 3, but not in case 1.
  */
 public class PyRenameEntryPoint extends RenameProcessor {
@@ -158,7 +159,7 @@ public class PyRenameEntryPoint extends RenameProcessor {
      * In this method we have to check the conditions for doing the refactorings
      * and finding the definition / references that will be affected in the
      * refactoring.
-     * 
+     *
      * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
      */
     @Override
@@ -207,8 +208,8 @@ public class PyRenameEntryPoint extends RenameProcessor {
 
     /**
      * Checks all the changed file resources to cooperate with a VCS.
-     * 
-     * @throws CoreException 
+     *
+     * @throws CoreException
      */
     private static void checkResourcesToBeChanged(Set<IResource> resources,
             CheckConditionsContext context, RefactoringStatus refactoringStatus)
@@ -231,6 +232,12 @@ public class PyRenameEntryPoint extends RenameProcessor {
         RefactoringStatus status = new RefactoringStatus();
 
         try {
+            if (this.fRequest.isModuleRenameRefactoringRequest() && this.fRequest.getSimpleResourceRename()
+                    && this.fRequest.getIFileResource() != null) {
+                // Ok, simple resource change
+                return status;
+            }
+
             final Map<IPath, Tuple<TextChange, MultiTextEdit>> fileToChangeInfo = new HashMap<IPath, Tuple<TextChange, MultiTextEdit>>();
             final Set<IResource> affectedResources = new HashSet<>();
 
@@ -331,6 +338,12 @@ public class PyRenameEntryPoint extends RenameProcessor {
      */
     @Override
     public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+        if (this.fRequest.isModuleRenameRefactoringRequest() && this.fRequest.getSimpleResourceRename()
+                && this.fRequest.getIFileResource() != null) {
+            IFile targetFile = this.fRequest.getIFileResource();
+
+            return new RenameResourceChange(targetFile.getFullPath(), fRequest.getInputName());
+        }
         PyCompositeChange finalChange;
         List<RefactoringRequest> requests = fRequest.getRequests();
         if (requests.size() == 1) {
diff --git a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameImportProcess.java b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameImportProcess.java
index 814764e..e9f3062 100644
--- a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameImportProcess.java
+++ b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameImportProcess.java
@@ -63,6 +63,16 @@ public class PyRenameImportProcess extends AbstractRenameWorkspaceRefactorProces
     }
 
     @Override
+    public void findReferencesToRename(RefactoringRequest request, RefactoringStatus status) {
+        if (request.isModuleRenameRefactoringRequest() && request.getSimpleResourceRename()
+                && request.getIFileResource() != null) {
+            return;
+
+        }
+        super.findReferencesToRename(request, status);
+    }
+
+    @Override
     protected void findReferencesToRenameOnLocalScope(RefactoringRequest request, RefactoringStatus status) {
         if (request.isModuleRenameRefactoringRequest()) {
             onModuleRenameRefactoringRequest(request);
diff --git a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameRefactoringWizard.java b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameRefactoringWizard.java
index 83f67c5..39effe9 100644
--- a/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameRefactoringWizard.java
+++ b/plugins/com.python.pydev.refactoring/src/com/python/pydev/refactoring/wizards/rename/PyRenameRefactoringWizard.java
@@ -9,6 +9,7 @@
  */
 package com.python.pydev.refactoring.wizards.rename;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.preference.IPreferenceStore;
@@ -34,6 +35,7 @@ import com.python.pydev.refactoring.wizards.TextInputWizardPage;
 public class PyRenameRefactoringWizard extends RefactoringWizard {
 
     private static final String UPDATE_REFERENCES = "UPDATE_REFERENCES";
+    private static final String SIMPLE_RESOURCE_RENAME = "SIMPLE_RESOURCE_RENAME";
     private final String fInputPageDescription;
     private IPyRefactoringRequest fRequest;
     private TextInputWizardPage inputPage;
@@ -58,12 +60,16 @@ public class PyRenameRefactoringWizard extends RefactoringWizard {
         addPage(inputPage);
     }
 
-    protected TextInputWizardPage createInputPage(String message, String initialSetting) {
+    protected TextInputWizardPage createInputPage(String message, final String initialSetting) {
         return new TextInputWizardPage(message, true, initialSetting) {
+            private Text textField;
+            private IFile targetFile;
+
             @Override
             protected RefactoringStatus validateTextField(String text) {
                 RefactoringStatus status = new RefactoringStatus();
-                if (PyStringUtils.isValidIdentifier(text, fRequest.isModuleRenameRefactoringRequest())) {
+                boolean acceptPoint = fRequest.isModuleRenameRefactoringRequest();
+                if (PyStringUtils.isValidIdentifier(text, acceptPoint)) {
                     fRequest.setInputName(text);
                 } else {
                     status.addFatalError("The name: " + text + " is not a valid identifier.");
@@ -74,18 +80,55 @@ public class PyRenameRefactoringWizard extends RefactoringWizard {
             @Override
             protected Text createTextInputField(Composite parent, int style) {
                 Text ret = super.createTextInputField(parent, style);
-                String text = ret.getText();
+                this.textField = ret;
+                setTextToFullName();
+                return ret;
+            }
+
+            private void setTextToResourceName() {
+                if (targetFile != null) {
+                    String curr = targetFile.getName();
+                    textField.setText(curr);
+                    int i = curr.lastIndexOf('.');
+
+                    if (i >= 0) {
+                        textField.setSelection(0, i);
+                    } else {
+                        textField.selectAll();
+                    }
+                }
+            }
+
+            private void setTextToFullName() {
+                textField.setText(initialSetting);
+
+                String text = initialSetting;
                 int i = text.lastIndexOf('.');
                 if (i >= 0) {
-                    ret.setSelection(i + 1, text.length());
+                    textField.setSelection(i + 1, text.length());
                 } else {
-                    ret.selectAll();
+                    textField.selectAll();
                 }
-                return ret;
             }
 
             @Override
             protected void textModified(String text) {
+                if (targetFile != null && fRequest.getSimpleResourceRename()) {
+                    if (!isEmptyInputValid() && text.equals("")) { //$NON-NLS-1$
+                        setPageComplete(false);
+                        setErrorMessage(null);
+                        restoreMessage();
+                        return;
+                    }
+                    if ((!isInitialInputValid()) && text.equals(targetFile.getName())) {
+                        setPageComplete(false);
+                        setErrorMessage(null);
+                        restoreMessage();
+                        return;
+                    }
+
+                    setPageComplete(validateTextField(text));
+                }
                 if (fRequest instanceof MultiModuleMoveRefactoringRequest) {
                     RefactoringStatus status;
                     if (text.length() == 0) {
@@ -127,41 +170,86 @@ public class PyRenameRefactoringWizard extends RefactoringWizard {
                 gd.widthHint = convertWidthInCharsToPixels(25);
                 text.setLayoutData(gd);
 
-                //                layouter.perform(label, text, 1);
-                //                
+                // layouter.perform(label, text, 1);
+                //
                 if (fRequest.isModuleRenameRefactoringRequest()) {
-                    addOptionalUpdateReferencesCheckbox(composite);
+                    Button updateReferencesButton = addOptionalUpdateReferencesCheckbox(composite);
+                    IFile targetFile = fRequest.getIFileResource();
+                    if (targetFile != null) {
+                        this.targetFile = targetFile;
+                        addResourceRenameCheckbox(composite, updateReferencesButton);
+                    }
                 }
-                //                addOptionalUpdateTextualMatches(composite, layouter);
-                //                addOptionalUpdateQualifiedNameComponent(composite, layouter, layout.marginWidth);
+                // addOptionalUpdateTextualMatches(composite, layouter);
+                // addOptionalUpdateQualifiedNameComponent(composite, layouter, layout.marginWidth);
 
                 Dialog.applyDialogFont(superComposite);
             }
-        };
-    }
 
-    protected void addOptionalUpdateReferencesCheckbox(Composite result) {
-        final Button updateReferences = new Button(result, SWT.CHECK);
-        updateReferences.setText("&Update References?");
+            protected Button addResourceRenameCheckbox(Composite result, final Button updateReferencesButton) {
+                final Button resourceRename = new Button(result, SWT.CHECK);
+                resourceRename.setText("&Simple Resource Rename / Change Extension?");
 
-        IPreferenceStore preferences = PydevPrefs.getPreferences();
-        preferences.setDefault(UPDATE_REFERENCES, true);//Default is always true to update references.
-        boolean updateRefs = preferences.getBoolean(UPDATE_REFERENCES);
-        updateReferences.setSelection(updateRefs);
-        fRequest.setUpdateReferences(updateRefs);
-        updateReferences.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
                 IPreferenceStore preferences = PydevPrefs.getPreferences();
-                boolean updateRefs = updateReferences.getSelection();
-                preferences.setValue(UPDATE_REFERENCES, updateRefs);
-                fRequest.setUpdateReferences(updateRefs);
+                preferences.setDefault(SIMPLE_RESOURCE_RENAME, false); //Default is always false to rename resources.
+                boolean simpleResourceRenameBool = preferences.getBoolean(SIMPLE_RESOURCE_RENAME);
+                resourceRename.setSelection(simpleResourceRenameBool);
+                fRequest.setSimpleResourceRename(simpleResourceRenameBool);
+                resourceRename.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        IPreferenceStore preferences = PydevPrefs.getPreferences();
+                        boolean simpleResourceRenameBool = resourceRename.getSelection();
+                        updateReferencesButton.setVisible(!simpleResourceRenameBool);
+                        preferences.setValue(SIMPLE_RESOURCE_RENAME, simpleResourceRenameBool);
+                        fRequest.setSimpleResourceRename(simpleResourceRenameBool);
+
+                        // Must be the last thing.
+                        if (simpleResourceRenameBool) {
+                            setTextToResourceName();
+                        } else {
+                            setTextToFullName();
+                        }
+                    }
+
+                });
+                GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+                gridData.horizontalSpan = 2;
+                resourceRename.setLayoutData(gridData);
+                updateReferencesButton.setVisible(!simpleResourceRenameBool);
+                if (simpleResourceRenameBool) {
+                    setTextToResourceName();
+                }
+                return resourceRename;
             }
 
-        });
-        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
-        gridData.horizontalSpan = 2;
-        updateReferences.setLayoutData(gridData);
+            protected Button addOptionalUpdateReferencesCheckbox(Composite result) {
+                final Button updateReferences = new Button(result, SWT.CHECK);
+                updateReferences.setText("&Update References?");
+
+                IPreferenceStore preferences = PydevPrefs.getPreferences();
+                preferences.setDefault(UPDATE_REFERENCES, true); //Default is always true to update references.
+                boolean updateRefs = preferences.getBoolean(UPDATE_REFERENCES);
+                updateReferences.setSelection(updateRefs);
+                fRequest.setUpdateReferences(updateRefs);
+                updateReferences.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        IPreferenceStore preferences = PydevPrefs.getPreferences();
+                        boolean updateRefs = updateReferences.getSelection();
+                        preferences.setValue(UPDATE_REFERENCES, updateRefs);
+                        fRequest.setUpdateReferences(updateRefs);
+                    }
+
+                });
+                GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
+                gridData.horizontalSpan = 2;
+                updateReferences.setLayoutData(gridData);
+                return updateReferences;
+
+            }
+        };
 
     }
+
 }
diff --git a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/changes/PyRenameResourceChangeTest.java b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/changes/PyRenameResourceChangeTest.java
index dbd5236..059f0bb 100644
--- a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/changes/PyRenameResourceChangeTest.java
+++ b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/changes/PyRenameResourceChangeTest.java
@@ -6,11 +6,11 @@ import junit.framework.TestCase;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.runtime.Path;
-import org.python.pydev.navigator.FileStub;
-import org.python.pydev.navigator.FolderStub;
-import org.python.pydev.navigator.ProjectStub;
 import org.python.pydev.parser.PythonNatureStub;
 import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.resource_stubs.FileStub;
+import org.python.pydev.shared_core.resource_stubs.FolderStub;
+import org.python.pydev.shared_core.resource_stubs.ProjectStub;
 
 public class PyRenameResourceChangeTest extends TestCase {
 
diff --git a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RefactoringRenameTestBase.java b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RefactoringRenameTestBase.java
index 9573cef..44ef6c1 100644
--- a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RefactoringRenameTestBase.java
+++ b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RefactoringRenameTestBase.java
@@ -43,7 +43,6 @@ import org.python.pydev.editor.codecompletion.revisited.modules.ASTEntryWithSour
 import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule;
 import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
 import org.python.pydev.editor.refactoring.RefactoringRequest;
-import org.python.pydev.navigator.FileStub;
 import org.python.pydev.parser.jython.SimpleNode;
 import org.python.pydev.parser.jython.ast.ClassDef;
 import org.python.pydev.parser.jython.ast.FunctionDef;
@@ -51,6 +50,7 @@ import org.python.pydev.parser.visitors.scope.ASTEntry;
 import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.resource_stubs.FileStub;
 import org.python.pydev.shared_core.string.FastStringBuffer;
 import org.python.pydev.shared_core.string.StringUtils;
 import org.python.pydev.shared_core.structure.Tuple;
@@ -68,7 +68,7 @@ import com.python.pydev.refactoring.wizards.rename.TextEditCreation;
 
 /**
  * A class used for the refactorings that need the rename project (in pysrcrefactoring)
- * 
+ *
  * @author Fabio
  */
 public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase {
@@ -135,10 +135,10 @@ public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase
         setUpConfigWorkspaceFiles();
     }
 
-    private org.python.pydev.navigator.ProjectStub projectStub;
+    private org.python.pydev.shared_core.resource_stubs.ProjectStub projectStub;
 
     public void setUpConfigWorkspaceFiles() throws Exception {
-        projectStub = new org.python.pydev.navigator.ProjectStub(
+        projectStub = new org.python.pydev.shared_core.resource_stubs.ProjectStub(
                 new File(TestDependent.TEST_COM_REFACTORING_PYSRC_LOC),
                 natureRefactoring);
         TextEditCreation.createWorkspaceFile = new ICallback<IFile, File>() {
@@ -150,6 +150,7 @@ public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase
                     public IPath getFullPath() {
                         return Path.fromOSString(this.file.getAbsolutePath());
                     }
+
                 };
             }
         };
@@ -185,8 +186,8 @@ public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase
     protected abstract Class getProcessUnderTest();
 
     /**
-     * A method that creates a project that references no other project 
-     * 
+     * A method that creates a project that references no other project
+     *
      * @param force whether the creation of the new nature should be forced
      * @param path the pythonpath for the new nature
      * @param name the name for the project
@@ -206,7 +207,7 @@ public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase
 
     /**
      * Overriden so that the pythonpath is only restored for the system and the refactoring nature
-     * 
+     *
      * @param force whether this should be forced, even if it was previously created for this class
      */
     @Override
@@ -290,7 +291,7 @@ public abstract class RefactoringRenameTestBase extends RefactoringLocalTestBase
     /**
      * Goes through all the workspace (in this case the refactoring project) and gathers the references
      * for the current selection.
-     * 
+     *
      * @param moduleName the name of the module we're currently in
      * @param line the line we're in
      * @param col the col we're in
diff --git a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameBuiltinRefactoringTest.java b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameBuiltinRefactoringTest.java
index 7fa026f..0fa2b4a 100644
--- a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameBuiltinRefactoringTest.java
+++ b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameBuiltinRefactoringTest.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameFunctionRefactoringTest2.java b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameFunctionRefactoringTest2.java
index 97debfb..424a385 100644
--- a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameFunctionRefactoringTest2.java
+++ b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameFunctionRefactoringTest2.java
@@ -50,14 +50,14 @@ public class RenameFunctionRefactoringTest2 extends RefactoringRenameTestBase {
                         + "    Line: 0  class RenameFunc2: --> class new_name:\n"
                         + "\n"
                         + "reflib.renamefunction2.renamefunc2\n"
-                        + "  ASTEntry<RenameFunc2 (Name L=4 C=18)>\n"
-                        + "    Line: 3          self.bar.RenameFunc2 -->         self.bar.new_name\n"
                         + "  ASTEntry<RenameFunc2 (Name L=6 C=1)>\n"
                         + "    Line: 5  RenameFunc2.RenameFunc2 #and only the 2nd part of the access --> new_name.RenameFunc2 #and only the 2nd part of the access\n"
                         + "  ASTEntry<RenameFunc2 (NameTok L=1 C=7)>\n"
                         + "    Line: 0  class RenameFunc2: --> class new_name:\n"
                         + "  ASTEntry<RenameFunc2 (NameTok L=3 C=9)>\n"
                         + "    Line: 2      def RenameFunc2(self): #rename this method -->     def new_name(self): #rename this method\n"
+                        + "  ASTEntry<RenameFunc2 (NameTok L=4 C=18)>\n"
+                        + "    Line: 3          self.bar.RenameFunc2 -->         self.bar.new_name\n"
                         + "  ASTEntry<RenameFunc2 (NameTok L=6 C=13)>\n"
                         + "    Line: 5  RenameFunc2.RenameFunc2 #and only the 2nd part of the access --> RenameFunc2.new_name #and only the 2nd part of the access\n"
                         + "\n"
diff --git a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameModuleRefactoringTest.java b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameModuleRefactoringTest.java
index 8664694..ffe78d2 100644
--- a/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameModuleRefactoringTest.java
+++ b/plugins/com.python.pydev.refactoring/tests/com/python/pydev/refactoring/refactorer/refactorings/rename/RenameModuleRefactoringTest.java
@@ -325,6 +325,8 @@ public class RenameModuleRefactoringTest extends RefactoringRenameTestBase {
                         + "    Line: 1  a = renamemodule4 --> a = p2\n"
                         + "  ImportFromRenameAstEntry<from reflib import renamemodule4 (ImportFrom L=1 C=6)>\n"
                         + "    Line: 0  from reflib import renamemodule4 --> import p2\n"
+                        + "  ImportFromRenameAstEntry<import reflib.renamemodule4 (Import L=5 C=12)>\n"
+                        + "    Line: 4      import reflib.renamemodule4 -->     import p2\n"
                         + "\n"
                         + "", asStr);
     }
diff --git a/plugins/com.python.pydev.refactoring/tests/pysrcrefactoring/reflib/renamemodule4/mymod.py b/plugins/com.python.pydev.refactoring/tests/pysrcrefactoring/reflib/renamemodule4/mymod.py
index d6e8b0b..a49935c 100644
--- a/plugins/com.python.pydev.refactoring/tests/pysrcrefactoring/reflib/renamemodule4/mymod.py
+++ b/plugins/com.python.pydev.refactoring/tests/pysrcrefactoring/reflib/renamemodule4/mymod.py
@@ -1,2 +1,5 @@
 from reflib import renamemodule4
-a = renamemodule4
\ No newline at end of file
+a = renamemodule4
+
+if True:
+    import reflib.renamemodule4
\ No newline at end of file
diff --git a/plugins/com.python.pydev.runalltests/META-INF/MANIFEST.MF b/plugins/com.python.pydev.runalltests/META-INF/MANIFEST.MF
index 45e6fd0..4a22228 100644
--- a/plugins/com.python.pydev.runalltests/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev.runalltests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Runalltests2 Plug-in
 Bundle-SymbolicName: com.python.pydev.runalltests
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.runalltests2.Activator
 Eclipse-BundleShape: dir
 Bundle-Vendor: Aptana
diff --git a/plugins/com.python.pydev.runalltests/RUN ON RELEASE AllWorkbenchTests.launch b/plugins/com.python.pydev.runalltests/RUN ON RELEASE AllWorkbenchTests.launch
index 88cb3db..57b0317 100644
--- a/plugins/com.python.pydev.runalltests/RUN ON RELEASE AllWorkbenchTests.launch	
+++ b/plugins/com.python.pydev.runalltests/RUN ON RELEASE AllWorkbenchTests.launch	
@@ -10,7 +10,7 @@
 <booleanAttribute key="clearws" value="true"/>
 <booleanAttribute key="clearwslog" value="false"/>
 <stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
-<booleanAttribute key="default" value="false"/>
+<booleanAttribute key="default" value="true"/>
 <booleanAttribute key="includeOptional" value="true"/>
 <stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
 <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
@@ -24,16 +24,17 @@
 <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
 <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
 <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.python.pydev.runalltests2.AllWorkbenchTests"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}"/>
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.python.pydev.runalltests"/>
 <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
 <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512m"/>
 <stringAttribute key="pde.version" value="3.3"/>
-<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
+<stringAttribute key="product" value="org.eclipse.platform.ide"/>
 <booleanAttribute key="run_in_ui_thread" value="true"/>
-<stringAttribute key="selected_target_plugins" value="com.ibm.icu at default:default,com.jcraft.jsch at default:default,javax.servlet.jsp at default:default,javax.servlet at default:default,org.apache.ant at default:default,org.apache.commons.codec at default:default,org.apache.commons.el at default:default,org.apache.commons.httpclient at default:default,org.apache.commons.logging at default:default,org.apache.jasper at default:default,org.apache.lucene.analysis at default:default,org.apache.lucene at default:default,org. [...]
-<stringAttribute key="selected_workspace_plugins" value="beaver at default:default,com.amazon.s3 at default:default,com.appcelerator.titanium.aptana.editor.common.override at default:false,com.appcelerator.titanium.aptana.editor.findbar.override at default:false,com.appcelerator.titanium.aptana.git.ui.override at default:false,com.appcelerator.titanium.aptana.scripting.ui.override at default:false,com.appcelerator.titanium.aptana.ui.override at default:false,com.appcelerator.titanium.branding at default:default [...]
+<stringAttribute key="selected_target_plugins" value="com.ibm.icu at default:default,com.jcraft.jsch at default:default,javax.servlet.jsp at default:default,javax.servlet at default:default,org.apache.ant at default:default,org.apache.commons.codec at default:default,org.apache.commons.logging at default:default,org.apache.lucene.analysis at default:default,org.eclipse.ant.core at default:default,org.eclipse.ant.launching at default:default,org.eclipse.ant.ui at default:default,org.eclipse.compare.core at default:default,o [...]
+<stringAttribute key="selected_workspace_plugins" value="com.brainwy.liclipse.editor.epl at default:default,com.brainwy.liclipse.editor.html at default:default,com.brainwy.liclipse.editor.javascript.epl at default:default,com.brainwy.liclipse.editor.javascript at default:default,com.brainwy.liclipse.editor.xml at default:default,com.brainwy.liclipse.editor at default:default,com.brainwy.liclipse.help at default:default,com.brainwy.liclipse.language.editor at default:default,com.brainwy.liclipse.rcp at default:defa [...]
 <booleanAttribute key="show_selected_only" value="false"/>
 <booleanAttribute key="tracing" value="false"/>
 <booleanAttribute key="useCustomFeatures" value="false"/>
diff --git a/plugins/com.python.pydev.runalltests/pom.xml b/plugins/com.python.pydev.runalltests/pom.xml
index bac9870..0d4fd0b 100644
--- a/plugins/com.python.pydev.runalltests/pom.xml
+++ b/plugins/com.python.pydev.runalltests/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev/META-INF/MANIFEST.MF b/plugins/com.python.pydev/META-INF/MANIFEST.MF
index 17fcd37..1de0584 100644
--- a/plugins/com.python.pydev/META-INF/MANIFEST.MF
+++ b/plugins/com.python.pydev/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Pydev Extensions
 Bundle-SymbolicName: com.python.pydev; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: com.python.pydev.PydevPlugin
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
diff --git a/plugins/com.python.pydev/pom.xml b/plugins/com.python.pydev/pom.xml
index aafd194..5232848 100644
--- a/plugins/com.python.pydev/pom.xml
+++ b/plugins/com.python.pydev/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/com.python.pydev/src/com/python/pydev/interactiveconsole/EvaluateActionSetter.java b/plugins/com.python.pydev/src/com/python/pydev/interactiveconsole/EvaluateActionSetter.java
index 4dab38c..fe72142 100644
--- a/plugins/com.python.pydev/src/com/python/pydev/interactiveconsole/EvaluateActionSetter.java
+++ b/plugins/com.python.pydev/src/com/python/pydev/interactiveconsole/EvaluateActionSetter.java
@@ -20,7 +20,6 @@ import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.widgets.Display;
 import org.python.pydev.core.docutils.PySelection;
 import org.python.pydev.core.log.Log;
-import org.python.pydev.debug.newconsole.PydevConsoleConstants;
 import org.python.pydev.debug.newconsole.PydevConsoleFactory;
 import org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs;
 import org.python.pydev.editor.PyEdit;
@@ -33,7 +32,7 @@ import org.python.pydev.shared_ui.editor.IPyEditListener;
 
 /**
  * This class will setup the editor so that we can create interactive consoles, send code to it or make an execfile.
- * 
+ *
  * It is as a 'singleton' for all PyEdit editors.
  */
 public class EvaluateActionSetter implements IPyEditListener {
@@ -51,7 +50,7 @@ public class EvaluateActionSetter implements IPyEditListener {
             try {
                 PySelection selection = new PySelection(edit);
 
-                ScriptConsole console = ScriptConsole.getActiveScriptConsole(PydevConsoleConstants.CONSOLE_TYPE);
+                ScriptConsole console = ScriptConsole.getActiveScriptConsole();
 
                 if (console == null) {
                     //if no console is available, create it (if possible).
@@ -69,7 +68,7 @@ public class EvaluateActionSetter implements IPyEditListener {
 
                 } else {
                     if (console instanceof ScriptConsole) {
-                        //ok, console available 
+                        //ok, console available
                         sendCommandToConsole(selection, console, this.edit);
                     }
                 }
@@ -126,7 +125,7 @@ public class EvaluateActionSetter implements IPyEditListener {
     }
 
     /**
-     * This method associates Ctrl+new line with the evaluation of commands in the console. 
+     * This method associates Ctrl+new line with the evaluation of commands in the console.
      */
     public void onCreateActions(ListResourceBundle resources, final BaseEditor baseEditor, IProgressMonitor monitor) {
         final PyEdit edit = (PyEdit) baseEditor;
diff --git a/plugins/org.python.pydev.ast/META-INF/MANIFEST.MF b/plugins/org.python.pydev.ast/META-INF/MANIFEST.MF
index ee2511c..32c95b4 100644
--- a/plugins/org.python.pydev.ast/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.ast/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Ast Plug-in
 Bundle-SymbolicName: org.python.pydev.ast; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: ast.jar
 Bundle-Activator: org.python.pydev.ast.AstPlugin
 Bundle-Localization: plugin
diff --git a/plugins/org.python.pydev.ast/pom.xml b/plugins/org.python.pydev.ast/pom.xml
index 471bc5f..3f9bf55 100644
--- a/plugins/org.python.pydev.ast/pom.xml
+++ b/plugins/org.python.pydev.ast/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.core/META-INF/MANIFEST.MF b/plugins/org.python.pydev.core/META-INF/MANIFEST.MF
index 4b7fd51..a6c73b0 100644
--- a/plugins/org.python.pydev.core/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Core Plug-in
 Bundle-SymbolicName: org.python.pydev.core; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: core.jar
 Bundle-Activator: org.python.pydev.core.CorePlugin
 Bundle-Vendor: Aptana
@@ -23,6 +23,5 @@ Bundle-ActivationPolicy: lazy
 Export-Package: org.python.pydev.core,org.python.pydev.core.cache,org.
  python.pydev.core.concurrency,org.python.pydev.core.docutils,org.pyth
  on.pydev.core.log,org.python.pydev.core.parser,org.python.pydev.core.
- performanceeval,org.python.pydev.core.resource_stubs,org.python.pydev
- .core.structure
+ performanceeval,org.python.pydev.core.structure
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
diff --git a/plugins/org.python.pydev.core/pom.xml b/plugins/org.python.pydev.core/pom.xml
index cdc23c2..ae6caca 100644
--- a/plugins/org.python.pydev.core/pom.xml
+++ b/plugins/org.python.pydev.core/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/IIndentPrefs.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/IIndentPrefs.java
index 17c5827..c6f91b5 100644
--- a/plugins/org.python.pydev.core/src/org/python/pydev/core/IIndentPrefs.java
+++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/IIndentPrefs.java
@@ -26,13 +26,13 @@ public interface IIndentPrefs {
 
     /**
      * Sets the forceTabs preference for auto-indentation.
-     * 
+     *
      * <p>
      * This is the preference that overrides "use spaces" preference when file
      * contains tabs (like mine do).
      * <p>
      * If the first indented line starts with a tab, then tabs override spaces.
-     * 
+     *
      * @return True If tabs should be used even if it says we should use spaces.
      */
     public void setForceTabs(boolean forceTabs);
@@ -44,6 +44,8 @@ public interface IIndentPrefs {
      */
     public int getTabWidth();
 
+    public void addTabChangedListener(ITabChangedListener listener);
+
     /**
      * @return the indentation string based on the current settings.
      */
@@ -66,7 +68,7 @@ public interface IIndentPrefs {
     public boolean getAutoColon();
 
     /**
-     * Get whether or not to auto-skip braces insertion  
+     * Get whether or not to auto-skip braces insertion
      * @return if auto-skip braces is ENABLED
      */
     public boolean getAutoBraces();
@@ -120,4 +122,6 @@ public interface IIndentPrefs {
      * Should we do the link on auto-close?
      */
     public boolean getAutoLink();
+
+    public boolean getGuessTabSubstitution();
 }
diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/IPyFormatStdProvider.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/IPyFormatStdProvider.java
index 5e166b4..f08746b 100644
--- a/plugins/org.python.pydev.core/src/org/python/pydev/core/IPyFormatStdProvider.java
+++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/IPyFormatStdProvider.java
@@ -1,6 +1,8 @@
 package org.python.pydev.core;
 
-public interface IPyFormatStdProvider {
+import org.eclipse.core.runtime.IAdaptable;
+
+public interface IPyFormatStdProvider extends IAdaptable {
 
     Object /*FormatStd*/getFormatStd();
 
diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/IPythonNature.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/IPythonNature.java
index b23cb24..a0ba944 100644
--- a/plugins/org.python.pydev.core/src/org/python/pydev/core/IPythonNature.java
+++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/IPythonNature.java
@@ -17,11 +17,12 @@ import java.util.List;
 import org.eclipse.core.resources.IProjectNature;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
 
 /**
  * @author Fabio
  */
-public interface IPythonNature extends IProjectNature, IGrammarVersionProvider {
+public interface IPythonNature extends IProjectNature, IGrammarVersionProvider, IAdaptable {
 
     /**
      * Helper class to contain information about the versions
diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/ITabChangedListener.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/ITabChangedListener.java
new file mode 100644
index 0000000..77e36d1
--- /dev/null
+++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/ITabChangedListener.java
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software LTDA. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.core;
+
+public interface ITabChangedListener {
+
+    public void onTabSettingsChanged(IIndentPrefs prefs);
+}
diff --git a/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/PyImportsIterator.java b/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/PyImportsIterator.java
index 6680b47..60cede0 100644
--- a/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/PyImportsIterator.java
+++ b/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/PyImportsIterator.java
@@ -89,10 +89,10 @@ public class PyImportsIterator implements Iterator<ImportHandle> {
 
             boolean match;
             if (addOnlyGlobalImports) {
-                match = str.startsWith("import ") || str.startsWith("from ");
+                match = str.startsWith("import ") || str.startsWith("from ") || str.trim().equals("import");
             } else {
                 str = StringUtils.leftTrim(str);
-                match = str.startsWith("import ") || str.startsWith("from ");
+                match = str.startsWith("import ") || str.startsWith("from ") || str.trim().equals("import");
             }
 
             if (match) {
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/PyImportsHandlingTest.java b/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/PyImportsHandlingTest.java
index 649559a..546ec55 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/PyImportsHandlingTest.java
+++ b/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/PyImportsHandlingTest.java
@@ -134,4 +134,38 @@ public class PyImportsHandlingTest extends TestCase {
 
     }
 
+    public void testPyImportHandling6() throws Exception {
+        Document doc = new Document("from a import\n");
+        PyImportsHandling importsHandling = new PyImportsHandling(doc, false, true);
+        Iterator<ImportHandle> it = importsHandling.iterator();
+        assertTrue(it.hasNext());
+        ImportHandle next = it.next();
+
+        assertEquals("from a import", next.importFound);
+        assertEquals(1, next.getImportInfo().size());
+        assertEquals(0, next.getImportInfo().get(0).getImportedStr().size());
+        assertEquals(0, next.startFoundLine);
+        assertEquals(0, next.endFoundLine);
+
+        assertTrue(!it.hasNext());
+
+    }
+
+    public void testPyImportHandling7() throws Exception {
+        Document doc = new Document("import\n");
+        PyImportsHandling importsHandling = new PyImportsHandling(doc, false, true);
+        Iterator<ImportHandle> it = importsHandling.iterator();
+        assertTrue(it.hasNext());
+        ImportHandle next = it.next();
+
+        assertEquals("import", next.importFound);
+        assertEquals(1, next.getImportInfo().size());
+        assertEquals(0, next.getImportInfo().get(0).getImportedStr().size());
+        assertEquals(0, next.startFoundLine);
+        assertEquals(0, next.endFoundLine);
+
+        assertTrue(!it.hasNext());
+
+    }
+
 }
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/StringSubstitutionTest.java b/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/StringSubstitutionTest.java
index 469f8c6..68f546b 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/StringSubstitutionTest.java
+++ b/plugins/org.python.pydev.core/tests/org/python/pydev/core/docutils/StringSubstitutionTest.java
@@ -124,6 +124,11 @@ public class StringSubstitutionTest extends TestCase {
                 throw new RuntimeException("Not implemented");
             }
 
+            @Override
+            public Object getAdapter(Class adapter) {
+                throw new RuntimeException("Not implemented");
+            }
+
             public IInterpreterInfo getProjectInterpreter() throws MisconfigurationException,
                     PythonNatureWithoutProjectException {
                 throw new RuntimeException("Not implemented");
diff --git a/plugins/org.python.pydev.customizations/META-INF/MANIFEST.MF b/plugins/org.python.pydev.customizations/META-INF/MANIFEST.MF
index 22ac225..f41c2c0 100644
--- a/plugins/org.python.pydev.customizations/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.customizations/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Customizations Plug-in
 Bundle-SymbolicName: org.python.pydev.customizations; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: customizations.jar
 Bundle-Activator: org.python.pydev.customizations.CustomizationsPlugin
 Bundle-Localization: plugin
diff --git a/plugins/org.python.pydev.customizations/pom.xml b/plugins/org.python.pydev.customizations/pom.xml
index 06f97c3..1c7300a 100644
--- a/plugins/org.python.pydev.customizations/pom.xml
+++ b/plugins/org.python.pydev.customizations/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF b/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF
index d5b6387..b6faad5 100644
--- a/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Pydev debug
 Bundle-SymbolicName: org.python.pydev.debug; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: pydev-debug.jar,
  libs/winp-1.19.jar
 Bundle-Activator: org.python.pydev.debug.core.PydevDebugPlugin
diff --git a/plugins/org.python.pydev.debug/icons/python_profile.png b/plugins/org.python.pydev.debug/icons/python_profile.png
new file mode 100644
index 0000000..c6efb8a
Binary files /dev/null and b/plugins/org.python.pydev.debug/icons/python_profile.png differ
diff --git a/plugins/org.python.pydev.debug/plugin.xml b/plugins/org.python.pydev.debug/plugin.xml
index 862d0fc..d68f4e7 100644
--- a/plugins/org.python.pydev.debug/plugin.xml
+++ b/plugins/org.python.pydev.debug/plugin.xml
@@ -468,6 +468,12 @@
         name="Code Coverage"
         id="org.python.pydev.views.PyCodeCoverageView"/>
    <view
+        class="org.python.pydev.debug.profile.ProfileView"
+        icon="icons/python_profile.png"
+        category="org.python.pydev"
+        name="Profile"
+        id="org.python.pydev.debug.profile.ProfileView"/>
+   <view
          class="org.python.pydev.debug.referrers.ReferrersView"
          icon="icons/referrers.png"
          category="org.python.pydev"
@@ -737,12 +743,27 @@
      <initializer class="org.python.pydev.debug.newconsole.PydevConsolePreferencesInitializer"/>
   </extension>
 
+	<extension point="org.eclipse.ui.keywords" name="Interpreter Keywords">
+	    <keyword id="org.python.pydev.debug.console"  label="interactive console shell"/>
+	</extension>
+	<extension point="org.eclipse.ui.keywords" name="Interpreter Keywords">
+	    <keyword id="org.python.pydev.debug.initial_commands"  label="interactive console shell initial commands"/>
+	</extension>
+
   <extension point="org.eclipse.ui.preferencePages">
      <page
         name="Interactive Console"
         category="org.python.pydev.prefs"
         class="org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs"
         id="org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs">
+        <keywordReference id="org.python.pydev.debug.console"/>
+     </page>
+     <page
+        name="Initial Commands"
+        category="org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs"
+        class="org.python.pydev.debug.newconsole.prefs.InteractiveConsoleInitialCommandsPreferencesPage"
+        id="org.python.pydev.debug.newconsole.prefs.InteractiveConsoleInitialCommandsPreferencesPage">
+        <keywordReference id="org.python.pydev.debug.initial_commands"/>
      </page>
      <page
            category="org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs"
@@ -781,6 +802,15 @@
       </consolePageParticipant>
    </extension>
 
+   <extension
+         point="org.eclipse.ui.console.consolePageParticipants">
+      <consolePageParticipant
+            class="org.python.pydev.debug.console.PromptOverlayConsolePageParticipant"
+            id="org.python.pydev.debug.console.PromptOverlayConsolePageParticipant">
+         <enablement></enablement>
+      </consolePageParticipant>
+   </extension>
+
    <!-- Make interactive console work with debugger infractstructure for variables view, expressions... -->
    <extension
          point="org.eclipse.ui.console.consolePageParticipants">
diff --git a/plugins/org.python.pydev.debug/pom.xml b/plugins/org.python.pydev.debug/pom.xml
index ad56ce1..e6247ca 100644
--- a/plugins/org.python.pydev.debug/pom.xml
+++ b/plugins/org.python.pydev.debug/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/codecoverage/PyCodeCoverageView.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/codecoverage/PyCodeCoverageView.java
index 7a5b107..0790644 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/codecoverage/PyCodeCoverageView.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/codecoverage/PyCodeCoverageView.java
@@ -568,7 +568,7 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
 
         leftComposite = new Composite(parent, SWT.MULTI);
         layout = new GridLayout();
-        layout.numColumns = 2;
+        layout.numColumns = 3;
         layout.verticalSpacing = 2;
         layout.marginWidth = 0;
         layout.marginHeight = 2;
@@ -622,8 +622,14 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
         parent = leftComposite;
 
         //all the runs from now on go through coverage?
+        Label label = new Label(parent, SWT.None);
+        label.setText("Enable code coverage for new launches?");
+        layoutData = new GridData();
+        layoutData.grabExcessHorizontalSpace = true;
+        layoutData.horizontalAlignment = GridData.FILL;
+        label.setLayoutData(layoutData);
+
         allRunsGoThroughCoverage = new Button(parent, SWT.CHECK);
-        allRunsGoThroughCoverage.setText("Enable code coverage for new launches?");
         allRunsGoThroughCoverage.setSelection(PyCoveragePreferences.getInternalAllRunsDoCoverage());
         allRunsGoThroughCoverage.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -633,15 +639,20 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
             }
         });
         layoutData = new GridData();
-        layoutData.grabExcessHorizontalSpace = true;
-        layoutData.horizontalAlignment = GridData.FILL;
         layoutData.horizontalSpan = 2;
+        layoutData.grabExcessHorizontalSpace = false;
         allRunsGoThroughCoverage.setLayoutData(layoutData);
         //end all runs go through coverage
 
         //Clear the coverage info on each launch?
+        label = new Label(parent, SWT.None);
+        label.setText("Auto clear on a new launch?");
+        layoutData = new GridData();
+        layoutData.grabExcessHorizontalSpace = true;
+        layoutData.horizontalAlignment = GridData.FILL;
+        label.setLayoutData(layoutData);
+
         clearCoverageInfoOnNextLaunch = new Button(parent, SWT.CHECK);
-        clearCoverageInfoOnNextLaunch.setText("Auto clear on a new launch?");
         clearCoverageInfoOnNextLaunch.setSelection(PyCoveragePreferences.getClearCoverageInfoOnNextLaunch());
         clearCoverageInfoOnNextLaunch.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -652,7 +663,7 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
 
         PythonRunnerCallbacks.onCreatedCommandLine.registerListener(onCreatedCommandLineListener);
         layoutData = new GridData();
-        layoutData.grabExcessHorizontalSpace = true;
+        layoutData.grabExcessHorizontalSpace = false;
         layoutData.horizontalAlignment = GridData.FILL;
         clearCoverageInfoOnNextLaunch.setLayoutData(layoutData);
 
@@ -672,8 +683,14 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
         //end all runs go through coverage
 
         //Refresh the coverage info on each launch?
+        label = new Label(parent, SWT.None);
+        label.setText("Auto refresh on new launch?");
+        layoutData = new GridData();
+        layoutData.grabExcessHorizontalSpace = true;
+        layoutData.horizontalAlignment = GridData.FILL;
+        label.setLayoutData(layoutData);
+
         refreshCoverageInfoOnNextLaunch = new Button(parent, SWT.CHECK);
-        refreshCoverageInfoOnNextLaunch.setText("Auto refresh on new launch?");
         refreshCoverageInfoOnNextLaunch.setSelection(PyCoveragePreferences.getRefreshAfterNextLaunch());
         refreshCoverageInfoOnNextLaunch.addSelectionListener(new SelectionAdapter() {
             @Override
@@ -716,7 +733,7 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
         layoutData.grabExcessVerticalSpace = true;
         layoutData.horizontalAlignment = GridData.FILL;
         layoutData.verticalAlignment = GridData.FILL;
-        layoutData.horizontalSpan = 2;
+        layoutData.horizontalSpan = 3;
         filter.setLayoutData(layoutData);
 
         viewer = filter.getViewer();
@@ -856,7 +873,7 @@ public class PyCodeCoverageView extends ViewPartWithOrientation implements IView
         layoutData = new GridData();
         layoutData.grabExcessHorizontalSpace = true;
         layoutData.horizontalAlignment = GridData.FILL;
-        layoutData.horizontalSpan = 2;
+        layoutData.horizontalSpan = 3;
         button.setLayoutData(layoutData);
     }
 
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java
index 185a75e..87c289c 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ConsoleCompletionsPageParticipant.java
@@ -10,12 +10,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.debug.core.model.IProcess;
 import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
-import org.eclipse.debug.ui.DebugUITools;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
 import org.eclipse.swt.events.KeyEvent;
@@ -27,22 +24,20 @@ import org.eclipse.ui.console.TextConsoleViewer;
 import org.eclipse.ui.internal.console.IOConsolePage;
 import org.eclipse.ui.internal.console.IOConsolePartition;
 import org.eclipse.ui.part.IPageBookViewPage;
-import org.python.pydev.core.IInterpreterInfo;
 import org.python.pydev.core.log.Log;
 import org.python.pydev.debug.core.Constants;
 import org.python.pydev.debug.model.AbstractDebugTarget;
-import org.python.pydev.debug.model.PyDebugTarget;
 import org.python.pydev.debug.model.PyStackFrame;
 import org.python.pydev.debug.model.XMLUtils;
 import org.python.pydev.debug.model.remote.AbstractDebuggerCommand;
 import org.python.pydev.debug.model.remote.GetCompletionsCommand;
 import org.python.pydev.debug.model.remote.ICommandResponseListener;
+import org.python.pydev.debug.newconsole.CurrentPyStackFrameForConsole;
 import org.python.pydev.debug.newconsole.PydevConsoleCommunication;
 import org.python.pydev.debug.newconsole.PydevConsoleCompletionProcessor;
 import org.python.pydev.debug.newconsole.PydevConsoleInterpreter;
 import org.python.pydev.editor.codecompletion.PyCodeCompletionPreferencesPage;
 import org.python.pydev.editor.codecompletion.PyContentAssistant;
-import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.shared_interactive_console.console.IScriptConsoleCommunication;
@@ -56,45 +51,30 @@ import org.python.pydev.shared_ui.bindings.KeyBindingHelper;
 public class ConsoleCompletionsPageParticipant implements IConsolePageParticipant {
 
     /**
-     * @return the currently selected / suspended frame. If the console is passed, it will only return
-     * a frame that matches the passed console. If no selected / suspended frame is found or the console
-     * doesn't match, null is returned.
-     */
-    protected static PyStackFrame getCurrentSuspendedPyStackFrame(IConsole console) {
-        IAdaptable context = DebugUITools.getDebugContext();
-
-        if (context instanceof PyStackFrame) {
-            PyStackFrame stackFrame = (PyStackFrame) context;
-            if (!stackFrame.isTerminated() && stackFrame.isSuspended()) {
-                if (console != null) {
-                    //If a console is passed, we must check if it matches the console from the selected frame.
-                    AbstractDebugTarget target = (AbstractDebugTarget) stackFrame.getAdapter(IDebugTarget.class);
-                    if (DebugUITools.getConsole(target.getProcess()) != console) {
-                        return null;
-                    }
-                }
-
-                return stackFrame;
-            }
-        }
-        return null;
-    }
-
-    /**
      * Class to get the completions in debug mode in a suspended frame.
      */
     public static class GetCompletionsInDebug implements IScriptConsoleCommunication, ICommandResponseListener {
 
         private static final ICompletionProposal[] EMPTY_COMPLETION_PROPOSALS = new ICompletionProposal[0];
-        private ICompletionProposal[] receivedCompletions;
         private String actTok;
         private String text;
         private int offset;
+        private volatile List<Object[]> receivedXmlCompletions;
+        private CurrentPyStackFrameForConsole currentPyStackFrameForConsole;
+
+        public GetCompletionsInDebug(CurrentPyStackFrameForConsole currentPyStackFrameForConsole) {
+            this.currentPyStackFrameForConsole = currentPyStackFrameForConsole;
+        }
 
         public String getDescription(String text) throws Exception {
             throw new RuntimeException("Not implemented");
         }
 
+        @Override
+        public boolean isConnected() {
+            return this.currentPyStackFrameForConsole.getLastSelectedFrame() != null;
+        }
+
         /**
          * Gets the completions at the passed offset.
          */
@@ -103,7 +83,7 @@ public class ConsoleCompletionsPageParticipant implements IConsolePageParticipan
             this.text = text;
             this.actTok = actTok;
             this.offset = offset;
-            PyStackFrame stackFrame = getCurrentSuspendedPyStackFrame(null);
+            PyStackFrame stackFrame = currentPyStackFrameForConsole.getLastSelectedFrame();
 
             if (stackFrame != null) {
                 AbstractDebugTarget target = (AbstractDebugTarget) stackFrame.getAdapter(IDebugTarget.class);
@@ -124,7 +104,7 @@ public class ConsoleCompletionsPageParticipant implements IConsolePageParticipan
          */
         private ICompletionProposal[] waitForCommand() {
             int i = 300; //wait up to 3 seconds
-            while (--i > 0 && receivedCompletions == null) {
+            while (--i > 0 && receivedXmlCompletions == null) {
                 try {
                     Thread.sleep(10); //10 millis
                 } catch (InterruptedException e) {
@@ -132,13 +112,15 @@ public class ConsoleCompletionsPageParticipant implements IConsolePageParticipan
                 }
             }
 
-            ICompletionProposal[] temp = receivedCompletions;
-            receivedCompletions = null;
-            if (temp == null) {
+            List<Object[]> fromServer = receivedXmlCompletions;
+            receivedXmlCompletions = null;
+            if (fromServer == null) {
                 Log.logInfo("Timeout for waiting for debug completions elapsed (3 seconds).");
                 return EMPTY_COMPLETION_PROPOSALS;
             }
-            return temp;
+            List<ICompletionProposal> ret = new ArrayList<ICompletionProposal>(fromServer.size());
+            PydevConsoleCommunication.convertToICompletions(text, actTok, offset, fromServer, ret, false);
+            return ret.toArray(new ICompletionProposal[0]);
         }
 
         public void execInterpreter(String command, ICallback<Object, InterpreterResponse> onResponseReceived) {
@@ -169,11 +151,9 @@ public class ConsoleCompletionsPageParticipant implements IConsolePageParticipan
             try {
                 String response = compCmd.getResponse();
                 List<Object[]> fromServer = XMLUtils.convertXMLcompletionsFromConsole(response);
-                List<ICompletionProposal> ret = new ArrayList<ICompletionProposal>();
-                PydevConsoleCommunication.convertToICompletions(text, actTok, offset, fromServer, ret, false);
-                receivedCompletions = ret.toArray(new ICompletionProposal[ret.size()]);
+                receivedXmlCompletions = fromServer;
             } catch (CoreException e) {
-                receivedCompletions = EMPTY_COMPLETION_PROPOSALS;
+                receivedXmlCompletions = new ArrayList<>(0);
                 Log.log(e);
             }
 
@@ -234,39 +214,27 @@ public class ConsoleCompletionsPageParticipant implements IConsolePageParticipan
                 }
             });
 
+            final CurrentPyStackFrameForConsole currentPyStackFrameForConsole = new CurrentPyStackFrameForConsole(
+                    console);
             IOConsolePage consolePage = (IOConsolePage) page;
             TextConsoleViewer viewer = consolePage.getViewer();
 
+            PydevConsoleInterpreter interpreter = new PydevConsoleInterpreter();
+            interpreter.setLaunchAndRelatedInfo(process.getLaunch());
+            interpreter.setConsoleCommunication(new GetCompletionsInDebug(currentPyStackFrameForConsole));
+
             contentAssist = new PyContentAssistant() {
                 @Override
                 public String showPossibleCompletions() {
                     //Only show completions if we're in a suspended console.
-                    if (getCurrentSuspendedPyStackFrame(console) == null) {
+                    if (currentPyStackFrameForConsole.getLastSelectedFrame() == null) {
                         return null;
                     }
                     return super.showPossibleCompletions();
                 };
             };
             contentAssist.setInformationControlCreator(PyContentAssistant.createInformationControlCreator(viewer));
-            ILaunch launch = process.getLaunch();
-            IDebugTarget debugTarget = launch.getDebugTarget();
-            IInterpreterInfo projectInterpreter = null;
-            if (debugTarget instanceof PyDebugTarget) {
-                PyDebugTarget pyDebugTarget = (PyDebugTarget) debugTarget;
-                PythonNature nature = PythonNature.getPythonNature(pyDebugTarget.project);
-                if (nature != null) {
-                    try {
-                        projectInterpreter = nature.getProjectInterpreter();
-                    } catch (Throwable e1) {
-                        Log.log(e1);
-                    }
-                }
-
-            }
-            contentAssist.install(new ScriptConsoleViewerWrapper(viewer, projectInterpreter));
-
-            PydevConsoleInterpreter interpreter = new PydevConsoleInterpreter();
-            interpreter.setConsoleCommunication(new GetCompletionsInDebug());
+            contentAssist.install(new ScriptConsoleViewerWrapper(viewer, interpreter.getInterpreterInfo()));
 
             IContentAssistProcessor processor = new PydevConsoleCompletionProcessor(interpreter, contentAssist);
             contentAssist.setContentAssistProcessor(processor, IOConsolePartition.INPUT_PARTITION_TYPE);
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlay.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlay.java
new file mode 100644
index 0000000..7879970
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlay.java
@@ -0,0 +1,327 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software Ltda. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.debug.console;
+
+import java.io.IOException;
+
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.console.IOConsoleOutputStream;
+import org.eclipse.ui.console.TextConsoleViewer;
+import org.eclipse.ui.internal.console.IOConsolePage;
+import org.eclipse.ui.internal.console.IOConsolePartitioner;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.newconsole.CurrentPyStackFrameForConsole;
+import org.python.pydev.debug.newconsole.PydevConsoleConstants;
+import org.python.pydev.debug.newconsole.PydevConsoleFactory;
+import org.python.pydev.debug.newconsole.PydevDebugConsole;
+import org.python.pydev.debug.newconsole.PydevDebugConsoleCommunication;
+import org.python.pydev.debug.newconsole.prefs.ColorManager;
+import org.python.pydev.shared_interactive_console.console.IScriptConsoleCommunication;
+import org.python.pydev.shared_interactive_console.console.InterpreterResponse;
+import org.python.pydev.shared_interactive_console.console.ScriptConsolePrompt;
+import org.python.pydev.shared_interactive_console.console.ui.IConsoleStyleProvider;
+import org.python.pydev.shared_interactive_console.console.ui.IScriptConsoleListener;
+import org.python.pydev.shared_interactive_console.console.ui.internal.IScriptConsoleContentHandler;
+import org.python.pydev.shared_interactive_console.console.ui.internal.ScriptConsoleViewer;
+
+ at SuppressWarnings("restriction")
+public class PromptOverlay implements DisposeListener, Listener, IScriptConsoleContentHandler {
+
+    private static final String IS_PROMPT_OVERLAY_STYLED_TEXT = "IS_PROMPT_OVERLAY_STYLED_TEXT";
+    private StyledText interactiveConsoleTextWidget;
+    private StyledText styledText;
+    private Composite styledTextParent;
+    private CustomPageBookLayout customLayout;
+    private final CurrentPyStackFrameForConsole currentPyStackFrameForConsole;
+    private ScriptConsoleViewer viewer;
+    private PromptOverlayReplaceGlobalActionHandlers promptOverlayActionHandlers;
+    private boolean overlayVisible = true;
+    private double percSize = .3;
+    private PydevDebugConsole debugConsole;
+    private boolean bufferedOutput = false;
+
+    public PromptOverlay(IOConsolePage consolePage, final ProcessConsole processConsole,
+            CurrentPyStackFrameForConsole currentPyStackFrameForConsole) {
+
+        this.currentPyStackFrameForConsole = currentPyStackFrameForConsole;
+        SourceViewerConfiguration cfg;
+        try {
+            ILaunch launch = processConsole.getProcess().getLaunch();
+            debugConsole = new PydevConsoleFactory().createDebugConsole(launch, "", false, bufferedOutput,
+                    currentPyStackFrameForConsole);
+            cfg = debugConsole.createSourceViewerConfiguration();
+            processConsole.setAttribute(PydevDebugConsole.SCRIPT_DEBUG_CONSOLE_IN_PROCESS_CONSOLE, debugConsole);
+        } catch (Exception e) {
+            // If we can't create the debug console, bail out and do nothing else.
+            Log.log(e);
+            return;
+        }
+
+        TextConsoleViewer consoleViewer = consolePage.getViewer();
+        final StyledText styledText = (StyledText) consoleViewer.getControl();
+        this.styledText = styledText;
+        styledTextParent = styledText.getParent();
+
+        final IConsoleStyleProvider styleProvider = debugConsole.createStyleProvider();
+        viewer = new ScriptConsoleViewer(styledTextParent, debugConsole, this, styleProvider,
+                debugConsole.getInitialCommands(), debugConsole.getFocusOnStart(), debugConsole.getBackspaceAction(),
+                debugConsole.getAutoEditStrategy(), debugConsole.getTabCompletionEnabled(), false);
+        viewer.configure(cfg);
+
+        Layout currentLayout = styledTextParent.getLayout();
+        this.customLayout = new CustomPageBookLayout(currentLayout);
+        this.interactiveConsoleTextWidget = viewer.getTextWidget();
+        this.interactiveConsoleTextWidget.setData(IS_PROMPT_OVERLAY_STYLED_TEXT, Boolean.TRUE);
+
+        final IOConsoleOutputStream streamPrompt = processConsole.newOutputStream();
+        final IOConsoleOutputStream stream = processConsole.newOutputStream();
+        this.promptOverlayActionHandlers = new PromptOverlayReplaceGlobalActionHandlers(consolePage, viewer);
+
+        IActionBars bars = consolePage.getSite().getActionBars();
+        IToolBarManager toolbarManager = bars.getToolBarManager();
+
+        ShowPromptOverlayAction showPromptOverlayAction = new ShowPromptOverlayAction(this);
+        toolbarManager.prependToGroup(IConsoleConstants.LAUNCH_GROUP, showPromptOverlayAction);
+        bars.updateActionBars();
+
+        debugConsole.addListener(new IScriptConsoleListener() {
+
+            @Override
+            public void userRequest(String text, ScriptConsolePrompt prompt) {
+                try {
+                    if (!bufferedOutput) {
+                        streamPrompt.setColor(ColorManager.getDefault().getPreferenceColor(
+                                PydevConsoleConstants.CONSOLE_PROMPT_COLOR));
+
+                        stream.setColor(ColorManager.getDefault().getPreferenceColor(
+                                PydevConsoleConstants.CONSOLE_INPUT_COLOR));
+
+                        IDocument document = processConsole.getDocument();
+                        IDocumentPartitioner partitioner = document.getDocumentPartitioner();
+                        IOConsolePartitioner ioConsolePartitioner = (IOConsolePartitioner) partitioner;
+
+                        ioConsolePartitioner.streamAppended(streamPrompt, prompt.toString());
+                        ioConsolePartitioner.streamAppended(stream, text + "\n");
+                    }
+                } catch (IOException e) {
+                    Log.log(e);
+                }
+            }
+
+            @Override
+            public void interpreterResponse(InterpreterResponse response, ScriptConsolePrompt prompt) {
+
+            }
+        });
+
+        styledText.addDisposeListener(this);
+        styledText.addListener(SWT.Hide, this);
+        styledText.addListener(SWT.Show, this);
+        styledText.addListener(SWT.Paint, this);
+        styledText.addListener(SWT.Resize, this);
+        styledText.addListener(SWT.Selection, this);
+        adjust();
+    }
+
+    @Override
+    public void contentAssistRequired() {
+        if (this.currentPyStackFrameForConsole.getLastSelectedFrame() == null) {
+            return;
+        }
+        viewer.getContentAssist().showPossibleCompletions();
+    }
+
+    @Override
+    public void quickAssistRequired() {
+        viewer.getQuickAssistAssistant().showPossibleQuickAssists();
+    }
+
+    @Override
+    public void widgetDisposed(DisposeEvent e) {
+        dispose();
+    }
+
+    @Override
+    public void handleEvent(Event event) {
+        adjust();
+    }
+
+    private void adjust() {
+        if (styledTextParent == null || styledTextParent.isDisposed()) {
+            return;
+        }
+        if (overlayVisible && styledText != null && !styledText.isDisposed() && styledText.isVisible()) {
+            if (styledTextParent.getLayout() != customLayout) {
+                styledTextParent.setLayout(customLayout);
+                styledTextParent.layout(true);
+            }
+            if (!interactiveConsoleTextWidget.isVisible()) {
+                interactiveConsoleTextWidget.setVisible(true);
+            }
+            if (!interactiveConsoleTextWidget.getBackground().equals(styledText.getBackground())) {
+                interactiveConsoleTextWidget.setBackground(styledText.getBackground());
+            }
+            if (!interactiveConsoleTextWidget.getForeground().equals(styledText.getForeground())) {
+                interactiveConsoleTextWidget.setForeground(styledText.getForeground());
+            }
+            if (!interactiveConsoleTextWidget.getFont().equals(styledText.getFont())) {
+                interactiveConsoleTextWidget.setFont(styledText.getFont());
+            }
+        } else {
+            if (interactiveConsoleTextWidget.isVisible()) {
+                interactiveConsoleTextWidget.setVisible(false);
+            }
+            if (styledTextParent.getLayout() != this.customLayout.originalParentLayout) {
+                styledTextParent.setLayout(this.customLayout.originalParentLayout);
+                styledTextParent.layout(true);
+            }
+        }
+    }
+
+    private class CustomPageBookLayout extends Layout {
+
+        public final Layout originalParentLayout;
+
+        public CustomPageBookLayout(Layout originalParentLayout) {
+            if (originalParentLayout instanceof CustomPageBookLayout) {
+                //It's there by some other view of ours (switched directly between them).
+                CustomPageBookLayout customPageBookLayout = (CustomPageBookLayout) originalParentLayout;
+                this.originalParentLayout = customPageBookLayout.originalParentLayout;
+            } else {
+                this.originalParentLayout = originalParentLayout;
+            }
+        }
+
+        @Override
+        protected Point computeSize(Composite composite, int wHint, int hHint,
+                boolean flushCache) {
+            if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
+                return new Point(wHint, hHint);
+            }
+
+            Point result = null;
+            if (styledText != null) {
+                result = styledText.computeSize(wHint, hHint, flushCache);
+            } else {
+                result = new Point(0, 0);
+            }
+            if (wHint != SWT.DEFAULT) {
+                result.x = wHint;
+            }
+            if (hHint != SWT.DEFAULT) {
+                result.y = hHint;
+            }
+            return result;
+        }
+
+        @Override
+        protected void layout(Composite composite, boolean flushCache) {
+            if (styledText != null && !styledText.isDisposed()) {
+                Rectangle bounds = composite.getClientArea();
+
+                int height = bounds.height;
+                int perc = (int) (height * percSize); // 30% to the input
+
+                interactiveConsoleTextWidget.setBounds(bounds.x, bounds.y + height - perc, bounds.width,
+                        perc);
+                styledText.setBounds(bounds.x, bounds.y, bounds.width, height - perc);
+            }
+        }
+    }
+
+    public void dispose() {
+        try {
+            styledText = null;
+            if (interactiveConsoleTextWidget != null) {
+                interactiveConsoleTextWidget.setVisible(false);
+                interactiveConsoleTextWidget.dispose();
+                interactiveConsoleTextWidget = null;
+            }
+        } catch (Exception e1) {
+            Log.log(e1);
+        }
+        try {
+            if (styledTextParent != null) {
+                if (!styledTextParent.isDisposed()) {
+                    if (styledTextParent.getLayout() == customLayout) {
+                        styledTextParent.setLayout(this.customLayout.originalParentLayout);
+                    }
+                }
+                styledTextParent = null;
+            }
+        } catch (Exception e1) {
+            Log.log(e1);
+        }
+        try {
+            if (promptOverlayActionHandlers != null) {
+                promptOverlayActionHandlers.dispose();
+            }
+            promptOverlayActionHandlers = null;
+        } catch (Exception e1) {
+            Log.log(e1);
+        }
+    }
+
+    public void setOverlayVisible(boolean visible) {
+        if (this.overlayVisible != visible) {
+            this.overlayVisible = visible;
+            adjustAndLayout();
+        }
+    }
+
+    public void setRelativeConsoleHeight(int relSize0To100) {
+        double newVal = relSize0To100 / 100.;
+        if (newVal != this.percSize) {
+            this.percSize = newVal;
+            adjustAndLayout();
+        }
+    }
+
+    private void adjustAndLayout() {
+        adjust();
+        if (styledTextParent != null && !styledTextParent.isDisposed()) {
+            styledTextParent.layout(true);
+        }
+    }
+
+    public void activated() {
+        //I.e.: Console view gets focus
+    }
+
+    public void deactivated() {
+        //I.e.: Console view looses focus
+    }
+
+    public void setBufferedOutput(boolean bufferedOutput) {
+        if (this.bufferedOutput != bufferedOutput) {
+            this.bufferedOutput = bufferedOutput;
+            IScriptConsoleCommunication consoleCommunication = debugConsole.getInterpreter().getConsoleCommunication();
+            if (consoleCommunication instanceof PydevDebugConsoleCommunication) {
+                PydevDebugConsoleCommunication pydevDebugConsoleCommunication = (PydevDebugConsoleCommunication) consoleCommunication;
+                pydevDebugConsoleCommunication.setBufferedOutput(bufferedOutput);
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayConsolePageParticipant.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayConsolePageParticipant.java
new file mode 100644
index 0000000..ef78043
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayConsolePageParticipant.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software Ltda. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.debug.console;
+
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsolePageParticipant;
+import org.eclipse.ui.internal.console.IOConsolePage;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.python.pydev.debug.core.Constants;
+import org.python.pydev.debug.newconsole.CurrentPyStackFrameForConsole;
+
+ at SuppressWarnings("restriction")
+public class PromptOverlayConsolePageParticipant implements IConsolePageParticipant {
+
+    private PromptOverlay promptOverlay;
+
+    @Override
+    public Object getAdapter(Class adapter) {
+        return null;
+    }
+
+    @Override
+    public void init(IPageBookViewPage page, IConsole console) {
+        if (!(console instanceof ProcessConsole)) {
+            return;
+        }
+        ProcessConsole processConsole = (ProcessConsole) console;
+        IProcess process = processConsole.getProcess();
+        if (process == null) {
+            return;
+        }
+
+        String attribute = process.getAttribute(Constants.PYDEV_DEBUG_IPROCESS_ATTR);
+        if (!Constants.PYDEV_DEBUG_IPROCESS_ATTR_TRUE.equals(attribute)) {
+            //Only provide the console page
+            return;
+        }
+        if (page instanceof IOConsolePage) {
+            final CurrentPyStackFrameForConsole currentPyStackFrameForConsole = new CurrentPyStackFrameForConsole(
+                    console);
+            IOConsolePage consolePage = (IOConsolePage) page;
+            this.promptOverlay = new PromptOverlay(consolePage, processConsole, currentPyStackFrameForConsole);
+        }
+
+    }
+
+    @Override
+    public void dispose() {
+        if (this.promptOverlay != null) {
+            this.promptOverlay.dispose();
+        }
+        this.promptOverlay = null;
+    }
+
+    @Override
+    public void activated() {
+        if (this.promptOverlay != null) {
+            this.promptOverlay.activated();
+        }
+    }
+
+    @Override
+    public void deactivated() {
+        if (this.promptOverlay != null) {
+            this.promptOverlay.deactivated();
+        }
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayReplaceGlobalActionHandlers.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayReplaceGlobalActionHandlers.java
new file mode 100644
index 0000000..cef69c6
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/PromptOverlayReplaceGlobalActionHandlers.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software Ltda. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.debug.console;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.ListResourceBundle;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.console.actions.TextViewerAction;
+import org.eclipse.ui.internal.console.IOConsolePage;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.texteditor.FindReplaceAction;
+import org.eclipse.ui.texteditor.IUpdate;
+import org.python.pydev.shared_interactive_console.console.ui.internal.ScriptConsoleViewer;
+
+/**
+ * Provides a way to leave the global handlers updated when we change the focus to our
+ * own StyledText.
+ */
+ at SuppressWarnings("restriction")
+public class PromptOverlayReplaceGlobalActionHandlers {
+
+    private final HashMap<String, IAction> newActions = new HashMap<>();
+
+    private final FocusListener focusListener;
+
+    private final ScriptConsoleViewer viewer;
+
+    public PromptOverlayReplaceGlobalActionHandlers(final IOConsolePage consolePage, final ScriptConsoleViewer viewer) {
+        this.viewer = viewer;
+
+        final Map<String, IAction> old = new HashMap<>();
+
+        TextViewerAction action = new TextViewerAction(viewer, ITextOperationTarget.SELECT_ALL);
+        action.configureAction("Select &All", "Select All", "Select All");
+        action.setActionDefinitionId(ActionFactory.SELECT_ALL.getCommandId());
+        newActions.put(ActionFactory.SELECT_ALL.getId(), action);
+
+        action = new TextViewerAction(viewer, ITextOperationTarget.COPY);
+        action.configureAction("&Copy", "Copy", "Copy");
+        action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+                .getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+        action.setActionDefinitionId(ActionFactory.COPY.getCommandId());
+        newActions.put(ActionFactory.COPY.getId(), action);
+
+        action = new TextViewerAction(viewer, ITextOperationTarget.PASTE);
+        action.configureAction("&Paste", "Paste", "Paste");
+        action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+                .getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+        action.setActionDefinitionId(ActionFactory.PASTE.getCommandId());
+        newActions.put(ActionFactory.PASTE.getId(), action);
+
+        action = new TextViewerAction(viewer, ITextOperationTarget.CUT);
+        action.configureAction("C&ut", "Cut", "Cut");
+        action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+                .getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+        action.setActionDefinitionId(ActionFactory.CUT.getCommandId());
+        newActions.put(ActionFactory.CUT.getId(), action);
+
+        ResourceBundle bundle = new ListResourceBundle() {
+
+            @Override
+            protected Object[][] getContents() {
+                return new Object[0][0];
+            }
+        };
+        FindReplaceAction findAction = new FindReplaceAction(bundle, "Editor.FindReplace.", viewer.getControl()
+                .getShell(), viewer.getFindReplaceTarget());
+        findAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE);
+        newActions.put(ActionFactory.FIND.getId(), findAction);
+
+        selectionDependentActionIds.add(ActionFactory.CUT.getId());
+        selectionDependentActionIds.add(ActionFactory.COPY.getId());
+        selectionDependentActionIds.add(ActionFactory.PASTE.getId());
+        selectionDependentActionIds.add(ActionFactory.FIND.getId());
+
+        this.focusListener = new FocusListener() {
+
+            @Override
+            public void focusLost(FocusEvent e) {
+                if (old.size() == 0) {
+                    return;
+                }
+                IPageSite site = consolePage.getSite();
+                final IActionBars actionBars = site.getActionBars();
+                site.setSelectionProvider(consolePage.getViewer());
+                viewer.getSelectionProvider().removeSelectionChangedListener(selectionChangedListener);
+
+                //Restore old ones
+                for (Entry<String, IAction> oldEntry : old.entrySet()) {
+                    String actionId = oldEntry.getKey();
+                    actionBars.setGlobalActionHandler(actionId, oldEntry.getValue());
+                }
+                old.clear();
+                actionBars.updateActionBars();
+            }
+
+            @Override
+            public void focusGained(FocusEvent e) {
+                if (old.size() > 0) {
+                    return;
+                }
+
+                IPageSite site = consolePage.getSite();
+                //site.registerContextMenu(id, fMenuManager, fViewer);
+                site.setSelectionProvider(viewer);
+                viewer.getSelectionProvider().addSelectionChangedListener(selectionChangedListener);
+
+                final IActionBars actionBars = site.getActionBars();
+                //Store old ones and set new ones
+                for (Entry<String, IAction> entry : newActions.entrySet()) {
+                    String actionId = entry.getKey();
+                    IAction globalActionHandler = actionBars.getGlobalActionHandler(actionId);
+                    old.put(actionId, globalActionHandler);
+                    actionBars.setGlobalActionHandler(actionId, entry.getValue());
+                }
+                actionBars.updateActionBars();
+            }
+        };
+        viewer.getTextWidget().addFocusListener(focusListener);
+    }
+
+    // text selection listener, used to update selection dependent actions on selection changes
+    private ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() {
+        @Override
+        public void selectionChanged(SelectionChangedEvent event) {
+            updateSelectionDependentActions();
+        }
+    };
+
+    protected ArrayList<String> selectionDependentActionIds = new ArrayList<String>();
+
+    protected void updateSelectionDependentActions() {
+        for (String string : selectionDependentActionIds) {
+            IAction action = newActions.get(string);
+            if (action instanceof IUpdate) {
+                ((IUpdate) action).update();
+            }
+        }
+    }
+
+    public void dispose() {
+        StyledText textWidget = viewer.getTextWidget();
+        if (textWidget != null && !textWidget.isDisposed()) {
+            textWidget.removeFocusListener(focusListener);
+        }
+
+    }
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetBufferedOutputAction.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetBufferedOutputAction.java
new file mode 100644
index 0000000..c2d7cc8
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetBufferedOutputAction.java
@@ -0,0 +1,115 @@
+/******************************************************************************
+* Copyright (C) 2015 Brainwy Software Ltda
+*
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+* Contributors:
+*     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
+******************************************************************************/
+package org.python.pydev.debug.console;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.core.PydevDebugPlugin;
+import org.python.pydev.debug.core.PydevDebugPreferencesInitializer;
+import org.python.pydev.shared_ui.utils.UIUtils;
+
+public class SetBufferedOutputAction extends Action implements IPropertyChangeListener {
+
+    private WeakReference<PromptOverlay> promptOverlay;
+    private IPreferenceStore preferences;
+
+    public SetBufferedOutputAction(WeakReference<PromptOverlay> promptOverlay) {
+        this.promptOverlay = promptOverlay;
+        this.setText("Output Mode: Async main console");
+        preferences = PydevDebugPlugin.getDefault().getPreferenceStore();
+        preferences.addPropertyChangeListener(this);
+        this.update();
+    }
+
+    private void update() {
+        PromptOverlay overlay = promptOverlay.get();
+        if (overlay == null) {
+            return;
+        }
+        int val = preferences.getInt(PydevDebugPreferencesInitializer.CONSOLE_PROMPT_OUTPUT_MODE);
+        if (val == PydevDebugPreferencesInitializer.MODE_ASYNC_SEPARATE_CONSOLE) {
+            this.setText("Output Mode: Async main console");
+            overlay.setBufferedOutput(false);
+        } else {
+            this.setText("Output Mode: Sync same console");
+            overlay.setBufferedOutput(true);
+        }
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent event) {
+        if (PydevDebugPreferencesInitializer.CONSOLE_PROMPT_OUTPUT_MODE.equals(event.getProperty())) {
+            this.update();
+        }
+    }
+
+    @Override
+    public void run() {
+        PromptOverlay overlay = promptOverlay.get();
+        if (overlay == null || preferences == null) {
+            return;
+        }
+        int curr = preferences.getInt(PydevDebugPreferencesInitializer.CONSOLE_PROMPT_OUTPUT_MODE);
+
+        int retVal = new MessageDialog(
+                UIUtils.getActiveShell(),
+                "Mode for command output",
+                null,
+                "Please choose the mode for the command output",
+                MessageDialog.QUESTION,
+                new String[] { "Output Asynchronous in main console view",
+                        "Output synchronous in console prompt view" },
+                curr == PydevDebugPreferencesInitializer.MODE_ASYNC_SEPARATE_CONSOLE ? 0 : 1).open();
+
+        if (retVal == 0) {
+            //button 1
+            preferences.setValue(PydevDebugPreferencesInitializer.CONSOLE_PROMPT_OUTPUT_MODE,
+                    PydevDebugPreferencesInitializer.MODE_ASYNC_SEPARATE_CONSOLE);
+            savePrefs();
+
+        } else if (retVal == 1) {
+            //button 2
+            preferences.setValue(PydevDebugPreferencesInitializer.CONSOLE_PROMPT_OUTPUT_MODE,
+                    PydevDebugPreferencesInitializer.MODE_NOT_ASYNC_SAME_CONSOLE);
+            savePrefs();
+        }
+
+    }
+
+    private void savePrefs() {
+        if (preferences instanceof IPersistentPreferenceStore) {
+            try {
+                ((IPersistentPreferenceStore) preferences).save();
+            } catch (IOException e) {
+                Log.log(e);
+            }
+        }
+
+    }
+
+    public void dispose() {
+        if (preferences != null) {
+            preferences.removePropertyChangeListener(this);
+        }
+        preferences = null;
+        this.setEnabled(false);
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetLayoutAction.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetLayoutAction.java
new file mode 100644
index 0000000..80e4ac0
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/SetLayoutAction.java
@@ -0,0 +1,90 @@
+/******************************************************************************
+* Copyright (C) 2015 Brainwy Software Ltda
+*
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+* Contributors:
+*     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
+******************************************************************************/
+package org.python.pydev.debug.console;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.core.PydevDebugPlugin;
+import org.python.pydev.debug.core.PydevDebugPreferencesInitializer;
+import org.python.pydev.shared_ui.dialogs.DialogHelpers;
+
+public class SetLayoutAction extends Action implements IPropertyChangeListener {
+
+    private WeakReference<PromptOverlay> promptOverlay;
+    private IPreferenceStore preferences;
+
+    public SetLayoutAction(WeakReference<PromptOverlay> promptOverlay) {
+        this.promptOverlay = promptOverlay;
+        this.setText("Set Console Height");
+        preferences = PydevDebugPlugin.getDefault().getPreferenceStore();
+        preferences.addPropertyChangeListener(this);
+        this.update();
+    }
+
+    private void update() {
+        PromptOverlay overlay = promptOverlay.get();
+        if (overlay == null) {
+            return;
+        }
+        overlay.setRelativeConsoleHeight(preferences.getInt(PydevDebugPreferencesInitializer.RELATIVE_CONSOLE_HEIGHT));
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent event) {
+        if (PydevDebugPreferencesInitializer.RELATIVE_CONSOLE_HEIGHT.equals(event.getProperty())) {
+            this.update();
+        }
+    }
+
+    @Override
+    public void run() {
+        PromptOverlay overlay = promptOverlay.get();
+        if (overlay == null || preferences == null) {
+            return;
+        }
+        Integer newSize = DialogHelpers.openAskInt("Percentual size for console prompt.",
+                "Please enter the relative size for the console prompt (0-100)",
+                preferences.getInt(PydevDebugPreferencesInitializer.RELATIVE_CONSOLE_HEIGHT));
+        if (newSize != null) {
+            if (newSize < 0) {
+                newSize = 0;
+            }
+            if (newSize > 100) {
+                newSize = 100;
+            }
+        }
+        preferences.setValue(PydevDebugPreferencesInitializer.RELATIVE_CONSOLE_HEIGHT, newSize);
+        if (preferences instanceof IPersistentPreferenceStore) {
+            try {
+                ((IPersistentPreferenceStore) preferences).save();
+            } catch (IOException e) {
+                Log.log(e);
+            }
+        }
+    }
+
+    public void dispose() {
+        if (preferences != null) {
+            preferences.removePropertyChangeListener(this);
+        }
+        preferences = null;
+        this.setEnabled(false);
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ShowPromptOverlayAction.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ShowPromptOverlayAction.java
new file mode 100644
index 0000000..22f6444
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/console/ShowPromptOverlayAction.java
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software Ltda. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.debug.console;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.texteditor.IUpdate;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.core.PydevDebugPlugin;
+import org.python.pydev.debug.core.PydevDebugPreferencesInitializer;
+import org.python.pydev.shared_ui.SharedUiPlugin;
+import org.python.pydev.shared_ui.UIConstants;
+import org.python.pydev.shared_ui.actions.BaseAction;
+
+public class ShowPromptOverlayAction extends BaseAction implements IUpdate, IEditorActionDelegate,
+        IPropertyChangeListener {
+
+    private final WeakReference<PromptOverlay> promptOverlay;
+    private Menu fMenu;
+    private final IPreferenceStore preferences;
+    private final SetLayoutAction setLayoutAction;
+    private final SetBufferedOutputAction setBufferedOutputAction;
+
+    private IMenuCreator menuCreator;
+
+    public ShowPromptOverlayAction(PromptOverlay promptOverlay) {
+        this.promptOverlay = new WeakReference<PromptOverlay>(promptOverlay);
+        preferences = PydevDebugPlugin.getDefault().getPreferenceStore();
+        preferences.addPropertyChangeListener(this);
+
+        this.setLayoutAction = new SetLayoutAction(this.promptOverlay);
+        this.setBufferedOutputAction = new SetBufferedOutputAction(this.promptOverlay);
+
+        update();
+        this.menuCreator = new IMenuCreator() {
+
+            @Override
+            public Menu getMenu(Menu parent) {
+                return null;
+            }
+
+            @Override
+            public void dispose() {
+                if (fMenu != null) {
+                    fMenu.dispose();
+                }
+                fMenu = null;
+            }
+
+            @Override
+            public Menu getMenu(Control parent) {
+                if (fMenu != null) {
+                    fMenu.dispose();
+                }
+
+                fMenu = new Menu(parent);
+
+                addActionToMenu(fMenu, setLayoutAction);
+                addActionToMenu(fMenu, setBufferedOutputAction);
+
+                return fMenu;
+            }
+
+            private void addActionToMenu(Menu parent, Action action) {
+                ActionContributionItem item = new ActionContributionItem(action);
+                item.fill(parent, -1);
+            }
+
+        };
+        setMenuCreator(this.menuCreator);
+    }
+
+    @Override
+    public void update() {
+        PromptOverlay overlay = promptOverlay.get();
+        if (overlay == null) {
+            return;
+        }
+        boolean show = preferences.getBoolean(PydevDebugPreferencesInitializer.SHOW_CONSOLE_PROMPT_ON_DEBUG);
+        if (show) {
+            this.setImageDescriptor(SharedUiPlugin.getImageCache().getDescriptor(UIConstants.CONSOLE_ENABLED));
+            this.setToolTipText("Hide console prompt");
+
+        } else {
+            this.setImageDescriptor(SharedUiPlugin.getImageCache().getDescriptor(UIConstants.CONSOLE_DISABLED));
+            this.setToolTipText("Show console prompt");
+        }
+        overlay.setOverlayVisible(show);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent event) {
+        if (PydevDebugPreferencesInitializer.SHOW_CONSOLE_PROMPT_ON_DEBUG.equals(event.getProperty())) {
+            this.update();
+        }
+    }
+
+    @Override
+    public void run(IAction action) {
+        preferences.setValue(PydevDebugPreferencesInitializer.SHOW_CONSOLE_PROMPT_ON_DEBUG,
+                !preferences.getBoolean(PydevDebugPreferencesInitializer.SHOW_CONSOLE_PROMPT_ON_DEBUG));
+
+        if (preferences instanceof IPersistentPreferenceStore) {
+            try {
+                ((IPersistentPreferenceStore) preferences).save();
+            } catch (IOException e) {
+                Log.log(e);
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        run(this);
+    }
+
+    public void dispose() {
+        this.menuCreator.dispose();
+        preferences.removePropertyChangeListener(this);
+        this.setLayoutAction.dispose();
+        this.setBufferedOutputAction.dispose();
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/core/PydevDebugPreferencesInitializer.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/core/PydevDebugPreferencesInitializer.java
index d53390a..dda8a79 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/core/PydevDebugPreferencesInitializer.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/core/PydevDebugPreferencesInitializer.java
@@ -26,6 +26,12 @@ public class PydevDebugPreferencesInitializer extends AbstractPreferenceInitiali
     public static final String SKIP_CAUGHT_EXCEPTIONS_IN_SAME_FUNCTION = "SKIP_CAUGHT_EXCEPTIONS_IN_SAME_FUNCTION";
     public static final boolean DEFAULT_SKIP_CAUGHT_EXCEPTIONS_IN_SAME_FUNCTION = false;
 
+    public static final String SHOW_CONSOLE_PROMPT_ON_DEBUG = "SHOW_CONSOLE_PROMPT_ON_DEBUG";
+    public final static String RELATIVE_CONSOLE_HEIGHT = "RELATIVE_CONSOLE_HEIGHT";
+    public final static String CONSOLE_PROMPT_OUTPUT_MODE = "CONSOLE_PROMPT_OUTPUT_MODE";
+    public final static int MODE_ASYNC_SEPARATE_CONSOLE = 1;
+    public final static int MODE_NOT_ASYNC_SAME_CONSOLE = 2;
+
     @Override
     public void initializeDefaultPreferences() {
         Preferences node = new DefaultScope().getNode("org.python.pydev.debug");
@@ -43,6 +49,11 @@ public class PydevDebugPreferencesInitializer extends AbstractPreferenceInitiali
         node.putBoolean(IGNORE_EXCEPTIONS_THROWN_IN_LINES_WITH_IGNORE_EXCEPTION,
                 DEFAULT_IGNORE_EXCEPTIONS_THROWN_IN_LINES_WITH_IGNORE_EXCEPTION);
 
+        //Prefs on console prompt on debug
+        node.putBoolean(SHOW_CONSOLE_PROMPT_ON_DEBUG, true);
+        node.putInt(RELATIVE_CONSOLE_HEIGHT, 30);
+        node.putInt(CONSOLE_PROMPT_OUTPUT_MODE, MODE_ASYNC_SEPARATE_CONSOLE);
+
         //Note: the preferences for the debug which appear in the preferences page are actually in
         //the PydevEditorPrefs (as we use the pydev preferences store there).
 
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionView.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionView.java
index 2b1f52a..304903a 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionView.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionView.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionViewContentProvider.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionViewContentProvider.java
index 21241d2..d4fc0df 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionViewContentProvider.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/CurrentExceptionViewContentProvider.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptions.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptions.java
index f888756..2174220 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptions.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptions.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptionsDialog.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptionsDialog.java
index 14ab563..c466e4d 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptionsDialog.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/curr_exception/EditIgnoredCaughtExceptionsDialog.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/handlers/IgnoreCaughtExceptionCommandHandler.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/handlers/IgnoreCaughtExceptionCommandHandler.java
index e2985cb..0512bd3 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/handlers/IgnoreCaughtExceptionCommandHandler.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/handlers/IgnoreCaughtExceptionCommandHandler.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/CaughtException.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/CaughtException.java
index f2a287b..19ca9db 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/CaughtException.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/CaughtException.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/IgnoreCaughtExceptionsWhenThrownFrom.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/IgnoreCaughtExceptionsWhenThrownFrom.java
index bbf60b6..23a7071 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/IgnoreCaughtExceptionsWhenThrownFrom.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/IgnoreCaughtExceptionsWhenThrownFrom.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/PyStackFrame.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/PyStackFrame.java
index 91433a6..2b6f337 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/PyStackFrame.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/PyStackFrame.java
@@ -37,7 +37,7 @@ import org.python.pydev.shared_core.string.StringUtils;
 
 /**
  * Represents a stack entry.
- * 
+ *
  * Needs to integrate with the source locator
  */
 public class PyStackFrame extends PlatformObject implements IStackFrame, IVariableLocator, IPyStackFrame {
@@ -158,10 +158,10 @@ public class PyStackFrame extends PlatformObject implements IStackFrame, IVariab
 
     /**
      * This interface changed in 3.2... we returned an empty collection before, and used the
-     * DeferredWorkbenchAdapter to get the actual children, but now we have to use the 
+     * DeferredWorkbenchAdapter to get the actual children, but now we have to use the
      * DeferredWorkbenchAdapter from here, as it is not called in that other interface
      * anymore.
-     * 
+     *
      * @see org.eclipse.debug.core.model.IStackFrame#getVariables()
      */
     public IVariable[] getVariables() throws DebugException {
@@ -205,7 +205,10 @@ public class PyStackFrame extends PlatformObject implements IStackFrame, IVariab
         this.onAskGetNewVars = true;
         AbstractDebugTarget target = getTarget();
         if (target != null) {
-            target.fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT));
+            // I.e.: if we do a new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT), the selection
+            // of the editor is redone (thus, if the user uses F2 it'd get back to the current breakpoint
+            // location because it'd be reselected).
+            target.fireEvent(new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.UNSPECIFIED));
         }
     }
 
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/AddIgnoreThrownExceptionIn.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/AddIgnoreThrownExceptionIn.java
index 18eff74..0317c9b 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/AddIgnoreThrownExceptionIn.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/AddIgnoreThrownExceptionIn.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/ListenConnector.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/ListenConnector.java
index 2c644d5..f284686 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/ListenConnector.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/model/remote/ListenConnector.java
@@ -26,7 +26,7 @@ public class ListenConnector implements Runnable {
     public ListenConnector(int timeout) throws IOException {
         this.timeout = timeout;
         try {
-            serverSocket = new ServerSocket(0);
+            serverSocket = SocketUtil.createLocalServerSocket();
         } catch (IOException e) {
             Log.log("Error when creating server socket.", e);
             throw e;
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/ProfileView.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/ProfileView.java
new file mode 100644
index 0000000..59dcae2
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/ProfileView.java
@@ -0,0 +1,96 @@
+package org.python.pydev.debug.profile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+import org.python.pydev.shared_ui.field_editors.BooleanFieldEditorCustom;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
+import org.python.pydev.shared_ui.field_editors.FileFieldEditorCustom;
+
+public class ProfileView extends ViewPart {
+
+    private BooleanFieldEditorCustom profileForNewLaunches;
+    private FileFieldEditorCustom pyvmmonitorUiLocation;
+    private List<FieldEditor> fields = new ArrayList<FieldEditor>();
+
+    protected void addField(final FieldEditor editor, Composite parent) {
+        addField(editor, parent, PyProfilePreferences.getTemporaryPreferenceStore());
+    }
+
+    protected void addField(final FieldEditor editor, Composite parent, IPreferenceStore preferenceStore) {
+        fields.add(editor);
+
+        editor.setPreferenceStore(preferenceStore);
+        editor.load();
+        editor.setPropertyChangeListener(new IPropertyChangeListener() {
+
+            @Override
+            public void propertyChange(PropertyChangeEvent event) {
+                // Apply on any change!
+                editor.store();
+            }
+        });
+        if (editor instanceof BooleanFieldEditorCustom) {
+            editor.fillIntoGrid(parent, 2);
+        } else {
+            editor.fillIntoGrid(parent, 1);
+        }
+    }
+
+    @Override
+    public void createPartControl(Composite parent) {
+
+        Composite checkParent = new Composite(parent, SWT.NONE);
+        checkParent.setLayoutData(GridDataFactory.fillDefaults().create());
+        checkParent.setLayout(new GridLayout(2, false));
+
+        profileForNewLaunches = new BooleanFieldEditorCustom(PyProfilePreferences.ENABLE_PROFILING_FOR_NEW_LAUNCHES,
+                "Enable profiling for new launches?", BooleanFieldEditorCustom.SEPARATE_LABEL, checkParent);
+        addField(profileForNewLaunches, checkParent);
+
+        String[][] ENTRIES_AND_VALUES = new String[][] {
+
+                { "Deterministic (profile)",
+                        Integer.toString(PyProfilePreferences.PROFILE_MODE_LSPROF) },
+
+                { "Sampling (yappi)",
+                        Integer.toString(PyProfilePreferences.PROFILE_MODE_YAPPI) },
+
+                { "Don't start profiling",
+                        Integer.toString(PyProfilePreferences.PROFILE_MODE_NONE) },
+        };
+        ComboFieldEditor editor = new ComboFieldEditor(PyProfilePreferences.PROFILE_MODE,
+                "Initial profile mode: ", ENTRIES_AND_VALUES, parent);
+        addField(editor, parent, PyProfilePreferences.getPermanentPreferenceStore());
+
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridData spacingLayoutData = new GridData();
+        spacingLayoutData.heightHint = 8;
+        composite.setLayoutData(spacingLayoutData);
+
+        pyvmmonitorUiLocation = new FileFieldEditorCustom(PyProfilePreferences.PYVMMONITOR_UI_LOCATION,
+                "pyvmmonitor-ui (executable) location", parent);
+        addField(pyvmmonitorUiLocation, parent, PyProfilePreferences.getPermanentPreferenceStore());
+
+        GridLayout layout = GridLayoutFactory.swtDefaults().create();
+        layout.numColumns = 1;
+        parent.setLayout(layout);
+    }
+
+    @Override
+    public void setFocus() {
+        profileForNewLaunches.getCheckBox().setFocus();
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/PyProfilePreferences.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/PyProfilePreferences.java
new file mode 100644
index 0000000..c993698
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/profile/PyProfilePreferences.java
@@ -0,0 +1,169 @@
+package org.python.pydev.debug.profile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceStore;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.plugin.preferences.PydevPrefs;
+import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.process.ProcessUtils;
+import org.python.pydev.shared_core.utils.PlatformUtils;
+import org.python.pydev.shared_ui.utils.RunInUiThread;
+import org.python.pydev.ui.dialogs.PyDialogHelpers;
+
+public class PyProfilePreferences {
+
+    public static final String ENABLE_PROFILING_FOR_NEW_LAUNCHES = "ENABLE_PROFILING_FOR_NEW_LAUNCHES";
+    public static final String PYVMMONITOR_UI_LOCATION = "PYVMMONITOR_UI_LOCATION";
+    public static final String PROFILE_MODE = "PROFILE_MODE";
+
+    public static final int PROFILE_MODE_YAPPI = 0;
+    public static final int PROFILE_MODE_LSPROF = 1;
+    public static final int PROFILE_MODE_NONE = 2;
+
+    // Volatile stuff (not persisted across restarts).
+    public static boolean getAllRunsDoProfile() {
+        return tempPreferenceStore.getBoolean(ENABLE_PROFILING_FOR_NEW_LAUNCHES);
+    }
+
+    private static PreferenceStore tempPreferenceStore = new PreferenceStore();
+    static {
+        tempPreferenceStore.setDefault(ENABLE_PROFILING_FOR_NEW_LAUNCHES, false);
+    }
+
+    public static IPreferenceStore getTemporaryPreferenceStore() {
+        return tempPreferenceStore;
+    }
+
+    // Non-volatile stuff
+    public static String getPyVmMonitorUILocation() {
+        return getPermanentPreferenceStore().getString(PYVMMONITOR_UI_LOCATION);
+    }
+
+    private static boolean firstCall = true;
+    private static final Object lock = new Object();
+
+    public static IPreferenceStore getPermanentPreferenceStore() {
+        IPreferenceStore preferenceStore = PydevPrefs.getPreferenceStore();
+        if (firstCall) {
+            synchronized (lock) {
+                if (firstCall) {
+                    firstCall = false;
+
+                    //TODO: Cover other platforms!
+                    if (PlatformUtils.isWindowsPlatform()) {
+                        try {
+                            //It may not be available in all versions of windows, but if it is, let's use it...
+                            String env = System.getenv("LOCALAPPDATA");
+                            if (env != null && env.length() > 0 && new File(env).exists()) {
+                                File settings = new File(new File(env, "Brainwy"), "PyVmMonitor.ini");
+                                if (settings.exists()) {
+                                    Properties props = new Properties();
+                                    props.load(new FileInputStream(settings));
+                                    String property = props.getProperty("pyvmmonitor_ui_executable");
+                                    preferenceStore.setDefault(PYVMMONITOR_UI_LOCATION, property);
+                                }
+                            }
+                        } catch (Exception e) {
+                            Log.log(e);
+                        }
+                    }
+                    preferenceStore.setDefault(PROFILE_MODE, PROFILE_MODE_LSPROF);
+                }
+            }
+        }
+        return preferenceStore;
+    }
+
+    public static int getProfileMode() {
+        return getPermanentPreferenceStore().getInt(PROFILE_MODE);
+    }
+
+    public static void addProfileArgs(List<String> cmdArgs, boolean profileRun, boolean actualRun) {
+        if (profileRun) {
+            // profile can use yappi or lsprof
+            final String pyVmMonitorUILocation = PyProfilePreferences.getPyVmMonitorUILocation();
+            if (pyVmMonitorUILocation == null || pyVmMonitorUILocation.length() == 0) {
+                if (actualRun) {
+                    RunInUiThread.async(new Runnable() {
+
+                        public void run() {
+                            PyDialogHelpers
+                                    .openWarning(
+                                            "Unable to run in profile mode.",
+                                            "Unable to run in profile mode: pyvmmonitor-ui location not specified.");
+                        }
+                    });
+                }
+                return;
+
+            }
+
+            if (!new File(pyVmMonitorUILocation).exists()) {
+                if (actualRun) {
+                    RunInUiThread.async(new Runnable() {
+
+                        public void run() {
+                            PyDialogHelpers
+                                    .openWarning(
+                                            "Unable to run in profile mode.",
+                                            "Unable to run in profile mode: Invalid location for pyvmmonitor-ui: "
+                                                    + pyVmMonitorUILocation);
+                        }
+                    });
+                }
+                return;
+            }
+
+            // Ok, we have the pyvmmonitor-ui executable location, let's discover the pyvmmonitor.__init__ location
+            // for doing the launch.
+            File file = new File(pyVmMonitorUILocation);
+            File publicApi = new File(file.getParentFile(), "public_api");
+            File pyvmmonitorFolder = new File(publicApi, "pyvmmonitor");
+            final File pyvmmonitorInit = new File(pyvmmonitorFolder, "__init__.py");
+            if (!pyvmmonitorInit.exists()) {
+                if (actualRun) {
+                    RunInUiThread.async(new Runnable() {
+
+                        public void run() {
+                            PyDialogHelpers
+                                    .openWarning(
+                                            "Unable to run in profile mode.",
+                                            "Unable to run in profile mode: Invalid location for pyvmmonitor/__init__.py: "
+                                                    + FileUtils.getFileAbsolutePath(pyvmmonitorInit));
+                        }
+                    });
+                }
+                return;
+
+            }
+
+            // Now, for the profile to work we have to change the initial script to be pyvmmonitor.__init__.
+            cmdArgs.add(FileUtils.getFileAbsolutePath(pyvmmonitorInit));
+
+            int profileMode = PyProfilePreferences.getProfileMode();
+            if (profileMode == PyProfilePreferences.PROFILE_MODE_YAPPI) {
+                cmdArgs.add("--profile=yappi");
+            } else if (profileMode == PyProfilePreferences.PROFILE_MODE_LSPROF) {
+                cmdArgs.add("--profile=lsprof");
+            } else {
+                //Don't pass profile mode
+            }
+
+            // We'll spawn the UI ourselves (so, ask the backend to skip that step).
+            // We have to do that because otherwise the process we launch will 'appear' to be live unless we
+            // also close the profiler.
+            cmdArgs.add("--spawn-ui=false");
+
+            if (actualRun) {
+                ProcessUtils.run(new String[] { pyVmMonitorUILocation, "--default-port-single-instance" }, null,
+                        new File(pyVmMonitorUILocation).getParentFile(), null);
+            }
+        }
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitServer.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitServer.java
index 54482b3..74cbbf3 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitServer.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitServer.java
@@ -92,6 +92,13 @@ public class PyUnitServer implements IPyUnitServer {
 
     }
 
+    private String getAsStr(Object obj) {
+        if (obj instanceof byte[]) {
+            return StringUtils.safeDecodeByteArray((byte[]) obj, "ISO-8859-1"); //same from server
+        }
+        return obj.toString();
+    }
+
     /**
      * This is where the handling of xml-rpc methods from the servers is handled and properly translated for listeners.
      */
@@ -141,35 +148,26 @@ public class PyUnitServer implements IPyUnitServer {
 
             @Override
             public void dispatch(IRequest request) {
-                String status = request.getParameter(0).toString();
+                String status = getAsStr(request.getParameter(0));
 
-                Object stdout = getAsStr(request.getParameter(1));
-                Object stderr = getAsStr(request.getParameter(2));
-
-                String capturedOutput = stdout.toString();
-                String errorContents = stderr.toString();
-                String location = request.getParameter(3).toString();
-                String test = request.getParameter(4).toString();
-                String time = request.getParameter(5).toString();
+                String capturedOutput = getAsStr(request.getParameter(1));
+                String errorContents = getAsStr(request.getParameter(2));
+                String location = getAsStr(request.getParameter(3));
+                String test = getAsStr(request.getParameter(4));
+                String time = getAsStr(request.getParameter(5));
 
                 for (IPyUnitServerListener listener : listeners) {
                     listener.notifyTest(status, location, test, capturedOutput, errorContents, time);
                 }
             }
 
-            private Object getAsStr(Object obj) {
-                if (obj instanceof byte[]) {
-                    return StringUtils.safeDecodeByteArray((byte[]) obj, "ISO-8859-1"); //same from server
-                }
-                return obj;
-            }
         });
         dispatch.put("notifyStartTest", new Dispatch(2) {
 
             @Override
             public void dispatch(IRequest request) {
-                String location = request.getParameter(0).toString();
-                String test = request.getParameter(1).toString();
+                String location = getAsStr(request.getParameter(0));
+                String test = getAsStr(request.getParameter(1));
                 for (IPyUnitServerListener listener : listeners) {
                     listener.notifyStartTest(location, test);
                 }
@@ -180,7 +178,7 @@ public class PyUnitServer implements IPyUnitServer {
 
             @Override
             public void dispatch(IRequest request) {
-                String totalTestsCount = request.getParameter(0).toString();
+                String totalTestsCount = getAsStr(request.getParameter(0));
                 for (IPyUnitServerListener listener : listeners) {
                     listener.notifyTestsCollected(totalTestsCount);
                 }
@@ -199,7 +197,7 @@ public class PyUnitServer implements IPyUnitServer {
             public void dispatch(IRequest request) {
                 for (IPyUnitServerListener listener : listeners) {
                     Object seconds = request.getParameter(0);
-                    listener.notifyFinished(seconds.toString());
+                    listener.notifyFinished(getAsStr(seconds));
                 }
             }
         });
@@ -241,7 +239,7 @@ public class PyUnitServer implements IPyUnitServer {
                                 continue;
                             }
 
-                            final String methodName = methodAndParams[0].toString();
+                            final String methodName = getAsStr(methodAndParams[0]);
                             final Object[] params = (Object[]) methodAndParams[1];
 
                             Dispatch d = dispatch.get(methodName);
@@ -309,7 +307,6 @@ public class PyUnitServer implements IPyUnitServer {
     public PyUnitServer(PythonRunnerConfig config, ILaunch launch) throws IOException {
         initializeDispatches();
         port = SocketUtil.findUnusedLocalPorts(1)[0];
-        SocketUtil.checkValidPort(port);
         this.webServer = new WebServer(port);
         XmlRpcServer serverToHandleRawInput = this.webServer.getXmlRpcServer();
         serverToHandleRawInput.setHandlerMapping(new XmlRpcHandlerMapping() {
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitTestResult.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitTestResult.java
index 44181c3..7b3eee0 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitTestResult.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/pyunit/PyUnitTestResult.java
@@ -92,7 +92,12 @@ public class PyUnitTestResult {
         if (file.exists()) {
             PyOpenAction openAction = new PyOpenAction();
             String fileContents = FileUtils.getFileContents(file);
-            ItemPointer itemPointer = getItemPointer(file, fileContents, this.test);
+            String thisTest = this.test;
+            int i = thisTest.indexOf('['); // This happens when parameterizing pytest tests.
+            if (i != -1) {
+                thisTest = thisTest.substring(0, i);
+            }
+            ItemPointer itemPointer = getItemPointer(file, fileContents, thisTest);
             openAction.run(itemPointer);
         }
     }
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/PythonSourceViewer.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/PythonSourceViewer.java
index 53eed3d..4e28c65 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/PythonSourceViewer.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/PythonSourceViewer.java
@@ -76,7 +76,7 @@ public class PythonSourceViewer extends BaseSourceViewer {
 
             @Override
             public int getTabWidth() {
-                return DefaultIndentPrefs.getStaticTabWidth();
+                return DefaultIndentPrefs.get(null).getTabWidth();
             }
         });
         StyledText text = this.getTextWidget();
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/SourceLocatorPrefsPage.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/SourceLocatorPrefsPage.java
index d37e04c..05fa514 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/SourceLocatorPrefsPage.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/SourceLocatorPrefsPage.java
@@ -22,7 +22,7 @@ import org.python.pydev.editor.preferences.PydevEditorPrefs;
 import org.python.pydev.editorinput.PySourceLocatorPrefs;
 import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.shared_core.string.StringUtils;
-import org.python.pydev.utils.ComboFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
 
 /**
  * Preferences for the locations that should be translated -- used when the debugger is not able
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/AbstractLaunchShortcut.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/AbstractLaunchShortcut.java
index 8eb88bf..5df8032 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/AbstractLaunchShortcut.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/AbstractLaunchShortcut.java
@@ -52,8 +52,8 @@ import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.utils.ArrayUtils;
 import org.python.pydev.shared_ui.EditorUtils;
+import org.python.pydev.shared_ui.dialogs.ProjectSelectionDialog;
 import org.python.pydev.shared_ui.utils.RunInUiThread;
-import org.python.pydev.ui.dialogs.ProjectSelectionDialog;
 import org.python.pydev.ui.dialogs.PythonModulePickerDialog;
 
 /**
diff --git a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/PythonRunnerConfig.java b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/PythonRunnerConfig.java
index b9dd093..0cebf73 100644
--- a/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/PythonRunnerConfig.java
+++ b/plugins/org.python.pydev.debug/src/org/python/pydev/debug/ui/launching/PythonRunnerConfig.java
@@ -50,6 +50,7 @@ import org.python.pydev.debug.codecoverage.PyCoveragePreferences;
 import org.python.pydev.debug.core.Constants;
 import org.python.pydev.debug.core.PydevDebugPlugin;
 import org.python.pydev.debug.model.remote.ListenConnector;
+import org.python.pydev.debug.profile.PyProfilePreferences;
 import org.python.pydev.debug.pyunit.PyUnitServer;
 import org.python.pydev.debug.ui.DebugPrefsPage;
 import org.python.pydev.debug.ui.launching.PythonRunnerCallbacks.CreatedCommandLineParams;
@@ -637,6 +638,8 @@ public class PythonRunnerConfig {
     public String[] getCommandLine(boolean actualRun) throws CoreException, JDTNotAvailableException {
         List<String> cmdArgs = new ArrayList<String>();
 
+        boolean profileRun = PyProfilePreferences.getAllRunsDoProfile();
+
         if (isJython()) {
             //"java.exe" -classpath "C:\bin\jython21\jython.jar" org.python.util.jython script %ARGS%
             String javaLoc = JavaVmLocationFinder.findDefaultJavaExecutable().getAbsolutePath();
@@ -662,6 +665,7 @@ public class PythonRunnerConfig {
             cmdArgs.add("-Dpython.path=" + pythonpathUsed); //will be added to the env variables in the run (check if this works on all platforms...)
 
             addVmArgs(cmdArgs);
+            addProfileArgs(cmdArgs, profileRun, actualRun);
 
             if (isDebug) {
                 //This was removed because it cannot be used. See: 
@@ -682,6 +686,8 @@ public class PythonRunnerConfig {
             cmdArgs.add("-u");
 
             addVmArgs(cmdArgs);
+            addProfileArgs(cmdArgs, profileRun, actualRun);
+
             if (isDebug && isIronpython()) {
                 addIronPythonDebugVmArgs(cmdArgs);
             }
@@ -769,6 +775,10 @@ public class PythonRunnerConfig {
         return retVal;
     }
 
+    private void addProfileArgs(List<String> cmdArgs, boolean profileRun, boolean actualRun) {
+        PyProfilePreferences.addProfileArgs(cmdArgs, profileRun, actualRun);
+    }
+
     private void addIronPythonDebugVmArgs(List<String> cmdArgs) {
         if (cmdArgs.contains("-X:Frames") || cmdArgs.contains("-X:FullFrames")) {
             return;
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/AnyPyStackFrameSelected.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/AnyPyStackFrameSelected.java
new file mode 100644
index 0000000..58a0adf
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/AnyPyStackFrameSelected.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.debug.newconsole;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.python.pydev.debug.model.PyStackFrame;
+import org.python.pydev.shared_ui.utils.UIUtils;
+
+/**
+ * @author Fabio
+ */
+public class AnyPyStackFrameSelected implements IPyStackFrameProvider, IDebugContextListener {
+
+    /**
+     * By default, debug console will be linked with the selected frame
+     */
+    protected boolean isLinkedWithDebug = true;
+
+    private PyStackFrame last;
+
+    public AnyPyStackFrameSelected() {
+        IWorkbenchPart activePart = UIUtils.getActivePart();
+        if (activePart != null) {
+            IWorkbenchPartSite site = activePart.getSite();
+            DebugUITools.addPartDebugContextListener(site, this);
+        }
+    }
+
+    /**
+     * @return the currently selected / suspended frame. If the console is passed, it will only return
+     * a frame that matches the passed console. If no selected / suspended frame is found or the console
+     * doesn't match, null is returned.
+     */
+    public PyStackFrame getLastSelectedFrame() {
+        updateContext(DebugUITools.getDebugContext());
+
+        if (last instanceof PyStackFrame) {
+            PyStackFrame stackFrame = last;
+            if (!stackFrame.isTerminated() && stackFrame.isSuspended()) {
+                // I.e.: can only deal with suspended contexts!
+                return last;
+            }
+        }
+        return null;
+    }
+
+    private void updateContext(IAdaptable context) {
+        if (!isLinkedWithDebug && last != null) {
+            return;
+        }
+        if (context != last && context instanceof PyStackFrame) {
+            PyStackFrame stackFrame = (PyStackFrame) context;
+            if (!stackFrame.isTerminated() && stackFrame.isSuspended()) {
+                if (acceptsSelection(stackFrame)) {
+                    last = stackFrame;
+                }
+            }
+        }
+    }
+
+    //Subclasses may override
+    protected boolean acceptsSelection(PyStackFrame stackFrame) {
+        return true;
+    }
+
+    @Override
+    public void debugContextChanged(DebugContextEvent event) {
+        if (event.getFlags() == DebugContextEvent.ACTIVATED) {
+            updateContext(getDebugContextElementForSelection(event.getContext()));
+        }
+    }
+
+    private static IAdaptable getDebugContextElementForSelection(ISelection activeContext) {
+        if (activeContext instanceof IStructuredSelection) {
+            IStructuredSelection selection = (IStructuredSelection) activeContext;
+            if (!selection.isEmpty()) {
+                Object firstElement = selection.getFirstElement();
+                if (firstElement instanceof IAdaptable) {
+                    return (IAdaptable) firstElement;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Enable/Disable linking of the debug console with the suspended frame.
+     *
+     * @param isLinkedWithDebug
+     */
+    public void linkWithDebugSelection(boolean isLinkedWithDebug) {
+        this.isLinkedWithDebug = isLinkedWithDebug;
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/CurrentPyStackFrameForConsole.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/CurrentPyStackFrameForConsole.java
new file mode 100644
index 0000000..a93a7ba
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/CurrentPyStackFrameForConsole.java
@@ -0,0 +1,41 @@
+package org.python.pydev.debug.newconsole;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.ui.console.IConsole;
+import org.python.pydev.debug.model.AbstractDebugTarget;
+import org.python.pydev.debug.model.PyStackFrame;
+
+/**
+ * Only returns stacks which match the current console (and keeps the last one).
+ *
+ * A selection always changes it (so, always linked to debug context).
+ */
+public class CurrentPyStackFrameForConsole extends AnyPyStackFrameSelected {
+
+    private IConsole console;
+
+    public CurrentPyStackFrameForConsole(IConsole console) {
+        super();
+        Assert.isNotNull(console);
+        this.console = console;
+        isLinkedWithDebug = true;
+    }
+
+    @Override
+    protected boolean acceptsSelection(PyStackFrame stackFrame) {
+        if (super.acceptsSelection(stackFrame)) {
+            AbstractDebugTarget target = (AbstractDebugTarget) stackFrame.getAdapter(IDebugTarget.class);
+            if (DebugUITools.getConsole(target.getProcess()) == console) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void linkWithDebugSelection(boolean isLinkedWithDebug) {
+        // Overridden to do nothing because this one is always linked.
+    }
+}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/EvaluateDebugConsoleExpression.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/EvaluateDebugConsoleExpression.java
index 5eea45c..219aa66 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/EvaluateDebugConsoleExpression.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/EvaluateDebugConsoleExpression.java
@@ -24,7 +24,7 @@ import org.python.pydev.shared_core.string.StringUtils;
 
 /**
  * Class to exectute console command in the debugging context
- * 
+ *
  * @author hussain.bohra
  * @author Fabio Zadrozny
  */
@@ -40,8 +40,8 @@ public class EvaluateDebugConsoleExpression implements ICommandResponseListener
     }
 
     /**
-     * This method will get called from AbstractDebugTarget when 
-     * output arrives for the posted command 
+     * This method will get called from AbstractDebugTarget when
+     * output arrives for the posted command
      */
     public void commandComplete(AbstractDebuggerCommand cmd) {
         try {
@@ -53,13 +53,14 @@ public class EvaluateDebugConsoleExpression implements ICommandResponseListener
 
     /**
      * Execute the line in selected frame context
-     * 
+     *
      * @param consoleId
      * @param command
      */
-    public void executeCommand(String command) {
+    public void executeCommand(String command, boolean bufferedOutput) {
         AbstractDebugTarget target = frame.getTarget();
-        String locator = getLocator(frame.getThreadId(), frame.getId(), "EVALUATE", command);
+        String locator = getLocator(frame.getThreadId(), frame.getId(), bufferedOutput ? "EVALUATE"
+                : "EVALUATE_UNBUFFERED", command);
         AbstractDebuggerCommand cmd = new EvaluateConsoleExpressionCommand(target, locator,
                 new ICommandResponseListener() {
 
@@ -73,7 +74,7 @@ public class EvaluateDebugConsoleExpression implements ICommandResponseListener
 
     /**
      * Post the completions command
-     * 
+     *
      * @param consoleId
      * @param actTok
      * @param offset
@@ -110,8 +111,8 @@ public class EvaluateDebugConsoleExpression implements ICommandResponseListener
     }
 
     /**
-     * join and return all locators with '\t' 
-     * 
+     * join and return all locators with '\t'
+     *
      * @param locators
      * @return
      */
@@ -120,8 +121,8 @@ public class EvaluateDebugConsoleExpression implements ICommandResponseListener
     }
 
     /**
-     * This class represent the console message to be displayed in the debug console. 
-     * 
+     * This class represent the console message to be displayed in the debug console.
+     *
      * @author hussain.bohra
      *
      */
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/HandleBackspaceAction.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/HandleBackspaceAction.java
index d77643e..e4287b0 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/HandleBackspaceAction.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/HandleBackspaceAction.java
@@ -30,7 +30,7 @@ public class HandleBackspaceAction extends AbstractHandleBackspaceAction {
 
         PyBackspace pyBackspace = new PyBackspace();
         pyBackspace.setDontEraseMoreThan(commandLineOffset);
-        pyBackspace.setIndentPrefs(DefaultIndentPrefs.get());
+        pyBackspace.setIndentPrefs(DefaultIndentPrefs.get(null));
         PySelection ps = new PySelection(doc, selection);
 
         pyBackspace.perform(ps);
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/IPyStackFrameProvider.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/IPyStackFrameProvider.java
new file mode 100644
index 0000000..fc5d06f
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/IPyStackFrameProvider.java
@@ -0,0 +1,10 @@
+package org.python.pydev.debug.newconsole;
+
+import org.python.pydev.debug.model.PyStackFrame;
+
+public interface IPyStackFrameProvider {
+
+    public PyStackFrame getLastSelectedFrame();
+
+    public void linkWithDebugSelection(boolean isLinkedWithDebug);
+}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsole.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsole.java
index d2584c8..8da2e0e 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsole.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsole.java
@@ -10,6 +10,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.variables.IStringVariableManager;
 import org.eclipse.core.variables.VariablesPlugin;
 import org.eclipse.debug.core.model.IProcess;
@@ -105,7 +106,7 @@ public class PydevConsole extends ScriptConsole {
     }
 
     @Override
-    protected SourceViewerConfiguration createSourceViewerConfiguration() {
+    public SourceViewerConfiguration createSourceViewerConfiguration() {
         PyContentAssistant contentAssist = new PyContentAssistant();
         IContentAssistProcessor processor = createConsoleCompletionProcessor(contentAssist);
         contentAssist.setContentAssistProcessor(processor, PydevScriptConsoleSourceViewerConfiguration.PARTITION_TYPE);
@@ -326,6 +327,12 @@ public class PydevConsole extends ScriptConsole {
 
     @Override
     public IHandleScriptAutoEditStrategy getAutoEditStrategy() {
-        return new PyAutoIndentStrategy();
+        return new PyAutoIndentStrategy(new IAdaptable() {
+
+            @Override
+            public Object getAdapter(Class adapter) {
+                return null;
+            }
+        });
     }
 }
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java
index a48ed4f..21fc7e3 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleCommunication.java
@@ -71,7 +71,7 @@ public class PydevConsoleCommunication implements IScriptConsoleCommunication, X
     /**
      * XML-RPC client for sending messages to the server.
      */
-    private IXmlRpcClient client;
+    private volatile IXmlRpcClient client;
 
     /**
      * This is the server responsible for giving input to a raw_input() requested
@@ -101,11 +101,11 @@ public class PydevConsoleCommunication implements IScriptConsoleCommunication, X
 
         private final Object lock = new Object();
 
-        public StdStreamsThread(Process process) {
+        public StdStreamsThread(Process process, String encoding) {
             this.setName("StdStreamsThread: " + process);
             this.setDaemon(true);
-            stdOutReader = new ThreadStreamReader(process.getInputStream());
-            stdErrReader = new ThreadStreamReader(process.getErrorStream());
+            stdOutReader = new ThreadStreamReader(process.getInputStream(), true, encoding);
+            stdErrReader = new ThreadStreamReader(process.getErrorStream(), true, encoding);
             stdOutReader.start();
             stdErrReader.start();
         }
@@ -148,7 +148,7 @@ public class PydevConsoleCommunication implements IScriptConsoleCommunication, X
      * @throws MalformedURLException
      */
     public PydevConsoleCommunication(int port, final Process process, int clientPort, String[] commandArray,
-            String[] envp)
+            String[] envp, String encoding)
             throws Exception {
         this.commandArray = commandArray;
         this.envp = envp;
@@ -177,7 +177,7 @@ public class PydevConsoleCommunication implements IScriptConsoleCommunication, X
         });
 
         this.webServer.start();
-        this.stdStreamsThread = new StdStreamsThread(process);
+        this.stdStreamsThread = new StdStreamsThread(process, encoding);
         this.stdStreamsThread.start();
 
         IXmlRpcClient client = new ScriptXmlRpcClient(process);
@@ -218,6 +218,11 @@ public class PydevConsoleCommunication implements IScriptConsoleCommunication, X
         }
     }
 
+    @Override
+    public boolean isConnected() {
+        return this.client != null;
+    }
+
     /**
      * Variables that control when we're expecting to give some input to the server or when we're
      * adding some line to be executed
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleConstants.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleConstants.java
index f12d4cc..0218fc8 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleConstants.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleConstants.java
@@ -44,9 +44,15 @@ public final class PydevConsoleConstants {
     public static final String INTERACTIVE_CONSOLE_VM_ARGS = "INTERACTIVE_CONSOLE_VM_ARGS";
     public static final String DEFAULT_INTERACTIVE_CONSOLE_VM_ARGS = "-Xmx64m";
 
+    public static final String INTERACTIVE_CONSOLE_ENCODING = "INTERACTIVE_CONSOLE_ENCODING";
+    public static final String DEFAULT_INTERACTIVE_CONSOLE_ENCODING = "UTF-8";
+
     public static final String INITIAL_INTERPRETER_CMDS = "INITIAL_INTERPRETER_CMDS";
     public static final String DEFAULT_INITIAL_INTERPRETER_CMDS = "import sys; print('%s %s' % (sys.executable or sys.platform, sys.version))\n";
 
+    public static final String DJANGO_INTERPRETER_CMDS = "DJANGO_INTERPRETER_CMDS";
+    public static final String DEFAULT_DJANGO_INTERPRETER_CMDS = "import os; os.environ['DJANGO_SETTINGS_MODULE'] = '${DJANGO_SETTINGS_MODULE}'; import django\nif django.get_version() < '1.5':\n\tfrom django.core import management\n\timport ${DJANGO_SETTINGS_MODULE} as settings\n\tmanagement.setup_environ(settings)\nif django.get_version() >= '1.7':\n\tfrom django.core.wsgi import get_wsgi_application\n\tapplication = get_wsgi_application()\n";
+
     public static final String INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS = "INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS";
     public static final int DEFAULT_INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS = 50;
 
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleFactory.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleFactory.java
index 05c7175..7ad65f4 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleFactory.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleFactory.java
@@ -44,9 +44,9 @@ import org.python.pydev.shared_interactive_console.console.ui.ScriptConsoleManag
 
 /**
  * Could ask to configure the interpreter in the preferences
- * 
+ *
  * PreferencesUtil.createPreferenceDialogOn(null, preferencePageId, null, null)
- * 
+ *
  * This is the class responsible for creating the console (and setting up the communication
  * between the console server and the client).
  *
@@ -73,7 +73,8 @@ public class PydevConsoleFactory implements IConsoleFactory {
             if (interpreter.getFrame() == null) {
                 createConsole(interpreter, additionalInitialComands);
             } else {
-                createDebugConsole(interpreter.getFrame(), additionalInitialComands);
+                createDebugConsole(interpreter.getFrame(), additionalInitialComands, true, true,
+                        new AnyPyStackFrameSelected());
             }
         } catch (Exception e) {
             Log.log(e);
@@ -182,7 +183,7 @@ public class PydevConsoleFactory implements IConsoleFactory {
         try {
             // Jython within Eclipse does not yet support debugging
             // NOTE: Jython within Eclipse currently works "once", i.e. it sets up properly and you can debug your
-            // scripts you run within Eclipse, but the termination does not work properly and it seems that 
+            // scripts you run within Eclipse, but the termination does not work properly and it seems that
             // we don't clean-up properly. There is a small additional problem, pysrc is not on the PYTHONPATH
             // so it fails to run properly, a simple hack to the pydevconsole to add its dirname to the sys.path
             // resolves that issue though.
@@ -252,29 +253,51 @@ public class PydevConsoleFactory implements IConsoleFactory {
         }
     }
 
+    public PydevDebugConsole createDebugConsole(ILaunch launch, String additionalInitialComands, boolean addToManager,
+            boolean bufferedOutput, IPyStackFrameProvider consoleFrameProvider) throws Exception {
+        return createDebugConsole(launch, null, additionalInitialComands, addToManager, bufferedOutput,
+                consoleFrameProvider);
+    }
+
+    public PydevDebugConsole createDebugConsole(PyStackFrame frame, String additionalInitialComands,
+            boolean addToManager, boolean bufferedOutput, IPyStackFrameProvider consoleFrameProvider) throws Exception {
+        return createDebugConsole(null, frame, additionalInitialComands, addToManager, bufferedOutput,
+                consoleFrameProvider);
+    }
+
     /**
      * Create a new Debug Console
      *
      * @param interpreter
      * @param additionalInitialComands
+     * @return
      */
-    public void createDebugConsole(PyStackFrame frame, String additionalInitialComands) throws Exception {
-        PydevConsoleLaunchInfo launchAndProcess = new PydevConsoleLaunchInfo(null, null, 0, null, frame, null, null);
-
-        PydevConsoleInterpreter interpreter = createPydevDebugInterpreter(launchAndProcess);
-        ScriptConsoleManager manager = ScriptConsoleManager.getInstance();
+    private PydevDebugConsole createDebugConsole(ILaunch launch, PyStackFrame frame, String additionalInitialComands,
+            boolean addToManager, boolean bufferedOutput, IPyStackFrameProvider consoleFrameProvider) throws Exception {
+        PydevConsoleLaunchInfo launchAndProcess = new PydevConsoleLaunchInfo(null, null, 0, null, frame, null, null,
+                launch != null ? PydevIProcessFactory.getEncodingFromLaunch(launch)
+                        : PydevIProcessFactory.getEncodingFromFrame(frame));
+
+        PydevConsoleInterpreter interpreter = createPydevDebugInterpreter(launchAndProcess, bufferedOutput,
+                consoleFrameProvider);
         PydevDebugConsole console = new PydevDebugConsole(interpreter, additionalInitialComands);
-        manager.add(console, true);
+
+        if (addToManager) {
+            ScriptConsoleManager manager = ScriptConsoleManager.getInstance();
+            manager.add(console, true);
+        }
+        return console;
     }
 
     /**
      * @return A PydevConsoleInterpreter with its communication configured.
-     * 
+     *
      * @throws CoreException
      * @throws IOException
      * @throws UserCanceledException
      */
-    public static PydevConsoleInterpreter createDefaultPydevInterpreter() throws Exception, UserCanceledException {
+    public static PydevConsoleInterpreter createDefaultPydevInterpreter()
+            throws Exception, UserCanceledException {
 
         //            import sys; sys.ps1=''; sys.ps2=''
         //            import sys;print >> sys.stderr, ' '.join([sys.executable, sys.platform, sys.version])
@@ -291,16 +314,16 @@ public class PydevConsoleFactory implements IConsoleFactory {
             return null;
         }
         if (launchAndProcess.interpreter != null) {
-            return createPydevInterpreter(launchAndProcess, iprocessFactory.getNaturesUsed());
+            return createPydevInterpreter(launchAndProcess, iprocessFactory.getNaturesUsed(), launchAndProcess.encoding);
         } else {
-            return createPydevDebugInterpreter(launchAndProcess);
+            return createPydevDebugInterpreter(launchAndProcess, true, new AnyPyStackFrameSelected());
         }
 
     }
 
     // Use IProcessFactory to get the required tuple
     public static PydevConsoleInterpreter createPydevInterpreter(PydevConsoleLaunchInfo info,
-            List<IPythonNature> natures) throws Exception {
+            List<IPythonNature> natures, String encoding) throws Exception {
         final ILaunch launch = info.launch;
         Process process = info.process;
         Integer clientPort = info.clientPort;
@@ -312,7 +335,7 @@ public class PydevConsoleFactory implements IConsoleFactory {
         PydevConsoleInterpreter consoleInterpreter = new PydevConsoleInterpreter();
         int port = Integer.parseInt(launch.getAttribute(PydevIProcessFactory.INTERACTIVE_LAUNCH_PORT));
         consoleInterpreter.setConsoleCommunication(new PydevConsoleCommunication(port, process, clientPort,
-                info.cmdLine, info.env));
+                info.cmdLine, info.env, encoding));
         consoleInterpreter.setNaturesUsed(natures);
         consoleInterpreter.setInterpreterInfo(interpreterInfo);
         consoleInterpreter.setLaunch(launch);
@@ -332,15 +355,20 @@ public class PydevConsoleFactory implements IConsoleFactory {
     /**
      * Initialize Console Interpreter and Console Communication for the Debug Console
      */
-    public static PydevConsoleInterpreter createPydevDebugInterpreter(PydevConsoleLaunchInfo info) throws Exception {
+    public static PydevConsoleInterpreter createPydevDebugInterpreter(PydevConsoleLaunchInfo info,
+            boolean bufferedOutput, IPyStackFrameProvider consoleFrameProvider) throws Exception {
 
         PyStackFrame frame = info.frame;
 
         PydevConsoleInterpreter consoleInterpreter = new PydevConsoleInterpreter();
         consoleInterpreter.setFrame(frame);
+        consoleInterpreter.setLaunchAndRelatedInfo(info.launch);
+        consoleInterpreter.setProcess(info.process);
 
         // pydev console uses running debugger as a backend
-        consoleInterpreter.setConsoleCommunication(new PydevDebugConsoleCommunication());
+        consoleInterpreter.setConsoleCommunication(new PydevDebugConsoleCommunication(bufferedOutput,
+                consoleFrameProvider));
         return consoleInterpreter;
     }
+
 }
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java
index 5d922f1..49df6da 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsoleInterpreter.java
@@ -16,6 +16,7 @@ import java.util.Set;
 import java.util.TreeSet;
 
 import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
@@ -31,12 +32,15 @@ import org.python.pydev.core.MisconfigurationException;
 import org.python.pydev.core.docutils.ImportsSelection;
 import org.python.pydev.core.docutils.PySelection;
 import org.python.pydev.core.docutils.PySelection.ActivationTokenAndQual;
+import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.model.PyDebugTarget;
 import org.python.pydev.debug.model.PyStackFrame;
 import org.python.pydev.editor.codecompletion.IPyCodeCompletion;
 import org.python.pydev.editor.codecompletion.IPyDevCompletionParticipant2;
 import org.python.pydev.editor.codecompletion.PyLinkedModeCompletionProposal;
 import org.python.pydev.editor.codecompletion.templates.PyTemplateCompletionProcessor;
 import org.python.pydev.editor.simpleassist.ISimpleAssistParticipant2;
+import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.shared_interactive_console.console.IScriptConsoleCommunication;
@@ -324,4 +328,27 @@ public class PydevConsoleInterpreter implements IScriptConsoleInterpreter {
         this.consoleCommunication.linkWithDebugSelection(isLinkedWithDebug);
     }
 
+    public void setLaunchAndRelatedInfo(ILaunch launch) {
+        this.setLaunch(launch);
+        if (launch != null) {
+            IDebugTarget debugTarget = launch.getDebugTarget();
+            IInterpreterInfo projectInterpreter = null;
+            if (debugTarget instanceof PyDebugTarget) {
+                PyDebugTarget pyDebugTarget = (PyDebugTarget) debugTarget;
+                PythonNature nature = PythonNature.getPythonNature(pyDebugTarget.project);
+                if (nature != null) {
+                    ArrayList<IPythonNature> natures = new ArrayList<>(1);
+                    this.setNaturesUsed(natures);
+                    try {
+                        projectInterpreter = nature.getProjectInterpreter();
+                        this.setInterpreterInfo(projectInterpreter);
+                    } catch (Throwable e1) {
+                        Log.log(e1);
+                    }
+                }
+            }
+        }
+
+    }
+
 }
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsolePreferencesInitializer.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsolePreferencesInitializer.java
index 203dd40..8b8f681 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsolePreferencesInitializer.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevConsolePreferencesInitializer.java
@@ -44,8 +44,14 @@ public class PydevConsolePreferencesInitializer extends AbstractPreferenceInitia
 
         node.put(PydevConsoleConstants.INTERACTIVE_CONSOLE_VM_ARGS,
                 PydevConsoleConstants.DEFAULT_INTERACTIVE_CONSOLE_VM_ARGS);
+
+        node.put(PydevConsoleConstants.INTERACTIVE_CONSOLE_ENCODING,
+                PydevConsoleConstants.DEFAULT_INTERACTIVE_CONSOLE_ENCODING);
+
         node.put(PydevConsoleConstants.INITIAL_INTERPRETER_CMDS, PydevConsoleConstants.DEFAULT_INITIAL_INTERPRETER_CMDS);
 
+        node.put(PydevConsoleConstants.DJANGO_INTERPRETER_CMDS, PydevConsoleConstants.DEFAULT_DJANGO_INTERPRETER_CMDS);
+
         node.putInt(PydevConsoleConstants.INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS,
                 PydevConsoleConstants.DEFAULT_INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS);
 
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleCommunication.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleCommunication.java
index 6e6c5fc..a3084c6 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleCommunication.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleCommunication.java
@@ -63,12 +63,28 @@ public class PydevDebugConsoleCommunication implements IScriptConsoleCommunicati
      */
     private volatile InterpreterResponse nextResponse;
 
-    private final PydevDebugConsoleFrame consoleFrame;
+    private final IPyStackFrameProvider consoleFrameProvider;
 
     private ICallback<Object, Tuple<String, String>> onContentsReceived;
 
-    public PydevDebugConsoleCommunication() {
-        consoleFrame = new PydevDebugConsoleFrame();
+    private boolean bufferedOutput;
+
+    public void setBufferedOutput(boolean bufferedOutput) {
+        this.bufferedOutput = bufferedOutput;
+    }
+
+    public boolean getBufferedOutput() {
+        return this.bufferedOutput;
+    }
+
+    public PydevDebugConsoleCommunication(boolean bufferedOutput, IPyStackFrameProvider consoleFrameProvider) {
+        this.consoleFrameProvider = consoleFrameProvider;
+        this.bufferedOutput = bufferedOutput;
+    }
+
+    @Override
+    public boolean isConnected() {
+        return this.consoleFrameProvider.getLastSelectedFrame() != null;
     }
 
     @Override
@@ -94,7 +110,7 @@ public class PydevDebugConsoleCommunication implements IScriptConsoleCommunicati
 
                 @Override
                 protected IStatus run(IProgressMonitor monitor) {
-                    PyStackFrame frame = consoleFrame.getLastSelectedFrame();
+                    PyStackFrame frame = consoleFrameProvider.getLastSelectedFrame();
                     if (frame == null) {
                         if (onContentsReceived != null) {
                             onContentsReceived.call(new Tuple<String, String>(EMPTY,
@@ -105,7 +121,7 @@ public class PydevDebugConsoleCommunication implements IScriptConsoleCommunicati
                     }
                     final EvaluateDebugConsoleExpression evaluateDebugConsoleExpression = new EvaluateDebugConsoleExpression(
                             frame);
-                    evaluateDebugConsoleExpression.executeCommand(command);
+                    evaluateDebugConsoleExpression.executeCommand(command, bufferedOutput);
                     String result = evaluateDebugConsoleExpression.waitForCommand();
                     try {
                         if (result.length() == 0) {
@@ -166,7 +182,7 @@ public class PydevDebugConsoleCommunication implements IScriptConsoleCommunicati
             return new ICompletionProposal[0];
         }
 
-        PyStackFrame frame = consoleFrame.getLastSelectedFrame();
+        PyStackFrame frame = consoleFrameProvider.getLastSelectedFrame();
         if (frame == null) {
             return new ICompletionProposal[0];
         }
@@ -190,7 +206,7 @@ public class PydevDebugConsoleCommunication implements IScriptConsoleCommunicati
      * Enable/Disable linking of the debug console with the suspended frame.
      */
     public void linkWithDebugSelection(boolean isLinkedWithDebug) {
-        consoleFrame.linkWithDebugSelection(isLinkedWithDebug);
+        consoleFrameProvider.linkWithDebugSelection(isLinkedWithDebug);
     }
 
     public void close() throws Exception {
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleFrame.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleFrame.java
deleted file mode 100644
index fc3e75e..0000000
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevDebugConsoleFrame.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
- * Licensed under the terms of the Eclipse Public License (EPL).
- * Please see the license.txt included with this distribution for details.
- * Any modifications to this file must keep this entire header intact.
- */
-package org.python.pydev.debug.newconsole;
-
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.debug.ui.DebugUITools;
-import org.python.pydev.debug.model.PyStackFrame;
-
-/**
- * @author Fabio
- *
- */
-public class PydevDebugConsoleFrame {
-
-    /**
-     * Last selected frame in the debug console
-     */
-    private PyStackFrame lastSelectedFrame;
-
-    /**
-     * By default, debug console will be linked with the selected frame
-     */
-    private boolean isLinkedWithDebug = true;
-
-    /**
-     * @return the currently selected / suspended frame.
-     */
-    public static PyStackFrame getCurrentSuspendedPyStackFrame() {
-        IAdaptable context = DebugUITools.getDebugContext();
-
-        if (context instanceof PyStackFrame) {
-            PyStackFrame stackFrame = (PyStackFrame) context;
-            if (!stackFrame.isTerminated() && stackFrame.isSuspended()) {
-                return stackFrame;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * If debug console is linked with the selected frame in debug window, then
-     * it returns the current suspended frame. Otherwise it returns the frame
-     * that was selected on the last line of execution.
-     * 
-     * @return selectedFrame in debug view
-     */
-    public PyStackFrame getLastSelectedFrame() {
-        if (lastSelectedFrame == null) {
-            lastSelectedFrame = getCurrentSuspendedPyStackFrame();
-        }
-
-        if (isLinkedWithDebug) {
-            lastSelectedFrame = getCurrentSuspendedPyStackFrame();
-            return lastSelectedFrame;
-        } else { // Console is not linked with debug selection
-            if (lastSelectedFrame == null) {
-                return null;
-            } else {
-                if (lastSelectedFrame.getThread().isSuspended()) {
-                    // Debugger is currently paused
-                    return lastSelectedFrame;
-                } else { // return null if debugger is not paused
-                    return null;
-                }
-            }
-        }
-    }
-
-    /**
-     * Enable/Disable linking of the debug console with the suspended frame.
-     * 
-     * @param isLinkedWithDebug
-     */
-    public void linkWithDebugSelection(boolean isLinkedWithDebug) {
-        this.isLinkedWithDebug = isLinkedWithDebug;
-    }
-
-}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevScriptConsoleSourceViewerConfiguration.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevScriptConsoleSourceViewerConfiguration.java
index eaf7d10..cfd56f0 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevScriptConsoleSourceViewerConfiguration.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/PydevScriptConsoleSourceViewerConfiguration.java
@@ -9,69 +9,78 @@
 * Contributors:
 *     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
 ******************************************************************************/
-package org.python.pydev.debug.newconsole;
-
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IInformationControlCreator;
-import org.eclipse.jface.text.ITextHover;
-import org.eclipse.jface.text.contentassist.IContentAssistant;
-import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
-import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.text.source.SourceViewerConfiguration;
-import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
-import org.python.pydev.editor.codecompletion.PyContentAssistant;
-
-/**
- * Configuration for the source viewer.
- */
-public class PydevScriptConsoleSourceViewerConfiguration extends SourceViewerConfiguration {
-
-    public static final String PARTITION_TYPE = IDocument.DEFAULT_CONTENT_TYPE;
-
-    private ITextHover hover;
-
-    private PyContentAssistant contentAssist;
-
-    private IQuickAssistAssistant quickAssist;
-
-    public PydevScriptConsoleSourceViewerConfiguration(ITextHover hover, PyContentAssistant contentAssist,
-            IQuickAssistAssistant quickAssist) {
-        this.hover = hover;
-        this.contentAssist = contentAssist;
-        this.quickAssist = quickAssist;
-    }
-
-    public int getTabWidth(ISourceViewer sourceViewer) {
-        return DefaultIndentPrefs.getStaticTabWidth();
-    }
-
-    public ITextHover getTextHover(ISourceViewer sv, String contentType) {
-        return hover;
-    }
-
-    public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
-        return new String[] { PARTITION_TYPE };
-    }
-
-    @Override
-    public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
-        contentAssist.setInformationControlCreator(this.getInformationControlCreator(sourceViewer));
-        return contentAssist;
-    }
-
-    @Override
-    public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
-        quickAssist.setInformationControlCreator(this.getInformationControlCreator(sourceViewer));
-        return quickAssist;
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getInformationControlCreator(org.eclipse.jface.text.source.ISourceViewer)
-     */
-    public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) {
-        return PyContentAssistant.createInformationControlCreator(sourceViewer);
-    }
-
-}
+package org.python.pydev.debug.newconsole;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
+import org.python.pydev.editor.codecompletion.PyContentAssistant;
+
+/**
+ * Configuration for the source viewer.
+ */
+public class PydevScriptConsoleSourceViewerConfiguration extends SourceViewerConfiguration {
+
+    public static final String PARTITION_TYPE = IDocument.DEFAULT_CONTENT_TYPE;
+
+    private ITextHover hover;
+
+    private PyContentAssistant contentAssist;
+
+    private IQuickAssistAssistant quickAssist;
+
+    public PydevScriptConsoleSourceViewerConfiguration(ITextHover hover, PyContentAssistant contentAssist,
+            IQuickAssistAssistant quickAssist) {
+        this.hover = hover;
+        this.contentAssist = contentAssist;
+        this.quickAssist = quickAssist;
+    }
+
+    @Override
+    public int getTabWidth(ISourceViewer sourceViewer) {
+        IAdaptable adaptable = null;
+        if (sourceViewer instanceof IAdaptable) {
+            adaptable = (IAdaptable) sourceViewer;
+        }
+        return new DefaultIndentPrefs(adaptable).getTabWidth();
+    }
+
+    @Override
+    public ITextHover getTextHover(ISourceViewer sv, String contentType) {
+        return hover;
+    }
+
+    @Override
+    public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) {
+        return new String[] { PARTITION_TYPE };
+    }
+
+    @Override
+    public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
+        contentAssist.setInformationControlCreator(this.getInformationControlCreator(sourceViewer));
+        return contentAssist;
+    }
+
+    @Override
+    public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
+        quickAssist.setInformationControlCreator(this.getInformationControlCreator(sourceViewer));
+        return quickAssist;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getInformationControlCreator(org.eclipse.jface.text.source.ISourceViewer)
+     */
+    @Override
+    public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) {
+        return PyContentAssistant.createInformationControlCreator(sourceViewer);
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/actions/DebugConsoleAction.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/actions/DebugConsoleAction.java
index ac934a2..2608607 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/actions/DebugConsoleAction.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/actions/DebugConsoleAction.java
@@ -15,13 +15,13 @@ package org.python.pydev.debug.newconsole.actions;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.ui.console.ConsolePlugin;
 import org.python.pydev.debug.model.PyStackFrame;
+import org.python.pydev.debug.newconsole.AnyPyStackFrameSelected;
 import org.python.pydev.debug.newconsole.PydevConsoleFactory;
-import org.python.pydev.debug.newconsole.PydevDebugConsoleFrame;
 import org.python.pydev.editor.actions.PyAction;
 
 /**
  * User can also launch pydev/debug console using Debug view context menu
- * 
+ *
  * @author hussain.bohra
  */
 public class DebugConsoleAction extends PyAction {
@@ -29,10 +29,12 @@ public class DebugConsoleAction extends PyAction {
     // Initialize the console factory class
     private static final PydevConsoleFactory fFactory = new PydevConsoleFactory();
 
+    @Override
     public void run(IAction action) {
         try {
-            PyStackFrame suspendedFrame = PydevDebugConsoleFrame.getCurrentSuspendedPyStackFrame();
-            fFactory.createDebugConsole(suspendedFrame, null);
+            AnyPyStackFrameSelected anyPyStackFrameSelected = new AnyPyStackFrameSelected();
+            PyStackFrame suspendedFrame = anyPyStackFrameSelected.getLastSelectedFrame();
+            fFactory.createDebugConsole(suspendedFrame, null, true, true, anyPyStackFrameSelected);
         } catch (Exception e) {
             ConsolePlugin.log(e);
         }
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevIProcessFactory.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevIProcessFactory.java
index d38690d..3d5f6e2 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevIProcessFactory.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevIProcessFactory.java
@@ -15,11 +15,13 @@ import java.util.List;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationType;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.core.ILaunchManager;
 import org.eclipse.debug.core.Launch;
+import org.eclipse.debug.core.model.IDebugTarget;
 import org.eclipse.debug.core.model.IProcess;
 import org.eclipse.debug.ui.IDebugUIConstants;
 import org.eclipse.jface.dialogs.MessageDialog;
@@ -33,6 +35,7 @@ import org.eclipse.ui.dialogs.SelectionDialog;
 import org.python.pydev.core.IInterpreterInfo;
 import org.python.pydev.core.IInterpreterManager;
 import org.python.pydev.core.IPythonNature;
+import org.python.pydev.core.log.Log;
 import org.python.pydev.debug.core.PydevDebugPlugin;
 import org.python.pydev.debug.model.PyStackFrame;
 import org.python.pydev.debug.newconsole.PydevConsoleConstants;
@@ -48,7 +51,7 @@ import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.ui.pythonpathconf.AbstractInterpreterPreferencesPage;
 
 /**
- * This class is used to create the given IProcess and get the console that is attached to that process. 
+ * This class is used to create the given IProcess and get the console that is attached to that process.
  */
 public class PydevIProcessFactory {
 
@@ -60,6 +63,7 @@ public class PydevIProcessFactory {
         public final PyStackFrame frame;
         public final String[] cmdLine;
         public final String[] env;
+        public final String encoding;
 
         /**
          * @param launch
@@ -67,11 +71,11 @@ public class PydevIProcessFactory {
          * @param clientPort
          * @param interpreter
          * @param frame
-         * @param env 
-         * @param cmdLine 
+         * @param env
+         * @param cmdLine
          */
         public PydevConsoleLaunchInfo(Launch launch, Process process, int clientPort, IInterpreterInfo interpreter,
-                PyStackFrame frame, String[] cmdLine, String[] env) {
+                PyStackFrame frame, String[] cmdLine, String[] env, String encoding) {
             this.launch = launch;
             this.process = process;
             this.clientPort = clientPort;
@@ -79,6 +83,7 @@ public class PydevIProcessFactory {
             this.frame = frame;
             this.cmdLine = cmdLine;
             this.env = env;
+            this.encoding = encoding;
         }
     }
 
@@ -99,15 +104,15 @@ public class PydevIProcessFactory {
 
     /**
      * Creates a launch (and its associated IProcess) for the xml-rpc server to be used in the interactive console.
-     * 
+     *
      * It'll ask the user how to create it:
      * - editor
      * - python interpreter
      * - jython interpreter
-     * 
+     *
      * @return the Launch, the Process created and the port that'll be used for the server to call back into
      * this client for requesting input.
-     * 
+     *
      * @throws UserCanceledException
      * @throws Exception
      */
@@ -125,10 +130,13 @@ public class PydevIProcessFactory {
         ChooseProcessTypeDialog dialog = new ChooseProcessTypeDialog(getShell(), edit);
         if (dialog.open() == ChooseProcessTypeDialog.OK) {
 
-            if (dialog.getSelectedFrame() != null) {
+            PyStackFrame selectedFrame = dialog.getSelectedFrame();
+            if (selectedFrame != null) {
                 // Interpreter not required for Debug Console
-                return new PydevConsoleLaunchInfo(null, null, 0, null, dialog.getSelectedFrame(),
-                        new String[] { "Debug connection (no command line)" }, null);
+                String encoding = getEncodingFromFrame(selectedFrame);
+
+                return new PydevConsoleLaunchInfo(null, null, 0, null, selectedFrame,
+                        new String[] { "Debug connection (no command line)" }, null, encoding);
             }
 
             IInterpreterManager interpreterManager = dialog.getInterpreterManager();
@@ -180,6 +188,42 @@ public class PydevIProcessFactory {
         return null;
     }
 
+    public static String getEncodingFromFrame(PyStackFrame selectedFrame) {
+        try {
+            IDebugTarget adapter = (IDebugTarget) selectedFrame.getAdapter(IDebugTarget.class);
+            if (adapter == null) {
+                return "UTF-8";
+            }
+            IProcess process = adapter.getProcess();
+            if (process == null) {
+                return "UTF-8";
+            }
+            ILaunch launch = process.getLaunch();
+            if (launch == null) {
+                Log.log("Unable to get launch for: " + process);
+                return "UTF-8";
+            }
+            return getEncodingFromLaunch(launch);
+        } catch (Exception e) {
+            Log.log(e);
+            return "UTF-8";
+        }
+    }
+
+    public static String getEncodingFromLaunch(ILaunch launch) {
+        try {
+            String encoding = launch.getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING);
+            if (encoding == null) {
+                Log.log("Unable to get: " + DebugPlugin.ATTR_CONSOLE_ENCODING + " from launch.");
+                return "UTF-8";
+            }
+            return encoding;
+        } catch (Exception e) {
+            Log.log(e);
+            return "UTF-8";
+        }
+    }
+
     private static ILaunchConfiguration createLaunchConfig() {
         ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
         ILaunchConfigurationType launchConfigurationType = manager
@@ -244,6 +288,12 @@ public class PydevIProcessFactory {
         String[] cmdLine;
         String[] env;
 
+        String encoding = PydevDebugPlugin.getDefault().getPreferenceStore()
+                .getString(PydevConsoleConstants.INTERACTIVE_CONSOLE_ENCODING);
+        if (encoding.trim().length() == 0) {
+            encoding = "UTF-8"; //Default is utf-8
+        }
+
         if (interpreterManager.getInterpreterType() == IInterpreterManager.INTERPRETER_TYPE_JYTHON_ECLIPSE) {
             process = new JythonEclipseProcess(scriptWithinPySrc.getAbsolutePath(), port, clientPort);
             cmdLine = new String[] { "Internal Jython process (no command line)" };
@@ -253,9 +303,10 @@ public class PydevIProcessFactory {
             env = SimpleRunner.createEnvWithPythonpath(pythonpathEnv, interpreter.getExecutableOrJar(),
                     interpreterManager, nature);
             // Add in UMD settings
-            String[] s = new String[env.length + 3];
+            String[] s = new String[env.length + 4];
             System.arraycopy(env, 0, s, 0, env.length);
 
+            s[s.length - 4] = "PYTHONIOENCODING=" + encoding;
             s[s.length - 3] = "PYDEV_UMD_ENABLED="
                     + Boolean.toString(InteractiveConsoleUMDPrefs.isUMDEnabled());
             s[s.length - 2] = "PYDEV_UMD_NAMELIST="
@@ -268,11 +319,11 @@ public class PydevIProcessFactory {
             process = SimpleRunner.createProcess(commandLine, env, null);
         }
 
-        IProcess newProcess = new PydevSpawnedInterpreterProcess(launch, process, interpreter.getNameForUI(), null);
+        IProcess newProcess = new PydevSpawnedInterpreterProcess(launch, process, interpreter.getNameForUI(), encoding);
 
         launch.addProcess(newProcess);
 
-        return new PydevConsoleLaunchInfo(launch, process, clientPort, interpreter, null, cmdLine, env);
+        return new PydevConsoleLaunchInfo(launch, process, clientPort, interpreter, null, cmdLine, env, encoding);
     }
 
 }
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevSpawnedInterpreterProcess.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevSpawnedInterpreterProcess.java
index be8615b..a4a2fec 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevSpawnedInterpreterProcess.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/env/PydevSpawnedInterpreterProcess.java
@@ -6,8 +6,7 @@
  */
 package org.python.pydev.debug.newconsole.env;
 
-import java.util.Map;
-
+import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.model.IProcess;
 import org.eclipse.debug.core.model.IStreamsProxy;
@@ -19,13 +18,14 @@ import org.python.pydev.debug.core.Constants;
  */
 public class PydevSpawnedInterpreterProcess extends RuntimeProcess {
 
-    public PydevSpawnedInterpreterProcess(ILaunch launch, Process process, String name, Map attributes) {
-        super(launch, process, name, attributes);
+    public PydevSpawnedInterpreterProcess(ILaunch launch, Process process, String name, String encoding) {
+        super(launch, process, name, null);
         this.setAttribute(IProcess.ATTR_PROCESS_TYPE, Constants.PROCESS_TYPE);
+        this.setAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING, encoding);
     }
 
     /**
-     * PydevSpawnedInterpreterProcess handles the IO in a custom way, so we don't 
+     * PydevSpawnedInterpreterProcess handles the IO in a custom way, so we don't
      * use the streams proxy.
      */
     @Override
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/ColorManager.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/ColorManager.java
index d90d3bb..59e00f2 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/ColorManager.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/ColorManager.java
@@ -17,6 +17,7 @@ import org.eclipse.jface.text.TextAttribute;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.widgets.Display;
+import org.python.pydev.core.log.Log;
 import org.python.pydev.debug.core.PydevDebugPlugin;
 import org.python.pydev.debug.newconsole.PydevConsoleConstants;
 import org.python.pydev.shared_core.SharedCorePlugin;
@@ -192,9 +193,13 @@ public class ColorManager {
     }
 
     public Color getColor(RGB rgb) {
+        Display current = Display.getCurrent();
+        if (current == null) {
+            Log.log("Should not try to get color in a non-ui thread (it will fail if the color is not cached!)");
+        }
         Color color = fColorTable.get(rgb);
         if (color == null) {
-            color = new Color(Display.getCurrent(), rgb);
+            color = new Color(current, rgb);
             fColorTable.put(rgb, color);
         }
         return color;
@@ -212,7 +217,7 @@ public class ColorManager {
      * @param type: see constants at {@link PydevConsoleConstants}
      * @return a color to be used.
      */
-    private Color getPreferenceColor(String type) {
+    public Color getPreferenceColor(String type) {
         if (SharedCorePlugin.inTestMode()) {
             return null;
         }
@@ -258,6 +263,7 @@ public class ColorManager {
         Color color = getPreferenceColor(PydevConsoleConstants.CONSOLE_PROMPT_COLOR);
         return new TextAttribute(color, null, 0);
     }
+
     //[[[end]]]
 
     public Color getConsoleBackgroundColor() {
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsoleInitialCommandsPreferencesPage.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsoleInitialCommandsPreferencesPage.java
new file mode 100644
index 0000000..979ea17
--- /dev/null
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsoleInitialCommandsPreferencesPage.java
@@ -0,0 +1,36 @@
+package org.python.pydev.debug.newconsole.prefs;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.python.pydev.debug.core.PydevDebugPlugin;
+import org.python.pydev.debug.newconsole.PydevConsoleConstants;
+import org.python.pydev.shared_ui.field_editors.MultiStringFieldEditor;
+
+public class InteractiveConsoleInitialCommandsPreferencesPage extends FieldEditorPreferencePage implements
+        IWorkbenchPreferencePage {
+
+    public InteractiveConsoleInitialCommandsPreferencesPage() {
+        super(FLAT);
+    }
+
+    @Override
+    protected void createFieldEditors() {
+        Composite p = getFieldEditorParent();
+        addField(new MultiStringFieldEditor(PydevConsoleConstants.INITIAL_INTERPRETER_CMDS,
+                "Initial interpreter commands.\n\nCan use variables from:\nRun/Debug > String Substitution", p));
+
+        addField(new MultiStringFieldEditor(
+                PydevConsoleConstants.DJANGO_INTERPRETER_CMDS,
+                "Django interpreter commands.\n\nCan use variables from:\nRun/Debug > String Substitution\n\nUse ${DJANGO_SETTINGS_MODULE} to access\nthe project's Django settings module.",
+                p));
+
+    }
+
+    public void init(IWorkbench workbench) {
+        setDescription("PyDev interactive console initial commands.");
+        setPreferenceStore(PydevDebugPlugin.getDefault().getPreferenceStore());
+    }
+
+}
diff --git a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsolePrefs.java b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsolePrefs.java
index 1b8ab36..4b5d1bf 100644
--- a/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsolePrefs.java
+++ b/plugins/org.python.pydev.debug/src_console/org/python/pydev/debug/newconsole/prefs/InteractiveConsolePrefs.java
@@ -21,7 +21,6 @@ import org.python.pydev.debug.newconsole.PydevConsoleConstants;
 import org.python.pydev.shared_core.SharedCorePlugin;
 import org.python.pydev.shared_interactive_console.InteractiveConsolePlugin;
 import org.python.pydev.shared_interactive_console.console.ui.ScriptConsoleUIConstants;
-import org.python.pydev.shared_ui.field_editors.MultiStringFieldEditor;
 
 public class InteractiveConsolePrefs extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
 
@@ -35,28 +34,26 @@ public class InteractiveConsolePrefs extends FieldEditorPreferencePage implement
     protected void createFieldEditors() {
         Composite p = getFieldEditorParent();
 
-        ColorFieldEditor sysout = new ColorFieldEditor(PydevConsoleConstants.CONSOLE_OUTPUT_COLOR, "Stdout color", p);
-        ColorFieldEditor syserr = new ColorFieldEditor(PydevConsoleConstants.CONSOLE_ERROR_COLOR, "Stderr color", p);
-        ColorFieldEditor sysin = new ColorFieldEditor(PydevConsoleConstants.CONSOLE_INPUT_COLOR, "Stdin color", p);
-        ColorFieldEditor prompt = new ColorFieldEditor(PydevConsoleConstants.CONSOLE_PROMPT_COLOR, "Prompt color", p);
-        ColorFieldEditor background = new ColorFieldEditor(PydevConsoleConstants.CONSOLE_BACKGROUND_COLOR,
-                "Background color", p);
-        ColorFieldEditor debugBackground = new ColorFieldEditor(PydevConsoleConstants.DEBUG_CONSOLE_BACKGROUND_COLOR,
-                "Debug console background color", p);
-
-        addField(sysout);
-        addField(syserr);
-        addField(sysin);
-        addField(prompt);
-        addField(background);
-        addField(debugBackground);
-
-        addField(new MultiStringFieldEditor(PydevConsoleConstants.INITIAL_INTERPRETER_CMDS,
-                "Initial interpreter commands.\n\nCan use variables from:\nRun/Debug > String Substitution", p));
+        addField(new ColorFieldEditor(PydevConsoleConstants.CONSOLE_OUTPUT_COLOR, "Stdout color", p));
+
+        addField(new ColorFieldEditor(PydevConsoleConstants.CONSOLE_ERROR_COLOR, "Stderr color", p));
+
+        addField(new ColorFieldEditor(PydevConsoleConstants.CONSOLE_INPUT_COLOR, "Stdin color", p));
+
+        addField(new ColorFieldEditor(PydevConsoleConstants.CONSOLE_PROMPT_COLOR, "Prompt color", p));
+
+        addField(new ColorFieldEditor(PydevConsoleConstants.CONSOLE_BACKGROUND_COLOR,
+                "Background color", p));
+
+        addField(new ColorFieldEditor(PydevConsoleConstants.DEBUG_CONSOLE_BACKGROUND_COLOR,
+                "Debug console background color", p));
 
         addField(new StringFieldEditor(PydevConsoleConstants.INTERACTIVE_CONSOLE_VM_ARGS,
                 "Vm Args for jython\n(used only on external\nprocess option):", p));
 
+        addField(new StringFieldEditor(PydevConsoleConstants.INTERACTIVE_CONSOLE_ENCODING,
+                "Encoding for interactive console:", p));
+
         addField(new IntegerFieldEditor(PydevConsoleConstants.INTERACTIVE_CONSOLE_MAXIMUM_CONNECTION_ATTEMPTS,
                 "Maximum connection attempts\nfor initial communication:", p));
 
diff --git a/plugins/org.python.pydev.debug/tests/org/python/pydev/debug/newconsole/PydevConsoleDebugCommsTest.java b/plugins/org.python.pydev.debug/tests/org/python/pydev/debug/newconsole/PydevConsoleDebugCommsTest.java
index a1341f4..8a25e5e 100644
--- a/plugins/org.python.pydev.debug/tests/org/python/pydev/debug/newconsole/PydevConsoleDebugCommsTest.java
+++ b/plugins/org.python.pydev.debug/tests/org/python/pydev/debug/newconsole/PydevConsoleDebugCommsTest.java
@@ -81,6 +81,7 @@ public class PydevConsoleDebugCommsTest extends TestCase {
         Map<String, String> env = new TreeMap<String, String>();
         env.put("HOME", homeDir.toString());
         env.put("PYTHONPATH", pydevdDir);
+        env.put("PYTHONIOENCODING", "utf-8");
         String sysRoot = System.getenv("SystemRoot");
         if (sysRoot != null) {
             env.put("SystemRoot", sysRoot); //Needed on windows boxes (random/socket. module needs it to work).
@@ -96,10 +97,10 @@ public class PydevConsoleDebugCommsTest extends TestCase {
         }
 
         process = SimpleRunner.createProcess(cmdarray, envp, null);
-        pydevConsoleCommunication = new PydevConsoleCommunication(port, process, clientPort, cmdarray, envp);
+        pydevConsoleCommunication = new PydevConsoleCommunication(port, process, clientPort, cmdarray, envp, "utf-8");
         pydevConsoleCommunication.hello(new NullProgressMonitor());
 
-        ServerSocket socket = new ServerSocket(0);
+        ServerSocket socket = SocketUtil.createLocalServerSocket();
         pydevConsoleCommunication.connectToDebugger(socket.getLocalPort());
         socket.setSoTimeout(5000);
         Socket accept = socket.accept();
@@ -209,24 +210,38 @@ public class PydevConsoleDebugCommsTest extends TestCase {
 
     }
 
-    private void execInterpreter(String command) {
-        final Boolean done[] = new Boolean[1];
+    private InterpreterResponse execInterpreter(String command) {
+        final InterpreterResponse response[] = new InterpreterResponse[1];
         ICallback<Object, InterpreterResponse> onResponseReceived = new ICallback<Object, InterpreterResponse>() {
 
             public Object call(InterpreterResponse arg) {
-                done[0] = true;
+                response[0] = arg;
                 return null;
             }
         };
         pydevConsoleCommunication.execInterpreter(command, onResponseReceived);
-        waitUntilNonNull(done);
+        waitUntilNonNull(response);
+        return response[0];
+    }
+
+    /**
+     * #PyDev-502: PyDev 3.9 F2 doesn't support backslash continuations
+     */
+    public void testContinuation() throws Exception {
+
+        InterpreterResponse response = execInterpreter("from os import \\\n");
+        assertTrue(response.more);
+        response = execInterpreter("  path,\\\n");
+        assertTrue(response.more);
+        response = execInterpreter("  remove\n");
+        assertTrue(response.more);
+        response = execInterpreter("\n");
     }
 
     /**
      * Test that variables can be seen
      */
     public void testVariable() throws Exception {
-
         execInterpreter("my_var=1");
 
         IVariableLocator frameLocator = new IVariableLocator() {
diff --git a/plugins/org.python.pydev.django/META-INF/MANIFEST.MF b/plugins/org.python.pydev.django/META-INF/MANIFEST.MF
index 5ccca4d..06000b5 100644
--- a/plugins/org.python.pydev.django/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.django/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Pydev Django
 Bundle-SymbolicName: org.python.pydev.django;singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Vendor: Aptana
 Bundle-Activator: org.python.pydev.django.DjangoPlugin
 Eclipse-BundleShape: dir
diff --git a/plugins/org.python.pydev.django/plugin.xml b/plugins/org.python.pydev.django/plugin.xml
index b5d01f3..b1be313 100644
--- a/plugins/org.python.pydev.django/plugin.xml
+++ b/plugins/org.python.pydev.django/plugin.xml
@@ -165,9 +165,25 @@
 	               class="org.python.pydev.django.debug.ui.actions.DjangoSyncDB"
 	               enablesFor="+"
 	               id="org.python.pydev.django.debug.ui.actions.project.djangoSyncDB"
-	               label="Sync DB (manage.py syncdb)" 
+	               label="SyncDB (Django < 1.7) (manage.py syncdb)" 
 	               menubarPath="org.python.pydev.django.ui.django.menu/common"
-	               tooltip="Synchronize database">
+	               tooltip="Migrate database Django < 1.7">
+	         </action>	   
+	         <action
+	               class="org.python.pydev.django.debug.ui.actions.DjangoMigrate"
+	               enablesFor="+"
+	               id="org.python.pydev.django.debug.ui.actions.project.djangoMigrate"
+	               label="Migrate (Django >= 1.7) (manage.py migrate)" 
+	               menubarPath="org.python.pydev.django.ui.django.menu/common"
+	               tooltip="Migrate database Django >= 1.7">
+	         </action>	   
+	         <action
+	               class="org.python.pydev.django.debug.ui.actions.DjangoMakeMigrations"
+	               enablesFor="+"
+	               id="org.python.pydev.django.debug.ui.actions.project.djangoMakeMigrations"
+	               label="Make Migrations (Django >= 1.7) (manage.py makemigrations)" 
+	               menubarPath="org.python.pydev.django.ui.django.menu/common"
+	               tooltip="Make database migrations Django >= 1.7">
 	         </action>	   
 	         <action
 	               class="org.python.pydev.django.debug.ui.actions.DjangoCustomCommand"
diff --git a/plugins/org.python.pydev.django/pom.xml b/plugins/org.python.pydev.django/pom.xml
index 4fd3653..7844853 100644
--- a/plugins/org.python.pydev.django/pom.xml
+++ b/plugins/org.python.pydev.django/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMakeMigrations.java b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMakeMigrations.java
new file mode 100644
index 0000000..c8e83d5
--- /dev/null
+++ b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMakeMigrations.java
@@ -0,0 +1,39 @@
+package org.python.pydev.django.debug.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.python.pydev.shared_ui.EditorUtils;
+
+public class DjangoMakeMigrations extends DjangoAction {
+
+    @Override
+    public void run(IAction action) {
+        IInputValidator validator = new IInputValidator() {
+
+            public String isValid(String newText) {
+                if (newText.trim().length() == 0) {
+                    return "Name cannot be empty";
+                }
+                return null;
+            }
+        };
+        InputDialog d = new InputDialog(EditorUtils.getShell(), "App name",
+                "Name of the django app to makemigrations on", "",
+                validator);
+
+        int retCode = d.open();
+        if (retCode == InputDialog.OK) {
+            createApp(d.getValue().trim());
+        }
+    }
+
+    private void createApp(String name) {
+        try {
+            launchDjangoCommand("makemigrations " + name, true);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMigrate.java
similarity index 79%
copy from plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java
copy to plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMigrate.java
index 853d9a7..1577af0 100644
--- a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java
+++ b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoMigrate.java
@@ -8,10 +8,11 @@ package org.python.pydev.django.debug.ui.actions;
 
 import org.eclipse.jface.action.IAction;
 
-public class DjangoSyncDB extends DjangoAction {
+public class DjangoMigrate extends DjangoAction {
 
+    @Override
     public void run(IAction action) {
-        launchDjangoCommand("syncdb", true);
+        launchDjangoCommand("migrate", true);
     }
 
 }
diff --git a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoShell.java b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoShell.java
index cdbee0e..53644af 100644
--- a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoShell.java
+++ b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoShell.java
@@ -17,6 +17,8 @@ import org.eclipse.jface.dialogs.MessageDialog;
 import org.python.pydev.core.IPythonNature;
 import org.python.pydev.core.IPythonPathNature;
 import org.python.pydev.core.log.Log;
+import org.python.pydev.debug.core.PydevDebugPlugin;
+import org.python.pydev.debug.newconsole.PydevConsoleConstants;
 import org.python.pydev.debug.newconsole.PydevConsoleFactory;
 import org.python.pydev.debug.newconsole.PydevConsoleInterpreter;
 import org.python.pydev.debug.newconsole.env.PydevIProcessFactory;
@@ -96,19 +98,17 @@ public class DjangoShell extends DjangoAction {
                     nature.getPythonPathNature().getCompleteProjectPythonPath(nature.getProjectInterpreter(),
                             nature.getRelatedInterpreterManager()), nature, natures);
 
-            PydevConsoleInterpreter interpreter = PydevConsoleFactory.createPydevInterpreter(launchInfo, natures);
+            PydevConsoleInterpreter interpreter = PydevConsoleFactory.createPydevInterpreter(launchInfo, natures,
+                    launchInfo.encoding);
 
-            String newVersion = "import os; os.environ['DJANGO_SETTINGS_MODULE'] = '" + settingsModule
-                    + "'; import django\n"
-                    + "if django.get_version() < '1.5': ";
+            String djangoAdditionalCommands = PydevDebugPlugin.getDefault().getPreferenceStore().
+                    getString(PydevConsoleConstants.DJANGO_INTERPRETER_CMDS);
 
-            String importStr = "import " + settingsModule + " as settings; ";//"from " + selectedProject.getName() + " import settings;";
-            String old = "from django.core import management; " + importStr
-                    + "management.setup_environ(settings)\n\n";
-            String additionalInitialComands = newVersion + old;
+            djangoAdditionalCommands = djangoAdditionalCommands.replace("${"
+                    + DjangoConstants.DJANGO_SETTINGS_MODULE + "}", settingsModule);
 
             //os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fooproject.settings")
-            consoleFactory.createConsole(interpreter, additionalInitialComands);
+            consoleFactory.createConsole(interpreter, djangoAdditionalCommands);
 
         } catch (Exception e) {
             throw new RuntimeException(e);
diff --git a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java
index 853d9a7..8631554 100644
--- a/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java
+++ b/plugins/org.python.pydev.django/src/org/python/pydev/django/debug/ui/actions/DjangoSyncDB.java
@@ -10,6 +10,7 @@ import org.eclipse.jface.action.IAction;
 
 public class DjangoSyncDB extends DjangoAction {
 
+    @Override
     public void run(IAction action) {
         launchDjangoCommand("syncdb", true);
     }
diff --git a/plugins/org.python.pydev.help/META-INF/MANIFEST.MF b/plugins/org.python.pydev.help/META-INF/MANIFEST.MF
index bf8c8ae..f177280 100644
--- a/plugins/org.python.pydev.help/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.help/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Pydev Online Help
 Bundle-SymbolicName: org.python.pydev.help; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Vendor: Aptana
 Bundle-Localization: plugin
 Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.python.pydev.help/pom.xml b/plugins/org.python.pydev.help/pom.xml
index c7f06ed..f75b1fa 100644
--- a/plugins/org.python.pydev.help/pom.xml
+++ b/plugins/org.python.pydev.help/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.jython/META-INF/MANIFEST.MF b/plugins/org.python.pydev.jython/META-INF/MANIFEST.MF
index d5778e5..04d0d21 100644
--- a/plugins/org.python.pydev.jython/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.jython/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Jython Plug-in
 Bundle-SymbolicName: org.python.pydev.jython; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: pydev-jython.jar,
  jython.jar
 Bundle-Activator: org.python.pydev.jython.JythonPlugin
diff --git a/plugins/org.python.pydev.jython/pom.xml b/plugins/org.python.pydev.jython/pom.xml
index 29ecbbb..a9c1986 100644
--- a/plugins/org.python.pydev.jython/pom.xml
+++ b/plugins/org.python.pydev.jython/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.mylyn/pom.xml b/plugins/org.python.pydev.mylyn/pom.xml
index a2cc29d..8f83f39 100644
--- a/plugins/org.python.pydev.mylyn/pom.xml
+++ b/plugins/org.python.pydev.mylyn/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.parser/META-INF/MANIFEST.MF b/plugins/org.python.pydev.parser/META-INF/MANIFEST.MF
index ba4b156..5915262 100644
--- a/plugins/org.python.pydev.parser/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.parser/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Parser Plug-in
 Bundle-SymbolicName: org.python.pydev.parser; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: parser.jar
 Bundle-Activator: org.python.pydev.parser.ParserPlugin
 Bundle-Localization: plugin
diff --git a/plugins/org.python.pydev.parser/pom.xml b/plugins/org.python.pydev.parser/pom.xml
index 1868294..bf934e4 100644
--- a/plugins/org.python.pydev.parser/pom.xml
+++ b/plugins/org.python.pydev.parser/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/fastparser/FastParser.java b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/fastparser/FastParser.java
index c0f93d0..261a62f 100644
--- a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/fastparser/FastParser.java
+++ b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/fastparser/FastParser.java
@@ -7,7 +7,9 @@
 package org.python.pydev.parser.fastparser;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -17,12 +19,15 @@ import org.python.pydev.core.docutils.ParsingUtils;
 import org.python.pydev.core.docutils.PySelection;
 import org.python.pydev.parser.jython.ast.ClassDef;
 import org.python.pydev.parser.jython.ast.FunctionDef;
+import org.python.pydev.parser.jython.ast.Name;
 import org.python.pydev.parser.jython.ast.NameTok;
 import org.python.pydev.parser.jython.ast.argumentsType;
 import org.python.pydev.parser.jython.ast.decoratorsType;
 import org.python.pydev.parser.jython.ast.exprType;
 import org.python.pydev.parser.jython.ast.stmtType;
+import org.python.pydev.parser.visitors.NodeUtils;
 import org.python.pydev.shared_core.string.DocIterator;
+import org.python.pydev.shared_core.structure.FastStack;
 
 /**
  * This class is able to obtain the classes and function definitions as a tree structure (only filled with
@@ -113,7 +118,7 @@ public final class FastParser {
 
     /**
      * Note: Used from jython scripts.
-     * 
+     *
      * @param doc the document to be parsed
      * @param currentLine the line where the parsing should begin (inclusive -- starts at 0)
      * @return the path to the current statement (where the current is the last element and the top-level is the 1st).
@@ -139,6 +144,10 @@ public final class FastParser {
 
     private List<stmtType> parse() {
         List<stmtType> body = new ArrayList<stmtType>();
+
+        FastStack<stmtType> stack = new FastStack<>(5);
+        Map<Integer, List<stmtType>> objectIdToBody = new HashMap<>();
+
         PySelection ps = new PySelection(doc);
         DocIterator it = new DocIterator(forward, ps, currentLine, false);
 
@@ -201,7 +210,7 @@ public final class FastParser {
                     FunctionDef functionDef = createFunctionDef(lastReturnedLine, nameTok,
                             PySelection.getFirstCharPosition(line));
 
-                    if (!addStatement(body, functionDef)) {
+                    if (!addStatement(body, stack, objectIdToBody, functionDef)) {
                         return body;
                     }
 
@@ -223,7 +232,7 @@ public final class FastParser {
                     ClassDef classDef = createClassDef(lastReturnedLine, nameTok,
                             PySelection.getFirstCharPosition(line));
 
-                    if (!addStatement(body, classDef)) {
+                    if (!addStatement(body, stack, objectIdToBody, classDef)) {
                         return body;
                     }
 
@@ -236,14 +245,62 @@ public final class FastParser {
 
         }
 
+        if (cythonParse) {
+            for (stmtType t : body) {
+                buildBody(t, objectIdToBody);
+            }
+        }
         return body;
     }
 
+    private void buildBody(stmtType t, Map<Integer, List<stmtType>> objectIdToBody) {
+        int id = System.identityHashCode(t);
+        List<stmtType> list = objectIdToBody.get(id);
+        if (list != null) {
+            NodeUtils.setBody(t, list.toArray(new stmtType[0]));
+            for (stmtType stmtType : list) {
+                buildBody(stmtType, objectIdToBody);
+            }
+        }
+
+    }
+
     /**
+     * @param objectIdToBody
      * @return whether we should continue iterating.
      */
-    private boolean addStatement(List<stmtType> body, stmtType stmt) {
-        if (!findGloballyAccessiblePath) {
+    private boolean addStatement(List<stmtType> body, FastStack<stmtType> stack,
+            Map<Integer, List<stmtType>> objectIdToBody, stmtType stmt) {
+        if (cythonParse) {
+            if (stack.empty()) {
+                stack.push(stmt);
+                body.add(stmt); // Globals added to body
+            } else {
+                stmtType prev = stack.peek();
+
+                while (prev.beginColumn >= stmt.beginColumn) {
+                    stack.pop();
+                    if (stack.empty()) {
+                        stack.push(stmt);
+                        body.add(stmt); // Globals added to body
+                        return true;
+                    }
+                    prev = stack.peek();
+                }
+                //If it got here we are inside some context...
+                stack.push(stmt);
+                int id = System.identityHashCode(prev);
+                List<stmtType> prevBody = objectIdToBody.get(id);
+                if (prevBody == null) {
+                    prevBody = new ArrayList<>();
+                    objectIdToBody.put(id, prevBody);
+                }
+                //Inside some other: add to its context (and not to global).
+                prevBody.add(stmt);
+            }
+            return true;
+
+        } else if (!findGloballyAccessiblePath) {
             body.add(stmt);
             return true;
         } else {
@@ -263,8 +320,20 @@ public final class FastParser {
     }
 
     private FunctionDef createFunctionDef(int lastReturnedLine, NameTok nameTok, int matchedCol) {
-        argumentsType args = new argumentsType(EMTPY_EXPR_TYPE, null, null, EMTPY_EXPR_TYPE, null, null, null, null,
-                null, null);
+        argumentsType args;
+        if (cythonParse) {
+            Name name = new Name("self", Name.Store, false);
+            exprType[] selfExprType = new exprType[] { name };
+
+            name.beginLine = lastReturnedLine + 1;
+            name.beginColumn = matchedCol + 1 + 4 + 1 + nameTok.id.length(); // 4 for 'def ' and 1 for '('
+
+            args = new argumentsType(selfExprType, null, null, EMTPY_EXPR_TYPE, null, null, null, null,
+                    null, null);
+        } else {
+            args = new argumentsType(EMTPY_EXPR_TYPE, null, null, EMTPY_EXPR_TYPE, null, null, null, null,
+                    null, null);
+        }
         FunctionDef functionDef = new FunctionDef(nameTok, args, EMTPY_STMT_TYPE, EMTPY_DECORATORS_TYPE, null);
         functionDef.beginLine = lastReturnedLine + 1;
         functionDef.beginColumn = matchedCol + 1;
diff --git a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/jython/ast/factory/AdapterPrefs.java b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/jython/ast/factory/AdapterPrefs.java
index 5cb788b..c9b90cd 100644
--- a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/jython/ast/factory/AdapterPrefs.java
+++ b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/jython/ast/factory/AdapterPrefs.java
@@ -1,14 +1,21 @@
 package org.python.pydev.parser.jython.ast.factory;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.python.pydev.core.IGrammarVersionProvider;
 
 public class AdapterPrefs {
 
     public final String endLineDelim;
     public final IGrammarVersionProvider versionProvider;
+    public final IAdaptable projectAdaptable;
 
     public AdapterPrefs(String endLineDelim, IGrammarVersionProvider versionProvider) {
         this.endLineDelim = endLineDelim;
         this.versionProvider = versionProvider;
+        if (versionProvider instanceof IAdaptable) {
+            projectAdaptable = (IAdaptable) versionProvider;
+        } else {
+            projectAdaptable = null;
+        }
     }
 }
diff --git a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/visitors/NodeUtils.java b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/visitors/NodeUtils.java
index 2bf4625..e2a1d4e 100644
--- a/plugins/org.python.pydev.parser/src/org/python/pydev/parser/visitors/NodeUtils.java
+++ b/plugins/org.python.pydev.parser/src/org/python/pydev/parser/visitors/NodeUtils.java
@@ -1233,6 +1233,63 @@ public class NodeUtils {
     }
 
     /**
+     * Sets the body of some node.
+     */
+    public static void setBody(SimpleNode node, stmtType... body) {
+        if (node instanceof Module) {
+            Module module = (Module) node;
+            module.body = body;
+        }
+
+        if (node instanceof ClassDef) {
+            ClassDef module = (ClassDef) node;
+            module.body = body;
+        }
+
+        if (node instanceof FunctionDef) {
+            FunctionDef module = (FunctionDef) node;
+            module.body = body;
+        }
+
+        if (node instanceof excepthandlerType) {
+            excepthandlerType module = (excepthandlerType) node;
+            module.body = body;
+        }
+        if (node instanceof For) {
+            For module = (For) node;
+            module.body = body;
+        }
+        if (node instanceof If) {
+            If module = (If) node;
+            module.body = body;
+        }
+        if (node instanceof Suite) {
+            Suite module = (Suite) node;
+            module.body = body;
+        }
+        if (node instanceof suiteType) {
+            suiteType module = (suiteType) node;
+            module.body = body;
+        }
+        if (node instanceof TryExcept) {
+            TryExcept module = (TryExcept) node;
+            module.body = body;
+        }
+        if (node instanceof TryFinally) {
+            TryFinally module = (TryFinally) node;
+            module.body = body;
+        }
+        if (node instanceof While) {
+            While module = (While) node;
+            module.body = body;
+        }
+        if (node instanceof With) {
+            With module = (With) node;
+            module.body.body = body;
+        }
+    }
+
+    /**
      * @param node This is the node where we should start looking (usually the Module)
      * @param path This is the path for which we want an item in the given node.
      *        E.g.: If we want to find a method testFoo in a class TestCase, we'de pass TestCase.testFoo as the path.
diff --git a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PyParserEditorIntegrationTest.java b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PyParserEditorIntegrationTest.java
index 0b25882..3f9d91b 100644
--- a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PyParserEditorIntegrationTest.java
+++ b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PyParserEditorIntegrationTest.java
@@ -62,6 +62,11 @@ public class PyParserEditorIntegrationTest extends TestCase {
             return this.cache;
         }
 
+        @Override
+        public Object getAdapter(Class adapter) {
+            return null;
+        }
+
         public boolean hasSameInput(IBaseEditor edit) {
             if (this == edit) {
                 throw new RuntimeException(
diff --git a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PythonNatureStub.java b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PythonNatureStub.java
index aec940a..db46640 100644
--- a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PythonNatureStub.java
+++ b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/PythonNatureStub.java
@@ -11,6 +11,7 @@ import java.io.File;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.python.pydev.core.ICodeCompletionASTManager;
 import org.python.pydev.core.IInterpreterInfo;
@@ -21,7 +22,12 @@ import org.python.pydev.core.IPythonPathNature;
 import org.python.pydev.core.IToken;
 import org.python.pydev.core.MisconfigurationException;
 
-public class PythonNatureStub implements IPythonNature {
+public class PythonNatureStub implements IPythonNature, IAdaptable {
+
+    @Override
+    public Object getAdapter(Class adapter) {
+        throw new RuntimeException("Not implemented");
+    }
 
     public void endRequests() {
         throw new RuntimeException("Not implemented");
diff --git a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/fastparser/FastParserTest.java b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/fastparser/FastParserTest.java
index b7051d1..dde4bae 100644
--- a/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/fastparser/FastParserTest.java
+++ b/plugins/org.python.pydev.parser/tests/org/python/pydev/parser/fastparser/FastParserTest.java
@@ -11,9 +11,15 @@ import java.util.List;
 import junit.framework.TestCase;
 
 import org.eclipse.jface.text.Document;
+import org.python.pydev.core.IGrammarVersionProvider;
+import org.python.pydev.core.MisconfigurationException;
 import org.python.pydev.parser.jython.SimpleNode;
-import org.python.pydev.parser.jython.ast.ClassDef;
+import org.python.pydev.parser.jython.ast.FunctionDef;
+import org.python.pydev.parser.jython.ast.Module;
 import org.python.pydev.parser.jython.ast.stmtType;
+import org.python.pydev.parser.prettyprinter.AbstractPrettyPrinterTestBase;
+import org.python.pydev.parser.prettyprinterv2.IPrettyPrinterPrefs;
+import org.python.pydev.parser.prettyprinterv2.PrettyPrinterPrefsV2;
 import org.python.pydev.parser.visitors.NodeUtils;
 
 /**
@@ -80,16 +86,16 @@ public class FastParserTest extends TestCase {
         check(all, 3, 10, 1, 10, 7);
 
         stmtType found = FastParser.firstClassOrFunction(doc, 1, true, false);
-        checkNode(3, 1, 3, 7, (ClassDef) found);
+        checkNode(3, 1, 3, 7, found);
 
         found = FastParser.firstClassOrFunction(doc, 0, true, false);
-        checkNode(1, 1, 1, 7, (ClassDef) found);
+        checkNode(1, 1, 1, 7, found);
 
         found = FastParser.firstClassOrFunction(doc, 5, true, false);
-        checkNode(10, 1, 10, 7, (ClassDef) found);
+        checkNode(10, 1, 10, 7, found);
 
         found = FastParser.firstClassOrFunction(doc, 5, false, false);
-        checkNode(5, 5, 5, 11, (ClassDef) found);
+        checkNode(5, 5, 5, 11, found);
 
         found = FastParser.firstClassOrFunction(doc, -1, false, false);
         assertNull(found);
@@ -98,7 +104,7 @@ public class FastParserTest extends TestCase {
         assertNull(found);
 
         found = FastParser.firstClassOrFunction(doc, 15, false, false);
-        checkNode(10, 1, 10, 7, (ClassDef) found);
+        checkNode(10, 1, 10, 7, found);
 
     }
 
@@ -186,6 +192,78 @@ public class FastParserTest extends TestCase {
         assertEquals("enum parrot_state:", NodeUtils.getRepresentationString(stmts.get(0)));
     }
 
+    public void testCython3() throws Exception {
+        Document doc = new Document();
+        doc.set(""
+                + "def a():\n"
+                + "    cdef int b\n"
+                + "    b2 = 8\n"
+                + "    return a\n"
+                + "\n"
+                + "def a2():\n"
+                + "    cdef int b\n"
+                + "    b = 6\n"
+                + "    return a\n"
+                + "\n"
+                );
+        List<stmtType> stmts = FastParser.parseCython(doc);
+        assertEquals(2, stmts.size());
+        assertEquals("a", NodeUtils.getRepresentationString(stmts.get(0)));
+
+        FunctionDef st0 = (FunctionDef) stmts.get(0);
+        assertEquals(1, st0.body.length);
+        assertEquals("int b", NodeUtils.getRepresentationString(st0.body[0]));
+
+        assertEquals("a2", NodeUtils.getRepresentationString(stmts.get(1)));
+        FunctionDef st1 = (FunctionDef) stmts.get(1);
+        assertEquals(1, st1.body.length);
+
+        String s = printAst(stmts);
+        assertEquals(""
+                + "def a(self):\n"
+                + "    def int b(self):\n"
+                + "def a2(self):\n"
+                + "    def int b(self):\n"
+                + "", s);
+    }
+
+    public void testCython4() throws Exception {
+        Document doc = new Document();
+        doc.set(""
+                + "def a():\n"
+                + "    cdef int b\n"
+                + "        def c():\n"
+                + "    def d():\n"
+                + "    def e():\n"
+                + "        cdef int b\n"
+                + "\n"
+                );
+        List<stmtType> stmts = FastParser.parseCython(doc);
+
+        String s = printAst(stmts);
+        assertEquals(""
+                + "def a(self):\n"
+                + "    def int b(self):\n"
+                + "        def c(self):\n"
+                + "    def d(self):\n"
+                + "    def e(self):\n"
+                + "        def int b(self):\n"
+                + "", s);
+    }
+
+    private String printAst(List<stmtType> stmts) throws Error {
+        IGrammarVersionProvider versionProvider = new IGrammarVersionProvider() {
+
+            @Override
+            public int getGrammarVersion() throws MisconfigurationException {
+                return IGrammarVersionProvider.GRAMMAR_PYTHON_VERSION_2_7;
+            }
+        };
+        IPrettyPrinterPrefs prefs = new PrettyPrinterPrefsV2("\n", "    ", versionProvider);
+        String s = AbstractPrettyPrinterTestBase.makePrint(prefs, new Module(stmts.toArray(new stmtType[0])));
+        return s;
+    }
+
     public void testBackwardsUntil1stGlobal2() throws Exception {
         Document doc = new Document();
         doc.set("def b():\n" +
diff --git a/plugins/org.python.pydev.refactoring/META-INF/MANIFEST.MF b/plugins/org.python.pydev.refactoring/META-INF/MANIFEST.MF
index 9a241de..dfa342b 100644
--- a/plugins/org.python.pydev.refactoring/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.refactoring/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %peptic.pluginName
 Bundle-SymbolicName: org.python.pydev.refactoring;singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-Activator: org.python.pydev.refactoring.PepticPlugin
 Bundle-Vendor: %peptic.providerName
 Bundle-Localization: plugin
diff --git a/plugins/org.python.pydev.refactoring/pom.xml b/plugins/org.python.pydev.refactoring/pom.xml
index d6b73ff..378ffe4 100644
--- a/plugins/org.python.pydev.refactoring/pom.xml
+++ b/plugins/org.python.pydev.refactoring/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/ClassDefAdapter.java b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/ClassDefAdapter.java
index 97bc275..fd0af6e 100644
--- a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/ClassDefAdapter.java
+++ b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/ClassDefAdapter.java
@@ -141,13 +141,15 @@ public class ClassDefAdapter extends AbstractScopeNode<ClassDef> implements ICla
     /* (non-Javadoc)
      * @see org.python.pydev.refactoring.ast.adapters.IClassDefAdapter#getNodeBodyIndent()
      */
+    @Override
     public String getNodeBodyIndent() {
         ClassDef classNode = getASTNode();
         if (classNode.body == null || classNode.body.length == 0) {
             PySelection pySelection = new PySelection(getModule().getDoc());
             String indentationFromLine = PySelection.getIndentationFromLine(pySelection
                     .getLine(classNode.beginLine - 1));
-            return indentationFromLine + DefaultIndentPrefs.get().getIndentationString();
+            return indentationFromLine
+                    + DefaultIndentPrefs.get(this.getAdapterPrefs().projectAdaptable).getIndentationString();
 
         }
         return getModule().getIndentationFromAst(classNode.body[0]);
@@ -175,6 +177,7 @@ public class ClassDefAdapter extends AbstractScopeNode<ClassDef> implements ICla
     /* (non-Javadoc)
      * @see org.python.pydev.refactoring.ast.adapters.IClassDefAdapter#getAssignedVariables()
      */
+    @Override
     public List<SimpleAdapter> getAssignedVariables() {
         ScopeAssignedVisitor visitor = VisitorFactory.createContextVisitor(ScopeAssignedVisitor.class, getASTNode(),
                 this.getModule(), this);
diff --git a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/FunctionDefAdapter.java b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/FunctionDefAdapter.java
index 8533c0d..57671e2 100644
--- a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/FunctionDefAdapter.java
+++ b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/adapters/FunctionDefAdapter.java
@@ -63,19 +63,22 @@ public class FunctionDefAdapter extends AbstractScopeNode<FunctionDef> {
         return arguments.getSignature();
     }
 
+    @Override
     public String getNodeBodyIndent() {
         FunctionDef functionNode = getASTNode();
         if (functionNode.body == null || functionNode.body.length == 0) {
             PySelection pySelection = new PySelection(getModule().getDoc());
             String indentationFromLine = PySelection.getIndentationFromLine(pySelection
                     .getLine(functionNode.beginLine - 1));
-            return indentationFromLine + DefaultIndentPrefs.get().getIndentationString();
+            return indentationFromLine
+                    + DefaultIndentPrefs.get(this.getAdapterPrefs().projectAdaptable).getIndentationString();
 
         }
 
         return getModule().getIndentationFromAst(functionNode.body[0]);
     }
 
+    @Override
     public List<FunctionDefAdapter> getFunctions() {
         if (this.functions == null) {
             LocalFunctionDefVisitor visitor = null;
@@ -87,6 +90,7 @@ public class FunctionDefAdapter extends AbstractScopeNode<FunctionDef> {
         return this.functions;
     }
 
+    @Override
     public List<SimpleAdapter> getAssignedVariables() {
         ScopeAssignedVisitor visitor = VisitorFactory.createContextVisitor(ScopeAssignedVisitor.class, getASTNode(),
                 this.getModule(), this);
diff --git a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/visitors/rewriter/Rewriter.java b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/visitors/rewriter/Rewriter.java
index 760fe4f..01283a0 100644
--- a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/visitors/rewriter/Rewriter.java
+++ b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/ast/visitors/rewriter/Rewriter.java
@@ -45,7 +45,7 @@ public final class Rewriter {
 
     public static String createSourceFromAST(SimpleNode root, boolean ignoreComments, AdapterPrefs adapterPrefs) {
         IGrammarVersionProvider versionProvider = adapterPrefs.versionProvider;
-        IIndentPrefs indentPrefs = DefaultIndentPrefs.get();
+        IIndentPrefs indentPrefs = DefaultIndentPrefs.get(adapterPrefs.projectAdaptable);
         String endLineDelim = adapterPrefs.endLineDelim;
 
         PrettyPrinterPrefsV2 prettyPrinterPrefs = PrettyPrinterV2.createDefaultPrefs(versionProvider, indentPrefs,
diff --git a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/core/base/RefactoringInfo.java b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/core/base/RefactoringInfo.java
index 8e2efba..8c076c8 100644
--- a/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/core/base/RefactoringInfo.java
+++ b/plugins/org.python.pydev.refactoring/src/org/python/pydev/refactoring/core/base/RefactoringInfo.java
@@ -86,7 +86,7 @@ public class RefactoringInfo {
         if (SharedCorePlugin.inTestMode()) {
             this.indentPrefs = new TestIndentPrefs(document.get().indexOf('\t') < 0, 4);
         } else {
-            this.indentPrefs = DefaultIndentPrefs.get();
+            this.indentPrefs = DefaultIndentPrefs.get(null);
         }
 
         initInfo(selection);
diff --git a/plugins/org.python.pydev.refactoring/tests/org/python/pydev/refactoring/tests/adapter/PythonNatureStub.java b/plugins/org.python.pydev.refactoring/tests/org/python/pydev/refactoring/tests/adapter/PythonNatureStub.java
index 3382c79..2d19141 100644
--- a/plugins/org.python.pydev.refactoring/tests/org/python/pydev/refactoring/tests/adapter/PythonNatureStub.java
+++ b/plugins/org.python.pydev.refactoring/tests/org/python/pydev/refactoring/tests/adapter/PythonNatureStub.java
@@ -36,6 +36,11 @@ import org.python.pydev.core.PythonNatureWithoutProjectException;
 
 public class PythonNatureStub implements IPythonNature {
 
+    @Override
+    public Object getAdapter(Class adapter) {
+        throw new RuntimeException("Not implemented");
+    }
+
     public boolean acceptsDecorators() throws CoreException {
         throw new RuntimeException("Not implemented");
     }
diff --git a/plugins/org.python.pydev.shared_core/.classpath b/plugins/org.python.pydev.shared_core/.classpath
index 34e25e2..ed3b2d8 100644
--- a/plugins/org.python.pydev.shared_core/.classpath
+++ b/plugins/org.python.pydev.shared_core/.classpath
@@ -2,6 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry kind="src" path="tests"/>
+	<classpathentry exported="true" kind="lib" path="libs/snakeyaml-1.11.jar"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/plugins/org.python.pydev.shared_core/META-INF/MANIFEST.MF b/plugins/org.python.pydev.shared_core/META-INF/MANIFEST.MF
index ede0153..65e4b45 100644
--- a/plugins/org.python.pydev.shared_core/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.shared_core/META-INF/MANIFEST.MF
@@ -2,8 +2,9 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Shared Core Plug-in
 Bundle-SymbolicName: org.python.pydev.shared_core;singleton:=true
-Bundle-Version: 3.9.0.qualifier
-Bundle-ClassPath: shared_core.jar
+Bundle-Version: 3.9.2.qualifier
+Bundle-ClassPath: shared_core.jar,
+ libs/snakeyaml-1.11.jar
 Bundle-Activator: org.python.pydev.shared_core.SharedCorePlugin
 Bundle-Localization: plugin
 Eclipse-BundleShape: dir
@@ -12,7 +13,8 @@ Require-Bundle: org.eclipse.core.runtime,
  org.junit;bundle-version="4.0";resolution:=optional,
  org.eclipse.jface,
  org.eclipse.core.resources,
- org.eclipse.core.filebuffers
+ org.eclipse.core.filebuffers,
+ org.eclipse.ui.workbench
 Bundle-ActivationPolicy: lazy
 Export-Package: org.python.pydev.shared_core,
  org.python.pydev.shared_core.actions,
@@ -30,10 +32,20 @@ Export-Package: org.python.pydev.shared_core,
  org.python.pydev.shared_core.parsing,
  org.python.pydev.shared_core.partitioner,
  org.python.pydev.shared_core.path_watch,
+ org.python.pydev.shared_core.preferences,
  org.python.pydev.shared_core.process,
+ org.python.pydev.shared_core.resource_stubs,
  org.python.pydev.shared_core.string,
  org.python.pydev.shared_core.structure,
  org.python.pydev.shared_core.testutils,
- org.python.pydev.shared_core.utils
+ org.python.pydev.shared_core.utils,
+ org.yaml.snakeyaml,
+ org.yaml.snakeyaml.error,
+ org.yaml.snakeyaml.events,
+ org.yaml.snakeyaml.nodes,
+ org.yaml.snakeyaml.parser,
+ org.yaml.snakeyaml.reader,
+ org.yaml.snakeyaml.scanner,
+ org.yaml.snakeyaml.tokens
 Bundle-Vendor: Appcelerator
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
diff --git a/plugins/org.python.pydev.shared_core/build.properties b/plugins/org.python.pydev.shared_core/build.properties
index b9871ea..2e4ba44 100644
--- a/plugins/org.python.pydev.shared_core/build.properties
+++ b/plugins/org.python.pydev.shared_core/build.properties
@@ -1,6 +1,8 @@
 bin.includes = shared_core.jar,\
                META-INF/,\
-               LICENSE.txt
+               LICENSE.txt,\
+               libs/
 jars.compile.order = shared_core.jar
 source.shared_core.jar = src/
 output.shared_core.jar = bin/
+jars.extra.classpath = libs/snakeyaml-1.11.jar
diff --git a/plugins/org.python.pydev.shared_core/pom.xml b/plugins/org.python.pydev.shared_core/pom.xml
index c58937a..1d524ed 100644
--- a/plugins/org.python.pydev.shared_core/pom.xml
+++ b/plugins/org.python.pydev.shared_core/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/net/SocketUtil.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/net/SocketUtil.java
index 6d30907..6704545 100644
--- a/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/net/SocketUtil.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/net/SocketUtil.java
@@ -11,9 +11,17 @@
 package org.python.pydev.shared_core.net;
 
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.net.ServerSocket;
+import java.net.SocketAddress;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import org.python.pydev.shared_core.log.Log;
 
 /**
  * Utility class to find a port to debug on.
@@ -23,17 +31,15 @@ import java.util.List;
 public class SocketUtil {
 
     /**
-     * Returns a free port number on the specified host within the given range,
-     * or throws an exception.
+     * Returns free ports on the local host.
      * 
-     * @param host name or IP addres of host on which to find a free port
-     * @param searchFrom the port number from which to start searching 
-     * @param searchTo the port number at which to stop searching
-     * @return a free port in the specified range, or an exception if it cannot be found
+     * @param ports: number of ports to return.
      */
-    public static Integer[] findUnusedLocalPorts(int ports) {
-        List<ServerSocket> socket = new ArrayList<ServerSocket>();
-        List<Integer> portsFound = new ArrayList<Integer>();
+    public static Integer[] findUnusedLocalPorts(final int ports) {
+
+        Throwable firstFoundExc = null;
+        final List<ServerSocket> socket = new ArrayList<ServerSocket>();
+        final List<Integer> portsFound = new ArrayList<Integer>();
         try {
             try {
                 for (int i = 0; i < ports; i++) {
@@ -43,6 +49,21 @@ public class SocketUtil {
                     checkValidPort(localPort);
                     portsFound.add(localPort);
                 }
+
+            } catch (Throwable e) {
+                firstFoundExc = e;
+                // Try a different approach...
+                final Set<Integer> searched = new HashSet<Integer>();
+                try {
+                    for (int i = 0; i < ports && portsFound.size() < ports; i++) {
+                        int localPort = findUnusedLocalPort(20000, 65535, searched);
+                        checkValidPort(localPort);
+                        portsFound.add(localPort);
+                    }
+                } catch (Exception e1) {
+                    Log.log(e1); // log this one (but the outer one will be thrown).
+                }
+
             } finally {
                 for (ServerSocket s : socket) {
                     if (s != null) {
@@ -54,6 +75,11 @@ public class SocketUtil {
                     }
                 }
             }
+
+            if (portsFound.size() != ports) {
+                throw firstFoundExc;
+            }
+
         } catch (Throwable e) {
             String message = "Unable to find an unused local port (is there an enabled firewall?)";
             throw new RuntimeException(message, e);
@@ -66,6 +92,73 @@ public class SocketUtil {
         if (port == -1) {
             throw new IOException("Port not bound (found port -1). Is there an enabled firewall?");
         }
+        if (port == 0) {
+            throw new IOException("Port not bound (found port 0). Is there an enabled firewall?");
+        }
+    }
+
+    private static final Random fgRandom = new Random(System.currentTimeMillis());
+
+    /**
+     * Returns a free port number on the specified host within the given range,
+     * or -1 if none found.
+     */
+    private static int findUnusedLocalPort(int searchFrom, int searchTo, Set<Integer> searched) {
+        for (int i = 0; i < 15; i++) {
+            int port = getRandomPort(searchFrom, searchTo);
+            if (searched.contains(i)) {
+                continue;
+            }
+            searched.add(i);
+            ServerSocket s = null;
+            try {
+                s = new ServerSocket();
+                SocketAddress sa = new InetSocketAddress(InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }), port);
+                s.bind(sa); // throws IOException (which can be ignored as this is in use...) 
+                return s.getLocalPort();
+            } catch (IOException e) {
+            } finally {
+                if (s != null) {
+                    try {
+                        s.close();
+                    } catch (IOException ioe) {
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    private static int getRandomPort(int low, int high) {
+        return (int) (fgRandom.nextFloat() * (high - low)) + low;
     }
 
+    public static ServerSocket createLocalServerSocket() throws IOException {
+        ServerSocket serverSocket = new ServerSocket(0);
+        int localPort = serverSocket.getLocalPort();
+        try {
+            SocketUtil.checkValidPort(localPort);
+        } catch (Exception e) {
+            // 0 did not give us a valid local port... close this one and try a different approach.
+            try {
+                serverSocket.close();
+            } catch (Exception e1) {
+            }
+
+            serverSocket = new ServerSocket(SocketUtil.findUnusedLocalPorts(1)[0]);
+            localPort = serverSocket.getLocalPort();
+            try {
+                SocketUtil.checkValidPort(localPort);
+            } catch (IOException invalidPortException) {
+                // Still invalid: close the socket and throw error!
+                try {
+                    serverSocket.close();
+                } catch (Exception e1) {
+                }
+                throw invalidPortException;
+            }
+        }
+
+        return serverSocket;
+    }
 }
diff --git a/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/IScopedPreferences.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/IScopedPreferences.java
new file mode 100644
index 0000000..32d79b6
--- /dev/null
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/IScopedPreferences.java
@@ -0,0 +1,82 @@
+package org.python.pydev.shared_core.preferences;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.python.pydev.shared_core.structure.Tuple;
+
+/**
+ * This is an API which takes care of getting preferences we want from a proper place.
+ * 
+ * Some use-cases:
+ * 
+ * - Get whether we should do code-formatting based on a configuration which is saved:
+ *     1. In the project (i.e.: .settings/org.python.pydev.yaml)
+ *     2. In the user-configuration (i.e.: user.home/.eclipse/org.python.pydev.yaml)
+ *     3. In the workspace (which is the Eclipse standard)
+ *      
+ * - Get additional templates (templates should be a collection of templates in project, user configuration, workspace).
+ * 
+ * - Automatically apply defaults from the user-configuration into the workspace settings 
+ *      (i.e.: %APPDATA%/EclipseSettings/override.workspacesettings)
+ */
+public interface IScopedPreferences {
+
+    // Note: these settings are not on each call and should usually be passed in a constructor...
+
+    // String pluginName:
+    // pluginName the name of the plugin (from which the name of the file in the preferences is derived 
+    //  -- i.e.: org.python.pydev will get a %APPDATA%/EclipseSettings/org.python.pydev.yaml file)
+
+    /**
+     * @param pluginPreferenceStore the preferences store of the plugin (workspace setting)
+     * @param keyInPreferenceStore the key to get from the workspace (if needed)
+     * @param adaptable an adaptable which can adapt to IProject.
+     */
+    public boolean getBoolean(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable);
+
+    /**
+     * @param pluginPreferenceStore the preferences store of the plugin (workspace setting)
+     * @param keyInPreferenceStore the key to get from the workspace (if needed)
+     * @param adaptable an adaptable which can adapt to IProject.
+     */
+    public int getInt(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable);
+
+    /**
+     * @param pluginPreferenceStore the preferences store of the plugin (workspace setting)
+     * @param keyInPreferenceStore the key to get from the workspace (if needed)
+     * @param adaptable an adaptable which can adapt to IProject.
+     */
+    public String getString(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable);
+
+    /**
+     * May throw an exception if it's not possible to save the passed data.
+     * 
+     * Common reasons include not being able to write the file, abort overriding an existing (non-valid) yaml file...
+     * 
+     * Returns a message which may be shown to the user with the confirmation of the save.
+     */
+    public String saveToUserSettings(Map<String, Object> saveData) throws Exception;
+
+    /**
+     * May throw an exception if it's not possible to load the passed data.
+     * 
+     * Returns a tuple with the loaded values and a set with the values which weren't found in the user settings.
+     * @throws Exception 
+     */
+    public Tuple<Map<String, Object>, Set<String>> loadFromUserSettings(Map<String, Object> saveData) throws Exception;
+
+    public String saveToProjectSettings(Map<String, Object> saveData, IProject... projects);
+
+    public Tuple<Map<String, Object>, Set<String>> loadFromProjectSettings(Map<String, Object> saveData,
+            IProject project) throws Exception;
+
+    public File getUserSettingsLocation();
+
+    public IFile getProjectSettingsLocation(IProject p);
+}
diff --git a/plugins/com.python.pydev/src/com/python/pydev/NullPrefsStore.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/NullPrefsStore.java
similarity index 90%
rename from plugins/com.python.pydev/src/com/python/pydev/NullPrefsStore.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/NullPrefsStore.java
index 524404b..353155d 100644
--- a/plugins/com.python.pydev/src/com/python/pydev/NullPrefsStore.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/NullPrefsStore.java
@@ -4,7 +4,10 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package com.python.pydev;
+package org.python.pydev.shared_core.preferences;
+
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.util.IPropertyChangeListener;
@@ -14,6 +17,8 @@ import org.eclipse.jface.util.IPropertyChangeListener;
  */
 public class NullPrefsStore implements IPreferenceStore {
 
+    Map<String, Object> nameToVal = new HashMap<>();
+
     public void addPropertyChangeListener(IPropertyChangeListener listener) {
 
     }
@@ -73,7 +78,10 @@ public class NullPrefsStore implements IPreferenceStore {
     }
 
     public int getInt(String name) {
-
+        Object val = nameToVal.get(name);
+        if (val != null) {
+            return (int) val;
+        }
         return 0;
     }
 
@@ -142,7 +150,7 @@ public class NullPrefsStore implements IPreferenceStore {
     }
 
     public void setValue(String name, int value) {
-
+        this.nameToVal.put(name, value);
     }
 
     public void setValue(String name, long value) {
diff --git a/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/ScopedPreferences.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/ScopedPreferences.java
new file mode 100644
index 0000000..c87ba69
--- /dev/null
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/preferences/ScopedPreferences.java
@@ -0,0 +1,521 @@
+package org.python.pydev.shared_core.preferences;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.IDocument;
+import org.python.pydev.shared_core.cache.LRUCache;
+import org.python.pydev.shared_core.callbacks.ICallback0;
+import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.log.Log;
+import org.python.pydev.shared_core.string.FastStringBuffer;
+import org.python.pydev.shared_core.string.StringUtils;
+import org.python.pydev.shared_core.structure.OrderedSet;
+import org.python.pydev.shared_core.structure.Tuple;
+import org.yaml.snakeyaml.Yaml;
+
+public final class ScopedPreferences implements IScopedPreferences {
+
+    private static final Map<String, IScopedPreferences> pluginNameToPreferences = new HashMap<String, IScopedPreferences>();
+    private static final Object lock = new Object();
+
+    public static IScopedPreferences get(final String pluginName) {
+        IScopedPreferences ret = pluginNameToPreferences.get(pluginName);
+        if (ret == null) {
+            synchronized (lock) {
+                ret = new ScopedPreferences(pluginName);
+                pluginNameToPreferences.put(pluginName, ret);
+            }
+        }
+        return ret;
+    }
+
+    public static String USER_HOME_IN_TESTS = null;
+
+    private String pluginName;
+    private File[] trackedDirs;
+    private File defaultSettingsDir = null;
+
+    public ScopedPreferences(String pluginName) {
+        this.pluginName = pluginName;
+        Set<File> set = new OrderedSet<File>();
+
+        //Default paths always there!
+        String userHome;
+        if (USER_HOME_IN_TESTS == null) {
+            userHome = System.getProperty("user.home");
+        } else {
+            userHome = USER_HOME_IN_TESTS;
+        }
+        if (userHome != null) {
+            try {
+                File f = new File(userHome);
+                if (f.isDirectory()) {
+                    f = new File(f, ".eclipse");
+                    try {
+                        if (!f.exists()) {
+                            f.mkdirs();
+                        }
+                    } catch (Exception e) {
+                        Log.log(e);
+                    }
+                    if (f.isDirectory()) {
+                        set.add(f);
+                        defaultSettingsDir = f;
+                    }
+                }
+            } catch (Throwable e) {
+                Log.log(e);
+            }
+        }
+        if (set.size() == 0) {
+            Log.log("System.getProperty(\"user.home\") returned " + userHome + " which is not a directory!");
+        }
+
+        // TODO: Add support later on.
+        // ScopedPreferenceStore workspaceSettings = new ScopedPreferenceStore(InstanceScope.INSTANCE, pluginName);
+        // String string = workspaceSettings.getString("ADDITIONAL_TRACKED_DIRS");
+        // //Load additional tracked dirs
+        // for (String s : StringUtils.split(string, '|')) {
+        //     set.add(new File(s));
+        // }
+        this.trackedDirs = set.toArray(new File[0]);
+    }
+
+    @Override
+    public File getUserSettingsLocation() {
+        return new File(defaultSettingsDir, pluginName + ".yaml");
+    }
+
+    @Override
+    public Tuple<Map<String, Object>, Set<String>> loadFromUserSettings(Map<String, Object> saveData) throws Exception {
+        Map<String, Object> o1 = new HashMap<>();
+        Set<String> o2 = new HashSet<>();
+        Tuple<Map<String, Object>, Set<String>> ret = new Tuple<>(o1, o2);
+
+        File yamlFile = getUserSettingsLocation();
+        if (yamlFile.exists()) {
+            Map<String, Object> loaded = getYamlFileContents(yamlFile);
+            Set<Entry<String, Object>> initialEntrySet = saveData.entrySet();
+            for (Entry<String, Object> entry : initialEntrySet) {
+                Object loadedObj = loaded.get(entry.getKey());
+                if (loadedObj == null) {
+                    //not in loaded file
+                    o2.add(entry.getKey());
+                } else {
+                    o1.put(entry.getKey(), convertValueToTypeOfOldValue(loadedObj, entry.getValue()));
+                }
+            }
+        }
+        return ret;
+    }
+
+    @Override
+    public Tuple<Map<String, Object>, Set<String>> loadFromProjectSettings(Map<String, Object> saveData,
+            IProject project) throws Exception {
+        Map<String, Object> o1 = new HashMap<>();
+        Set<String> o2 = new HashSet<>();
+        Tuple<Map<String, Object>, Set<String>> ret = new Tuple<>(o1, o2);
+        IFile yamlFile = getProjectConfigFile(project, pluginName + ".yaml", false);
+
+        if (yamlFile.exists()) {
+            Map<String, Object> loaded = getYamlFileContents(yamlFile);
+            Set<Entry<String, Object>> initialEntrySet = saveData.entrySet();
+            for (Entry<String, Object> entry : initialEntrySet) {
+                Object loadedObj = loaded.get(entry.getKey());
+                if (loadedObj == null) {
+                    //not in loaded file
+                    o2.add(entry.getKey());
+                } else {
+                    o1.put(entry.getKey(), convertValueToTypeOfOldValue(loadedObj, entry.getValue()));
+                }
+            }
+        }
+        return ret;
+    }
+
+    @Override
+    public String saveToUserSettings(Map<String, Object> saveData) throws Exception {
+        if (defaultSettingsDir == null) {
+            throw new Exception("user.home is not available!");
+        }
+        if (!defaultSettingsDir.isDirectory()) {
+            throw new Exception("user.home/.settings: " + defaultSettingsDir + "is not a directory!");
+        }
+        Map<String, Object> yamlMapToWrite = new TreeMap<>();
+        Set<Entry<String, Object>> entrySet = saveData.entrySet();
+        for (Entry<String, Object> entry : entrySet) {
+            yamlMapToWrite.put(entry.getKey(), entry.getValue());
+        }
+        saveData = null; // make sure we don't use it anymore
+        File yamlFile = new File(defaultSettingsDir, pluginName + ".yaml");
+        if (yamlFile.exists()) {
+            try {
+                Map<String, Object> initial = new HashMap<>(getYamlFileContents(yamlFile));
+                initial.putAll(yamlMapToWrite);
+                yamlMapToWrite = new TreeMap<>(initial);
+            } catch (Exception e) {
+                throw new Exception(
+                        StringUtils
+                                .format("Error: unable to write settings because the file: %s already exists but "
+                                        + "is not a parseable YAML file (aborting to avoid overriding existing file).",
+                                        yamlFile), e);
+            }
+        }
+
+        dumpSaveDataToFile(yamlMapToWrite, yamlFile);
+        return "Contents saved to:\n" + yamlFile;
+    }
+
+    @Override
+    public String saveToProjectSettings(Map<String, Object> saveData, IProject... projects) {
+        FastStringBuffer buf = new FastStringBuffer();
+
+        int createdForNProjects = 0;
+
+        for (IProject project : projects) {
+            try {
+                IFile projectConfigFile = getProjectConfigFile(project, pluginName + ".yaml", true);
+                if (projectConfigFile == null) {
+                    buf.append("Unable to get config file location for: ").append(project.getName()).append("\n");
+                    continue;
+                }
+                if (projectConfigFile.exists()) {
+                    Map<String, Object> yamlFileContents = null;
+                    try {
+                        yamlFileContents = getYamlFileContents(projectConfigFile);
+                    } catch (Exception e) {
+                        throw new Exception(
+                                StringUtils
+                                        .format("Error: unable to write settings because the file: %s already exists but "
+                                                + "is not a parseable YAML file (aborting to avoid overriding existing file).\n",
+                                                projectConfigFile), e);
+
+                    }
+                    Map<String, Object> yamlMapToWrite = new TreeMap<>();
+                    Set<Entry<String, Object>> entrySet = yamlFileContents.entrySet();
+                    for (Entry<String, Object> entry : entrySet) {
+                        yamlMapToWrite.put(entry.getKey(), entry.getValue());
+                    }
+                    yamlMapToWrite.putAll(saveData);
+                    dumpSaveDataToFile(yamlMapToWrite, projectConfigFile, true);
+                    createdForNProjects += 1;
+                    continue;
+                } else {
+                    //Create file
+                    dumpSaveDataToFile(saveData, projectConfigFile, false);
+                    createdForNProjects += 1;
+                }
+
+            } catch (Exception e) {
+                Log.log(e);
+                buf.append(e.getMessage());
+            }
+        }
+        if (createdForNProjects > 0) {
+            buf.insert(0, "Operation succeeded for " + createdForNProjects + " projects.\n");
+        }
+        return buf.toString();
+    }
+
+    private void dumpSaveDataToFile(Map<String, Object> saveData, IFile yamlFile, boolean exists) throws IOException,
+            CoreException {
+        Yaml yaml = new Yaml();
+        String dumpAsMap = yaml.dumpAsMap(saveData);
+        if (!exists) {
+            // Create empty (so that we can set the charset properly later on).
+            yamlFile.create(new ByteArrayInputStream("".getBytes()), true, new NullProgressMonitor());
+        }
+        yamlFile.setCharset("UTF-8", new NullProgressMonitor());
+        yamlFile.setContents(new ByteArrayInputStream(dumpAsMap.getBytes(Charset.forName("UTF-8"))), true, true,
+                new NullProgressMonitor());
+    }
+
+    private void dumpSaveDataToFile(Map<String, Object> saveData, File yamlFile) throws IOException {
+        Yaml yaml = new Yaml();
+        String dumpAsMap = yaml.dumpAsMap(saveData);
+        FileUtils.writeStrToFile(dumpAsMap, yamlFile);
+        // Don't use the code below because we want to dump as a map to have a better layout for the file.
+        //
+        // try (Writer output = new FileWriter(yamlFile)) {
+        //     yaml.dump(saveData, new BufferedWriter(output));
+        // }
+    }
+
+    @Override
+    public IFile getProjectSettingsLocation(IProject p) {
+        return getProjectConfigFile(p, pluginName + ".yaml", false);
+    }
+
+    /**
+     * Returns the contents of the configuration file to be used or null.
+     */
+    private static IFile getProjectConfigFile(IProject project, String filename, boolean createPath) {
+        try {
+            if (project != null && project.exists()) {
+                IFolder folder = project.getFolder(".settings");
+                if (createPath) {
+                    if (!folder.exists()) {
+                        folder.create(true, true, new NullProgressMonitor());
+                    }
+                }
+                return folder.getFile(filename);
+            }
+        } catch (Exception e) {
+            Log.log(e);
+        }
+        return null;
+    }
+
+    //TODO: We may want to have some caches...
+    //long modificationStamp = projectConfigFile.getModificationStamp();
+
+    @Override
+    public String getString(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable) {
+        Object object = getFromProjectOrUserSettings(keyInPreferenceStore, adaptable);
+        if (object != null) {
+            return object.toString();
+        }
+        // Ok, not in project or user settings: get it from the workspace settings.
+        return pluginPreferenceStore.getString(keyInPreferenceStore);
+    }
+
+    @Override
+    public boolean getBoolean(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable) {
+        Object object = getFromProjectOrUserSettings(keyInPreferenceStore, adaptable);
+        if (object != null) {
+            return toBoolean(object);
+        }
+        // Ok, not in project or user settings: get it from the workspace settings.
+        return pluginPreferenceStore.getBoolean(keyInPreferenceStore);
+    }
+
+    @Override
+    public int getInt(IPreferenceStore pluginPreferenceStore, String keyInPreferenceStore, IAdaptable adaptable) {
+        Object object = getFromProjectOrUserSettings(keyInPreferenceStore, adaptable);
+        if (object != null) {
+            return toInt(object);
+        }
+        // Ok, not in project or user settings: get it from the workspace settings.
+        return pluginPreferenceStore.getInt(keyInPreferenceStore);
+    }
+
+    private Object getFromProjectOrUserSettings(String keyInPreferenceStore, IAdaptable adaptable) {
+        // In the yaml all keys are lowercase!
+        String keyInYaml = keyInPreferenceStore;
+
+        if (adaptable != null) {
+            try {
+                IProject project;
+                if (adaptable instanceof IResource) {
+                    project = ((IResource) adaptable).getProject();
+                } else {
+                    project = (IProject) adaptable.getAdapter(IProject.class);
+                }
+                IFile projectConfigFile = getProjectSettingsLocation(project);
+                if (projectConfigFile != null && projectConfigFile.exists()) {
+                    Map<String, Object> yamlFileContents = null;
+                    try {
+                        yamlFileContents = getYamlFileContents(projectConfigFile);
+                    } catch (Exception e) {
+                        Log.log(e);
+                    }
+                    if (yamlFileContents != null) {
+                        Object object = yamlFileContents.get(keyInYaml);
+                        if (object != null) {
+                            return object;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                Log.log(e);
+            }
+        }
+
+        // If it got here, it's not in the project, let's try in the user settings...
+        for (File dir : trackedDirs) {
+            try {
+                File yaml = new File(dir, pluginName + ".yaml");
+                if (yaml.exists()) {
+                    Map<String, Object> yamlFileContents = null;
+                    try {
+                        yamlFileContents = getYamlFileContents(yaml);
+                    } catch (Exception e) {
+                        Log.log(e);
+                    }
+                    if (yamlFileContents != null) {
+                        Object object = yamlFileContents.get(keyInYaml);
+                        if (object != null) {
+                            return object;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                Log.log(e);
+            }
+        }
+        return null;
+    }
+
+    public static boolean toBoolean(Object found) {
+        if (found == null) {
+            return false;
+        }
+        if (Boolean.FALSE.equals(found)) {
+            return false;
+        }
+        String asStr = found.toString();
+
+        if ("false".equals(asStr) || "False".equals(asStr) || "0".equals(asStr) || asStr.trim().length() == 0) {
+            return false;
+        }
+        return true;
+    }
+
+    public static int toInt(Object found) {
+        if (found == null) {
+            return 0;
+        }
+        if (found instanceof Integer) {
+            return (int) found;
+        }
+
+        String asStr = found.toString();
+        try {
+            return Integer.parseInt(asStr);
+        } catch (Exception e) {
+            Log.log(e);
+            return 0;
+        }
+    }
+
+    private Object convertValueToTypeOfOldValue(Object loadedObj, Object oldValue) {
+        if (oldValue == null) {
+            return loadedObj; // Unable to do anything in this case...
+        }
+        if (loadedObj == null) {
+            return null; // Nothing to see?
+        }
+        if (oldValue instanceof Boolean) {
+            return toBoolean(loadedObj);
+        }
+        if (oldValue instanceof Integer) {
+            return toInt(loadedObj);
+        }
+        if (oldValue instanceof String) {
+            return loadedObj.toString();
+        }
+        throw new RuntimeException("Unable to handle type conversion to: " + oldValue.getClass());
+    }
+
+    LRUCache<Object, Map<String, Object>> cache = new LRUCache<>(15);
+    LRUCache<Object, Long> lastSeenCache = new LRUCache<>(15);
+
+    private Map<String, Object> getCachedYamlFileContents(Object key, long currentSeen, ICallback0<Object> iCallback0)
+            throws Exception {
+        Long lastSeen = lastSeenCache.getObj(key);
+        if (lastSeen != null) {
+            if (lastSeen != currentSeen) {
+                cache.remove(key);
+            }
+        }
+
+        Map<String, Object> obj = cache.getObj(key);
+        if (obj != null) {
+            return obj;
+        }
+
+        // Ok, not in cache...
+        Map<String, Object> ret = (Map<String, Object>) iCallback0.call();
+        lastSeenCache.add(key, currentSeen);
+        cache.add(key, ret);
+        return ret;
+    }
+
+    /**
+     * A number of exceptions may happen when loading the contents...
+     */
+    private Map<String, Object> getYamlFileContents(final IFile projectConfigFile) throws Exception {
+        return getCachedYamlFileContents(projectConfigFile, projectConfigFile.getModificationStamp(),
+                new ICallback0<Object>() {
+
+                    @Override
+                    public Object call() {
+                        IDocument fileContents = getFileContents(projectConfigFile);
+                        String yamlContents = fileContents.get();
+                        try {
+                            return getYamlFileContentsImpl(yamlContents);
+                        } catch (Exception e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                });
+    }
+
+    private Map<String, Object> getYamlFileContents(final File yamlFile) throws Exception {
+        //Using this API to get a higher precision!
+        FileTime ret = Files.getLastModifiedTime(yamlFile.toPath());
+        long lastModified = ret.to(TimeUnit.NANOSECONDS);
+
+        return getCachedYamlFileContents(yamlFile, lastModified,
+                new ICallback0<Object>() {
+
+                    @Override
+                    public Object call() {
+                        try {
+                            String fileContents = FileUtils.getFileContents(yamlFile);
+                            Map<String, Object> initial = getYamlFileContentsImpl(fileContents);
+                            return initial;
+                        } catch (Exception e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                });
+
+    }
+
+    /**
+     * A number of exceptions may happen when loading the contents...
+     */
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> getYamlFileContentsImpl(String yamlContents) throws Exception {
+        if (yamlContents.trim().length() == 0) {
+            return new HashMap<String, Object>();
+        }
+        Yaml yaml = new Yaml();
+        Object load = yaml.load(yamlContents);
+        if (!(load instanceof Map)) {
+            if (load == null) {
+                throw new Exception("Expected top-level element to be a map. Found: null");
+            }
+            throw new Exception("Expected top-level element to be a map. Found: " + load.getClass());
+        }
+        //As this object is from our internal cache, make it unmodifiable!
+        return Collections.unmodifiableMap((Map<String, Object>) load);
+    }
+
+    private IDocument getFileContents(IFile file) {
+        return FileUtils.getDocFromResource(file);
+    }
+
+}
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIContainerStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIContainerStub.java
similarity index 98%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIContainerStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIContainerStub.java
index 910718a..3b8e7ff 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIContainerStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIContainerStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IResourceFilterDescription;
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFileStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFileStub.java
similarity index 97%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFileStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFileStub.java
index 95ed43c..8ca791d 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFileStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFileStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.io.InputStream;
 import java.io.Reader;
@@ -91,7 +91,7 @@ public class AbstractIFileStub extends AbstractIResourceStub implements IFile {
     }
 
     public void setCharset(String newCharset, IProgressMonitor monitor) throws CoreException {
-        throw new RuntimeException("Not implemented");
+        //no-op
     }
 
     public void setContents(InputStream source, boolean force, boolean keepHistory, IProgressMonitor monitor)
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFolderStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFolderStub.java
similarity index 97%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFolderStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFolderStub.java
index a850eca..aafd72f 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIFolderStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIFolderStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.net.URI;
 
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIProjectStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIProjectStub.java
similarity index 99%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIProjectStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIProjectStub.java
index 44b88d2..c5b61b9 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIProjectStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIProjectStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.net.URI;
 import java.util.Map;
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIResourceStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIResourceStub.java
similarity index 99%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIResourceStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIResourceStub.java
index 5b260e4..7f5cba3 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIResourceStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIResourceStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.net.URI;
 import java.util.Map;
@@ -239,7 +239,7 @@ public class AbstractIResourceStub implements IResource {
     }
 
     public boolean isSynchronized(int depth) {
-        throw new RuntimeException("Not implemented");
+        return true;
     }
 
     public boolean isTeamPrivateMember() {
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIWorkspaceRootStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIWorkspaceRootStub.java
similarity index 97%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIWorkspaceRootStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIWorkspaceRootStub.java
index d379bee..de4c71a 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/AbstractIWorkspaceRootStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/AbstractIWorkspaceRootStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.net.URI;
 
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FileMock.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileMock.java
similarity index 95%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FileMock.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileMock.java
index 4e31796..b99b94b 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FileMock.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileMock.java
@@ -9,7 +9,7 @@
 * Contributors:
 *     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
 ******************************************************************************/
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IProject;
diff --git a/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileStub.java
new file mode 100644
index 0000000..ee4824a
--- /dev/null
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FileStub.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.shared_core.resource_stubs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.string.FastStringBuffer;
+import org.python.pydev.shared_core.string.StringUtils;
+
+public class FileStub extends AbstractIFileStub implements IFile {
+
+    private ProjectStub project;
+    protected File file;
+
+    public FileStub(ProjectStub project, File file) {
+        Assert.isTrue(file.exists() && file.isFile());
+        this.project = project;
+        this.file = file;
+    }
+
+    @Override
+    public String getFileExtension() {
+        String name = this.file.getName();
+        List<String> dotSplit = StringUtils.dotSplit(name);
+        if (dotSplit.size() > 1) {
+            return dotSplit.get(dotSplit.size() - 1);
+        }
+        return null;
+    }
+
+    @Override
+    public String getName() {
+        return this.file.getName();
+    }
+
+    @Override
+    public IContainer getParent() {
+        return project.getFolder(this.file.getParentFile());
+    }
+
+    @Override
+    public long getModificationStamp() {
+        try {
+            FileTime ret = Files.getLastModifiedTime(this.file.toPath());
+            return ret.to(TimeUnit.NANOSECONDS);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void setContents(InputStream source, boolean force, boolean keepHistory, IProgressMonitor monitor)
+            throws CoreException {
+        try {
+            FastStringBuffer buffer = FileUtils.fillBufferWithStream(source, "utf-8", monitor);
+            FileUtils.writeStrToFile(buffer.toString(), file);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public InputStream getContents() throws CoreException {
+        try {
+            return new FileInputStream(file);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public InputStream getContents(boolean force) throws CoreException {
+        return getContents();
+    }
+
+    @Override
+    public IPath getFullPath() {
+        IPath projectPath = Path.fromOSString(FileUtils.getFileAbsolutePath(project.projectRoot));
+        IPath filePath = Path.fromOSString(FileUtils.getFileAbsolutePath(file));
+        return filePath.makeRelativeTo(projectPath);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((file == null) ? 0 : file.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final FileStub other = (FileStub) obj;
+        if (file == null) {
+            if (other.file != null) {
+                return false;
+            }
+        } else if (!file.equals(other.file)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "FileStub:" + this.file;
+    }
+
+    @Override
+    public IProject getProject() {
+        return this.project;
+
+    }
+
+}
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FolderMock.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderMock.java
similarity index 97%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FolderMock.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderMock.java
index f04d800..fc37a7a 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/FolderMock.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderMock.java
@@ -9,7 +9,7 @@
 * Contributors:
 *     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
 ******************************************************************************/
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FolderStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderStub.java
similarity index 88%
rename from plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FolderStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderStub.java
index d03a4ae..8a25a99 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FolderStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/FolderStub.java
@@ -4,17 +4,17 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.navigator;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.io.File;
 
 import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
-import org.python.pydev.core.resource_stubs.AbstractIFolderStub;
 import org.python.pydev.shared_core.io.FileUtils;
 
 public class FolderStub extends AbstractIFolderStub implements IFolder {
@@ -49,6 +49,19 @@ public class FolderStub extends AbstractIFolderStub implements IFolder {
     }
 
     @Override
+    public IFile getFile(IPath path) {
+        if (path.segmentCount() != 1) {
+            throw new RuntimeException("finish implementing");
+        }
+        return new FileStub(project, new File(folder, path.segment(0)));
+    }
+
+    @Override
+    public IFile getFile(String name) {
+        return getFile(new Path(name));
+    }
+
+    @Override
     public IFolder getFolder(IPath path) {
         String[] segments = path.segments();
 
diff --git a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/ProjectMock.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectMock.java
similarity index 86%
rename from plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/ProjectMock.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectMock.java
index 7f76c3b..41ccc7f 100644
--- a/plugins/org.python.pydev.core/tests/org/python/pydev/core/resource_stubs/ProjectMock.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectMock.java
@@ -9,22 +9,21 @@
 * Contributors:
 *     Fabio Zadrozny <fabiofz at gmail.com> - initial API and implementation
 ******************************************************************************/
-package org.python.pydev.core.resource_stubs;
+package org.python.pydev.shared_core.resource_stubs;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectNature;
 import org.eclipse.core.runtime.CoreException;
-import org.python.pydev.core.IPythonNature;
 
 public class ProjectMock extends AbstractIProjectStub {
 
-    private IPythonNature nature;
+    private IProjectNature nature;
 
     public void addMember(FolderMock mod1) {
         mod1.setParent(this);
     }
 
-    public void setNature(IPythonNature pythonNatureStub) {
+    public void setNature(IProjectNature pythonNatureStub) {
         this.nature = pythonNatureStub;
     }
 
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/ProjectStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectStub.java
similarity index 84%
rename from plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/ProjectStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectStub.java
index a9d7325..17c3a82 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/ProjectStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/ProjectStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.navigator;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -13,6 +13,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectNature;
@@ -23,8 +24,6 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.ui.model.IWorkbenchAdapter;
-import org.python.pydev.core.IPythonNature;
-import org.python.pydev.core.resource_stubs.AbstractIProjectStub;
 import org.python.pydev.shared_core.io.FileUtils;
 
 public class ProjectStub extends AbstractIProjectStub implements IWorkbenchAdapter {
@@ -33,7 +32,7 @@ public class ProjectStub extends AbstractIProjectStub implements IWorkbenchAdapt
 
     private Map<File, IResource> cache = new HashMap<File, IResource>();
 
-    private IPythonNature nature;
+    private IProjectNature nature;
 
     private IContainer parent;
 
@@ -41,15 +40,15 @@ public class ProjectStub extends AbstractIProjectStub implements IWorkbenchAdapt
 
     private List<Object> additionalChildren;
 
-    public ProjectStub(File file, IPythonNature nature) {
+    public ProjectStub(File file, IProjectNature nature) {
         this(file, nature, false);
     }
 
-    public ProjectStub(File file, IPythonNature nature, boolean addNullChild) {
+    public ProjectStub(File file, IProjectNature nature, boolean addNullChild) {
         this(file, nature, addNullChild, new ArrayList<Object>());
     }
 
-    public ProjectStub(File file, IPythonNature nature, boolean addNullChild, List<Object> additionalChildren) {
+    public ProjectStub(File file, IProjectNature nature, boolean addNullChild, List<Object> additionalChildren) {
         Assert.isTrue(file.exists() && file.isDirectory());
         this.projectRoot = file;
         this.nature = nature;
@@ -123,6 +122,11 @@ public class ProjectStub extends AbstractIProjectStub implements IWorkbenchAdapt
     }
 
     @Override
+    public IFolder getFolder(String name) {
+        return getFolder(new Path(name));
+    }
+
+    @Override
     public IFolder getFolder(IPath path) {
         String[] segments = path.segments();
 
@@ -137,6 +141,21 @@ public class ProjectStub extends AbstractIProjectStub implements IWorkbenchAdapt
     }
 
     @Override
+    public IFile getFile(IPath path) {
+        String[] segments = path.segments();
+        int segmentCount = path.segmentCount();
+        IContainer container = this;
+        for (int i = 0; i < segmentCount - i; i++) {
+            container = container.getFolder(new Path(segments[i]));
+        }
+        if (container != this) {
+            return container.getFile(new Path(segments[segmentCount - 1]));
+        }
+
+        throw new RuntimeException("Finish implementing");
+    }
+
+    @Override
     public IPath getLocation() {
         return Path.fromOSString(FileUtils.getFileAbsolutePath(this.projectRoot));
     }
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkingSetStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkingSetStub.java
similarity index 98%
rename from plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkingSetStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkingSetStub.java
index 8bf54cf..5e6a37b 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkingSetStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkingSetStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.navigator;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceRootStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceRootStub.java
similarity index 93%
rename from plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceRootStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceRootStub.java
index 4ae7a2e..03af2fb34 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceRootStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceRootStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.navigator;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -13,10 +13,10 @@ import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.ui.model.IWorkbenchAdapter;
-import org.python.pydev.core.resource_stubs.AbstractIWorkspaceRootStub;
 
 public class WorkspaceRootStub extends AbstractIWorkspaceRootStub implements IWorkbenchAdapter {
 
+    @Override
     public Object getAdapter(Class adapter) {
         if (adapter == IWorkbenchAdapter.class) {
             return this;
@@ -47,10 +47,12 @@ public class WorkspaceRootStub extends AbstractIWorkspaceRootStub implements IWo
         throw new RuntimeException("Not implemented");
     }
 
+    @Override
     public IProject getProject() {
         return null;
     }
 
+    @Override
     public IContainer getParent() {
         return null;
     }
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceStub.java b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceStub.java
similarity index 99%
rename from plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceStub.java
rename to plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceStub.java
index 70a954f..c9f24fd 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/WorkspaceStub.java
+++ b/plugins/org.python.pydev.shared_core/src/org/python/pydev/shared_core/resource_stubs/WorkspaceStub.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.navigator;
+package org.python.pydev.shared_core.resource_stubs;
 
 import java.io.InputStream;
 import java.net.URI;
diff --git a/plugins/org.python.pydev.shared_core/tests/org/python/pydev/shared_core/preferences/ScopedPreferencesTest.java b/plugins/org.python.pydev.shared_core/tests/org/python/pydev/shared_core/preferences/ScopedPreferencesTest.java
new file mode 100644
index 0000000..bd6df2b
--- /dev/null
+++ b/plugins/org.python.pydev.shared_core/tests/org/python/pydev/shared_core/preferences/ScopedPreferencesTest.java
@@ -0,0 +1,126 @@
+package org.python.pydev.shared_core.preferences;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.resource_stubs.ProjectStub;
+
+public class ScopedPreferencesTest extends TestCase {
+
+    private File baseDir;
+
+    @Override
+    protected void setUp() throws Exception {
+        FileUtils.IN_TESTS = true;
+        baseDir = new File(FileUtils.getFileAbsolutePath(new File("ScopedPreferencesTest.temporary_dir")));
+        try {
+            FileUtils.deleteDirectoryTree(baseDir);
+        } catch (Exception e) {
+            //ignore
+        }
+        if (baseDir.exists()) {
+            throw new AssertionError("Not expecting: " + baseDir + " to exist.");
+        }
+        baseDir.mkdirs();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            FileUtils.deleteDirectoryTree(baseDir);
+        } catch (Exception e) {
+            //ignore
+        }
+    }
+
+    public void testUserSettingsScopedPreferences() throws Exception {
+        ScopedPreferences.USER_HOME_IN_TESTS = baseDir.getAbsolutePath();
+        try {
+            IScopedPreferences iScopedPreferences = ScopedPreferences.get("my.test");
+            File eclipsePrefs = new File(baseDir, ".eclipse");
+            assertTrue(eclipsePrefs.exists());
+            File userSettingsYamlFile = new File(eclipsePrefs, "my.test.yaml");
+            assertTrue(!userSettingsYamlFile.exists());
+            Map<String, Object> saveData = new HashMap<String, Object>();
+            saveData.put("foo", 1);
+            iScopedPreferences.saveToUserSettings(saveData);
+            assertTrue(userSettingsYamlFile.exists());
+            IAdaptable adaptable = new IAdaptable() {
+
+                @Override
+                public Object getAdapter(Class adapter) {
+                    return null;
+                }
+            };
+            IPreferenceStore pluginPreferenceStore = new NullPrefsStore();
+            assertEquals(1, iScopedPreferences.getInt(pluginPreferenceStore, "foo", adaptable));
+            assertEquals("foo: 1\n", FileUtils.getFileContents(userSettingsYamlFile));
+            saveData = new HashMap<String, Object>();
+            saveData.put("bar", 2);
+            iScopedPreferences.saveToUserSettings(saveData);
+            assertEquals("bar: 2\nfoo: 1\n", FileUtils.getFileContents(userSettingsYamlFile));
+            assertEquals(2, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable));
+            FileUtils.writeStrToFile("bar: 1\nfoo: 1\n", userSettingsYamlFile);
+            assertEquals(1, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable));
+        } finally {
+            ScopedPreferences.USER_HOME_IN_TESTS = null;
+        }
+    }
+
+    public void testProjectSettingsScopedPreferences() throws Exception {
+        ScopedPreferences.USER_HOME_IN_TESTS = baseDir.getAbsolutePath();
+        try {
+            IScopedPreferences iScopedPreferences = ScopedPreferences.get("my.test");
+            File eclipsePrefs = new File(baseDir, ".eclipse");
+            File projectDir = new File(baseDir, "project");
+            File projectDirSettings = new File(projectDir, ".settings");
+            File projectDirYAMLFile = new File(projectDirSettings, "my.test.yaml");
+            eclipsePrefs.mkdirs();
+            projectDir.mkdirs();
+            projectDirSettings.mkdirs();
+            FileUtils.writeStrToFile("", projectDirYAMLFile);
+            assertTrue(eclipsePrefs.exists());
+            File userSettingsYamlFile = new File(eclipsePrefs, "my.test.yaml");
+            assertTrue(!userSettingsYamlFile.exists());
+            final IProject project = new ProjectStub(projectDir, null);
+            Map<String, Object> saveData = new HashMap<String, Object>();
+            saveData.put("foo", 1);
+            iScopedPreferences.saveToProjectSettings(saveData, project);
+            assertTrue(!userSettingsYamlFile.exists());
+            assertEquals("foo: 1\n", FileUtils.getFileContents(projectDirYAMLFile));
+
+            IAdaptable adaptable = new IAdaptable() {
+
+                @Override
+                public Object getAdapter(Class adapter) {
+                    if (IProject.class == adapter) {
+                        return project;
+                    }
+                    return null;
+                }
+            };
+            IPreferenceStore pluginPreferenceStore = new NullPrefsStore();
+            assertEquals(1, iScopedPreferences.getInt(pluginPreferenceStore, "foo", adaptable));
+            saveData = new HashMap<String, Object>();
+            saveData.put("bar", 2);
+            iScopedPreferences.saveToProjectSettings(saveData, project);
+            assertEquals("bar: 2\nfoo: 1\n", FileUtils.getFileContents(projectDirYAMLFile));
+            assertEquals(2, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable));
+            FileUtils.writeStrToFile("bar: 1\nfoo: 1\n", projectDirYAMLFile);
+            assertEquals(1, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable));
+            FileUtils.writeStrToFile("foo: 1\n", projectDirYAMLFile);
+            assertEquals(0, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable)); // default in NullPrefsStore
+            pluginPreferenceStore.setValue("bar", 2);
+            assertEquals(2, iScopedPreferences.getInt(pluginPreferenceStore, "bar", adaptable)); // default in NullPrefsStore
+        } finally {
+            ScopedPreferences.USER_HOME_IN_TESTS = null;
+        }
+    }
+}
diff --git a/plugins/org.python.pydev.shared_interactive_console/META-INF/MANIFEST.MF b/plugins/org.python.pydev.shared_interactive_console/META-INF/MANIFEST.MF
index cf55e1d..3ec4a94 100644
--- a/plugins/org.python.pydev.shared_interactive_console/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.shared_interactive_console/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Interactive Console Plug-in
 Bundle-SymbolicName: org.python.pydev.shared_interactive_console;singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: interactive_console.jar,
  commons-logging-1.1.1.jar,
  ws-commons-util-1.0.2.jar,
diff --git a/plugins/org.python.pydev.shared_interactive_console/pom.xml b/plugins/org.python.pydev.shared_interactive_console/pom.xml
index 819dcf2..d30a2b8 100644
--- a/plugins/org.python.pydev.shared_interactive_console/pom.xml
+++ b/plugins/org.python.pydev.shared_interactive_console/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleCommunication.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleCommunication.java
index e618d13..2512e88 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleCommunication.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleCommunication.java
@@ -68,4 +68,9 @@ public interface IScriptConsoleCommunication {
 
     void interrupt();
 
+    /**
+     * I.e.: a debug console that doesn't have a frame is not connected.
+     */
+    boolean isConnected();
+
 }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleInterpreter.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleInterpreter.java
index a69eae2..a30ef59 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleInterpreter.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/IScriptConsoleInterpreter.java
@@ -35,4 +35,6 @@ public interface IScriptConsoleInterpreter extends IScriptConsoleShell, IConsole
 
     void interrupt();
 
+    public IScriptConsoleCommunication getConsoleCommunication();
+
 }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ScriptConsolePreferenceInitializer.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ScriptConsolePreferenceInitializer.java
index bf647f1..f4940e4 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ScriptConsolePreferenceInitializer.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ScriptConsolePreferenceInitializer.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/IScriptConsoleListener.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/IScriptConsoleListener.java
index 46211c4..20a29e7 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/IScriptConsoleListener.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/IScriptConsoleListener.java
@@ -5,7 +5,7 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
- 
+
  *******************************************************************************/
 package org.python.pydev.shared_interactive_console.console.ui;
 
@@ -14,7 +14,9 @@ import org.python.pydev.shared_interactive_console.console.ScriptConsolePrompt;
 
 public interface IScriptConsoleListener {
 
+    // Called in the UI thread before command is entered.
     void userRequest(String text, ScriptConsolePrompt prompt);
 
+    // Called out of the UI thread.
     void interpreterResponse(InterpreterResponse response, ScriptConsolePrompt prompt);
 }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/ScriptConsole.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/ScriptConsole.java
index 298c91b..18d020b 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/ScriptConsole.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/ScriptConsole.java
@@ -14,6 +14,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
 import org.eclipse.debug.ui.console.IConsoleLineTracker;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.text.ITextHover;
@@ -38,6 +39,7 @@ import org.eclipse.ui.part.IPageBookViewPage;
 import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.shared_core.utils.Reflection;
+import org.python.pydev.shared_interactive_console.console.IScriptConsoleCommunication;
 import org.python.pydev.shared_interactive_console.console.IScriptConsoleInterpreter;
 import org.python.pydev.shared_interactive_console.console.InterpreterResponse;
 import org.python.pydev.shared_interactive_console.console.ScriptConsoleHistory;
@@ -70,11 +72,18 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
 
     public static final String DEFAULT_CONSOLE_TYPE = "org.python.pydev.debug.newconsole.PydevConsole";
 
+    public static final String SCRIPT_DEBUG_CONSOLE_IN_PROCESS_CONSOLE = "SCRIPT_DEBUG_CONSOLE_IN_PROCESS_CONSOLE";
+
+    // Backward-compatibility
+    public static ScriptConsole getActiveScriptConsole(String ignored) {
+        return getActiveScriptConsole();
+    }
+
     /**
-     * @param consoleType the console type we're searching for
-     * @return the currently active console.
+     * @return the currently active script console.
      */
-    public static ScriptConsole getActiveScriptConsole(String consoleType) {
+    @SuppressWarnings("restriction")
+    public static ScriptConsole getActiveScriptConsole() {
         IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
         if (window != null) {
             IWorkbenchPage page = window.getActivePage();
@@ -112,8 +121,22 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
                     if (view != null) {
                         IConsole console = view.getConsole();
 
-                        if (console instanceof ScriptConsole && console.getType().equals(consoleType)) {
+                        if (console instanceof ScriptConsole) {
                             return (ScriptConsole) console;
+                        } else {
+                            if (console instanceof ProcessConsole) {
+                                ProcessConsole processConsole = (ProcessConsole) console;
+                                Object scriptConsole = processConsole
+                                        .getAttribute(ScriptConsole.SCRIPT_DEBUG_CONSOLE_IN_PROCESS_CONSOLE);
+                                if (scriptConsole instanceof ScriptConsole) {
+                                    ScriptConsole scriptConsole2 = (ScriptConsole) scriptConsole;
+                                    IScriptConsoleCommunication consoleCommunication = scriptConsole2.getInterpreter()
+                                            .getConsoleCommunication();
+                                    if (consoleCommunication.isConnected()) {
+                                        return scriptConsole2;
+                                    }
+                                }
+                            }
                         }
                     }
                 }
@@ -203,6 +226,10 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
         this.interpreter = interpreter;
     }
 
+    public IScriptConsoleInterpreter getInterpreter() {
+        return interpreter;
+    }
+
     public ScriptConsolePrompt getPrompt() {
         return prompt;
     }
@@ -220,7 +247,7 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
         return page;
     }
 
-    protected abstract SourceViewerConfiguration createSourceViewerConfiguration();
+    public abstract SourceViewerConfiguration createSourceViewerConfiguration();
 
     /**
      * Clears the console
@@ -235,6 +262,16 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
         interpreter.setOnContentsReceivedCallback(onContentsReceived);
     }
 
+    @Override
+    public void beforeHandleCommand(String userInput, ICallback<Object, InterpreterResponse> onResponseReceived) {
+        final Object[] listeners = consoleListeners.getListeners();
+
+        //notify about the user request in the UI thread.
+        for (Object listener : listeners) {
+            ((IScriptConsoleListener) listener).userRequest(userInput, prompt);
+        }
+    }
+
     /**
      * Handles some command that the user entered
      *
@@ -243,11 +280,6 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
     public void handleCommand(String userInput, final ICallback<Object, InterpreterResponse> onResponseReceived) {
         final Object[] listeners = consoleListeners.getListeners();
 
-        //notify about the user request
-        for (Object listener : listeners) {
-            ((IScriptConsoleListener) listener).userRequest(userInput, prompt);
-        }
-
         //executes the user input in the interpreter
         if (interpreter != null) {
             interpreter.exec(userInput, new ICallback<Object, InterpreterResponse>() {
@@ -257,7 +289,7 @@ public abstract class ScriptConsole extends TextConsole implements ICommandHandl
                     prompt.setMode(!response.more);
                     prompt.setNeedInput(response.need_input);
 
-                    //notify about the console answer
+                    //notify about the console answer (not in the UI thread).
                     for (Object listener : listeners) {
                         ((IScriptConsoleListener) listener).interpreterResponse(response, prompt);
                     }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ICommandHandler.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ICommandHandler.java
index c95371e..67e4ef3 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ICommandHandler.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ICommandHandler.java
@@ -21,4 +21,6 @@ public interface ICommandHandler {
     public ICompletionProposal[] getTabCompletions(String commandLine, int cursorPosition);
 
     void setOnContentsReceivedCallback(ICallback<Object, Tuple<String, String>> onContentsReceived);
+
+    void beforeHandleCommand(String userInput, ICallback<Object, InterpreterResponse> onResponseReceived);
 }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleDocumentListener.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleDocumentListener.java
index 648ecb6..84096fc 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleDocumentListener.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleDocumentListener.java
@@ -295,6 +295,14 @@ public class ScriptConsoleDocumentListener implements IDocumentListener {
             int lastLineLength = doc.getLineLength(lastLine);
             int end = doc.getLength();
             int start = end - lastLineLength;
+            // There may be read-only content before the current input. so last line
+            // may look like:
+            // Out[10]: >>> some_user_command
+            // The content before the prompt should be treated as read-only.
+            int promptOffset = doc.get(start, lastLineLength).indexOf(prompt.toString());
+            start += promptOffset;
+            lastLineLength -= promptOffset;
+
             pc.userInput = doc.get(start, lastLineLength);
             pc.cursorOffset = end - viewer.getCaretOffset();
             doc.replace(start, lastLineLength, "");
@@ -402,6 +410,7 @@ public class ScriptConsoleDocumentListener implements IDocumentListener {
                 Log.log(e);
             }
         }
+        revealEndOfDocument();
     }
 
     /**
@@ -591,6 +600,8 @@ public class ScriptConsoleDocumentListener implements IDocumentListener {
             }
         };
 
+        handler.beforeHandleCommand(commandLine, onResponseReceived);
+
         //Handle the command in a thread that doesn't block the U/I.
         Job j = new Job("PyDev Console Hander") {
             @Override
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsolePage.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsolePage.java
index c38b8e1..9cf498d 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsolePage.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsolePage.java
@@ -119,7 +119,7 @@ public class ScriptConsolePage extends TextConsolePage implements IScriptConsole
         ScriptConsole console = (ScriptConsole) getConsole();
         viewer = new ScriptConsoleViewer(parent, console, this, console.createStyleProvider(),
                 console.getInitialCommands(), console.getFocusOnStart(), console.getBackspaceAction(),
-                console.getAutoEditStrategy(), console.getTabCompletionEnabled());
+                console.getAutoEditStrategy(), console.getTabCompletionEnabled(), true);
         viewer.configure(cfg);
         return viewer;
     }
diff --git a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleViewer.java b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleViewer.java
index ee3f2e5..6efea3a 100644
--- a/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleViewer.java
+++ b/plugins/org.python.pydev.shared_interactive_console/src/org/python/pydev/shared_interactive_console/console/ui/internal/ScriptConsoleViewer.java
@@ -20,7 +20,9 @@ import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.contentassist.ContentAssistEvent;
 import org.eclipse.jface.text.contentassist.ICompletionListener;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
 import org.eclipse.jface.text.contentassist.IContentAssistantExtension2;
+import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
 import org.eclipse.jface.text.source.SourceViewerConfiguration;
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.ISelection;
@@ -211,6 +213,8 @@ public class ScriptConsoleViewer extends TextConsoleViewer implements IScriptCon
      */
     private AbstractHandleBackspaceAction handleBackspaceAction;
 
+    private boolean showInitialCommands;
+
     /**
      * This is the text widget that's used to edit the console. It has some treatments to handle
      * commands that should act differently (special handling for when the caret is on the last line
@@ -705,8 +709,9 @@ public class ScriptConsoleViewer extends TextConsoleViewer implements IScriptCon
     public ScriptConsoleViewer(Composite parent, ScriptConsole console,
             final IScriptConsoleContentHandler contentHandler, IConsoleStyleProvider styleProvider,
             String initialCommands, boolean focusOnStart, AbstractHandleBackspaceAction handleBackspaceAction,
-            IHandleScriptAutoEditStrategy strategy, boolean tabCompletionEnabled) {
+            IHandleScriptAutoEditStrategy strategy, boolean tabCompletionEnabled, boolean showInitialCommands) {
         super(parent, console);
+        this.showInitialCommands = showInitialCommands;
         this.handleBackspaceAction = handleBackspaceAction;
         this.focusOnStart = focusOnStart;
         this.tabCompletionEnabled = tabCompletionEnabled;
@@ -863,13 +868,21 @@ public class ScriptConsoleViewer extends TextConsoleViewer implements IScriptCon
         }
 
         if (isMainViewer) {
-            clear(true);
+            clear(showInitialCommands);
         }
         if (focusOnStart) {
             this.getTextWidget().setFocus();
         }
     }
 
+    public IContentAssistant getContentAssist() {
+        return fContentAssistant;
+    }
+
+    public IQuickAssistAssistant getQuickFixContentAssist() {
+        return fQuickAssistAssistant;
+    }
+
     /**
      * @return the contents of the current buffer (text edited still not passed to the shell)
      */
diff --git a/plugins/org.python.pydev.shared_ui/META-INF/MANIFEST.MF b/plugins/org.python.pydev.shared_ui/META-INF/MANIFEST.MF
index 78eac42..2637e01 100644
--- a/plugins/org.python.pydev.shared_ui/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev.shared_ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Shared Ui Plug-in
 Bundle-SymbolicName: org.python.pydev.shared_ui;singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: shared_ui.jar
 Bundle-Activator: org.python.pydev.shared_ui.SharedUiPlugin
 Bundle-Localization: plugin
diff --git a/plugins/org.python.pydev.shared_ui/icons/console_disabled.png b/plugins/org.python.pydev.shared_ui/icons/console_disabled.png
new file mode 100644
index 0000000..a846217
Binary files /dev/null and b/plugins/org.python.pydev.shared_ui/icons/console_disabled.png differ
diff --git a/plugins/org.python.pydev.shared_ui/icons/console_enabled.png b/plugins/org.python.pydev.shared_ui/icons/console_enabled.png
new file mode 100644
index 0000000..d72ba16
Binary files /dev/null and b/plugins/org.python.pydev.shared_ui/icons/console_enabled.png differ
diff --git a/plugins/org.python.pydev.shared_ui/pom.xml b/plugins/org.python.pydev.shared_ui/pom.xml
index f6d600d..cc93096 100644
--- a/plugins/org.python.pydev.shared_ui/pom.xml
+++ b/plugins/org.python.pydev.shared_ui/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ColorCache.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ColorCache.java
index b2cceba..e9a8b3c 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ColorCache.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ColorCache.java
@@ -26,11 +26,11 @@ import org.python.pydev.shared_core.log.Log;
 /**
  * ColorCache gets colors by RGB, or name
  * Named colors are retrieved from preferences
- * 
+ *
  * It would be nice if color cache listened to preference changes
  * and modified its colors when prefs changed. But currently colors are
  * immutable, so this can't be done
-        implements Preferences.IPropertyChangeListener 
+        implements Preferences.IPropertyChangeListener
         preferences.addPropertyChangeListener(this);
         preferences.removePropertyChangeListener(this);
 */
@@ -79,7 +79,7 @@ public abstract class ColorCache {
     protected Color getNamedColor(String name) {
         Color color = fNamedColorTable.get(name);
         if (color == null || color.isDisposed()) {
-            String colorCode = preferences.getString(name);
+            String colorCode = preferences != null ? preferences.getString(name) : "";
             if (colorCode.length() == 0) {
                 if (name.equals("RED")) {
                     color = getColor(new RGB(255, 0, 0));
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/EditorUtils.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/EditorUtils.java
index 066cb4b..4afb4b8 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/EditorUtils.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/EditorUtils.java
@@ -234,6 +234,34 @@ public class EditorUtils {
         }
     }
 
+    /**
+     * Open an editor anywhere on the file system using Eclipse's default editor registered for the given file.
+     *
+     * @param fileToOpen File to open
+     * @note we must be in the UI thread for this method to work.
+     * @return Editor opened or created
+     */
+    public static IEditorPart openFile(IFile fileToOpen) {
+        final IWorkbench workbench = PlatformUI.getWorkbench();
+        if (workbench == null) {
+            throw new RuntimeException("workbench cannot be null");
+        }
+
+        IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
+        if (activeWorkbenchWindow == null) {
+            throw new RuntimeException(
+                    "activeWorkbenchWindow cannot be null (we have to be in a ui thread for this to work)");
+        }
+
+        IWorkbenchPage wp = activeWorkbenchWindow.getActivePage();
+        try {
+            return IDE.openEditor(wp, fileToOpen);
+        } catch (Exception e) {
+            Log.log("Editor failed to open", e);
+            return null;
+        }
+    }
+
     public static IWorkbenchPartSite getSite() {
         final IWorkbench workbench = PlatformUI.getWorkbench();
         IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ImageCache.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ImageCache.java
index 507bbc6..4914ec9 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ImageCache.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/ImageCache.java
@@ -38,7 +38,7 @@ public class ImageCache {
 
     /**
      * Helper to decorate an image.
-     * 
+     *
      * The only method that should be used is: drawDecoration
      */
     private static final class ImageDecorator extends CompositeImageDescriptor {
@@ -48,10 +48,12 @@ public class ImageCache {
         private int ox;
         private int oy;
 
+        @Override
         protected Point getSize() {
             return size;
         }
 
+        @Override
         protected void drawCompositeImage(int width, int height) {
             this.drawImage(base, 0, 0);
             this.drawImage(decoration, ox, oy);
@@ -67,12 +69,42 @@ public class ImageCache {
         }
     }
 
+    // Access should be locked.
     private final Map<Object, Image> imageHash = new HashMap<Object, Image>(10);
+
+    private Image getFromImageHash(Object key) {
+        synchronized (lock) {
+            Image ret = imageHash.get(key);
+            if (ret != null && ret.isDisposed()) {
+                imageHash.remove(key);
+                ret = null;
+            }
+            return ret;
+        }
+    }
+
+    private Image putOnImageHash(Object key, Image image) {
+        synchronized (lock) {
+            // Check if it wasn't created in the meanwhile... because
+            // we only lock the actual put/get, not the image creation, we
+            // might actually create an image twice. Ssshh, don't let the
+            // external world know about it!
+            Image createdInMeanwhile = imageHash.get(key);
+            if (createdInMeanwhile != null && !createdInMeanwhile.isDisposed()) {
+                image.dispose();
+                image = createdInMeanwhile;
+            } else {
+                imageHash.put(key, image);
+            }
+            return image;
+        }
+    }
+
     private final Map<Object, ImageDescriptor> descriptorHash = new HashMap<Object, ImageDescriptor>(10);
     private final ImageDecorator imageDecorator = new ImageDecorator();
 
     private final URL baseURL;
-    private Image missing = null;
+    private volatile Image missing = null;
     private final Object lock = new Object();
     private final Object descriptorLock = new Object();
 
@@ -83,11 +115,15 @@ public class ImageCache {
     public void dispose() {
         synchronized (lock) {
             Iterator<Image> e = imageHash.values().iterator();
-            while (e.hasNext())
-                ((Image) e.next()).dispose();
-            if (missing != null) {
-                missing.dispose();
+            while (e.hasNext()) {
+                e.next().dispose();
+            }
+            imageHash.clear();
+            Image m = missing;
+            if (m != null) {
+                m.dispose();
             }
+            missing = null;
         }
     }
 
@@ -96,32 +132,37 @@ public class ImageCache {
      * @return the image
      */
     public Image get(String key) {
-        synchronized (lock) {
-            Image image = (Image) imageHash.get(key);
-            if (image == null) {
-                ImageDescriptor desc;
-                try {
-                    desc = getDescriptor(key);
-                    image = desc.createImage();
-                    imageHash.put(key, image);
-                } catch (NoClassDefFoundError e) {
-                    //we're in tests...
-                    return null;
-                } catch (UnsatisfiedLinkError e) {
-                    //we're in tests...
-                    return null;
-                } catch (Exception e) {
-                    // If image is missing, create a default missing one
-                    Log.log("ERROR: Missing image: " + key);
-                    if (missing == null) {
-                        desc = ImageDescriptor.getMissingImageDescriptor();
-                        missing = desc.createImage();
-                    }
-                    image = missing;
+        Image image = getFromImageHash(key);
+
+        if (image == null) {
+            ImageDescriptor desc;
+            try {
+                // Don't lock for this creation (GTK has a global lock for the image
+                // creation which is the same one for the main thread, so, if this
+                // happens in a thread, the main thread could deadlock).
+                // #PyDev-527: Deadlock in ImageCache rendering debug completions
+                desc = getDescriptor(key);
+                image = desc.createImage();
+                image = putOnImageHash(key, image);
+
+            } catch (NoClassDefFoundError e) {
+                //we're in tests...
+                return null;
+            } catch (UnsatisfiedLinkError e) {
+                //we're in tests...
+                return null;
+            } catch (Exception e) {
+                // If image is missing, create a default missing one
+                Log.log("ERROR: Missing image: " + key);
+                Image m = missing;
+                if (m == null || m.isDisposed()) {
+                    desc = ImageDescriptor.getMissingImageDescriptor();
+                    m = missing = desc.createImage();
                 }
+                image = m;
             }
-            return image;
         }
+        return image;
     }
 
     public Image getImageDecorated(String key, String decoration) {
@@ -142,28 +183,28 @@ public class ImageCache {
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public Image getImageDecorated(String key, String decoration, int decorationLocation, String secondDecoration,
             int secondDecorationLocation) {
-        synchronized (lock) {
-            Object cacheKey = new Tuple4(key, decoration, decorationLocation, "imageDecoration");
-            if (secondDecoration != null) {
-                //Also add the second decoration to the cache key.
-                cacheKey = new Tuple3(cacheKey, secondDecoration, secondDecorationLocation);
-            }
-
-            Image image = imageHash.get(cacheKey);
-            if (image == null) {
-                Display display = Display.getCurrent();
+        Display display = Display.getCurrent();
+        if (display == null) {
+            Log.log("This method should only be called in a UI thread.");
+        }
 
-                //Note that changing the image data gotten here won't affect the original image.
-                ImageData baseImageData = get(key).getImageData();
-                image = decorateImage(decoration, decorationLocation, display, baseImageData);
-                if (secondDecoration != null) {
-                    image = decorateImage(secondDecoration, secondDecorationLocation, display, image.getImageData());
-                }
-                imageHash.put(cacheKey, image);
+        Object cacheKey = new Tuple4(key, decoration, decorationLocation, "imageDecoration");
+        if (secondDecoration != null) {
+            //Also add the second decoration to the cache key.
+            cacheKey = new Tuple3(cacheKey, secondDecoration, secondDecorationLocation);
+        }
 
+        Image image = getFromImageHash(cacheKey);
+        if (image == null) {
+            //Note that changing the image data gotten here won't affect the original image.
+            ImageData baseImageData = get(key).getImageData();
+            image = decorateImage(decoration, decorationLocation, display, baseImageData);
+            if (secondDecoration != null) {
+                image = decorateImage(secondDecoration, secondDecorationLocation, display, image.getImageData());
             }
-            return image;
+            image = putOnImageHash(cacheKey, image);
         }
+        return image;
     }
 
     private Image decorateImage(String decoration, int decorationLocation, Display display, ImageData baseImageData)
@@ -195,55 +236,57 @@ public class ImageCache {
      * @param stringToAddToDecoration the string that should be drawn over the image
      */
     public Image getStringDecorated(String key, String stringToAddToDecoration) {
-        synchronized (lock) {
-            Tuple3<String, String, String> cacheKey = new Tuple3<String, String, String>(key, stringToAddToDecoration,
-                    "stringDecoration");
-
-            Image image = imageHash.get(cacheKey);
-            if (image == null) {
-                Display display = Display.getCurrent();
-                image = new Image(display, get(key), SWT.IMAGE_COPY);
-                imageHash.put(cacheKey, image); //put it there (even though it'll still be changed).
-
-                GC gc = new GC(image);
-
-                //		        Color color = new Color(display, 0, 0, 0);
-                //		        Color color2 = new Color(display, 255, 255, 255);
-                //		        gc.setForeground(color2); 
-                //		        gc.setBackground(color2); 
-                //		        gc.setFillRule(SWT.FILL_WINDING);
-                //		        gc.fillRoundRectangle(2, 1, base-1, base, 2, 2);
-                //		        gc.setForeground(color); 
-                //		        gc.drawRoundRectangle(6, 0, base, base+1, 2, 2);
-                //		        color2.dispose();
-                //		        color.dispose();
-
-                Color colorBackground = new Color(display, 255, 255, 255);
-                Color colorForeground = new Color(display, 0, 83, 41);
-
-                // get TextFont from preferences
-                FontData fontData = FontUtils.getFontData(IFontUsage.IMAGECACHE, true);
-                fontData.setStyle(SWT.BOLD);
-                Font font = new Font(display, fontData);
-
-                try {
-                    gc.setForeground(colorForeground);
-                    gc.setBackground(colorBackground);
-                    gc.setTextAntialias(SWT.ON);
-                    gc.setFont(font);
-                    gc.drawText(stringToAddToDecoration, 5, 0, true);
-                } catch (Exception e) {
-                    Log.log(e);
-                } finally {
-                    colorBackground.dispose();
-                    colorForeground.dispose();
-                    font.dispose();
-                    gc.dispose();
-                }
+        Display display = Display.getCurrent();
+        if (display == null) {
+            Log.log("This method should only be called in a UI thread.");
+        }
 
+        Tuple3<String, String, String> cacheKey = new Tuple3<String, String, String>(key, stringToAddToDecoration,
+                "stringDecoration");
+
+        Image image = getFromImageHash(cacheKey);
+        if (image == null) {
+            image = new Image(display, get(key), SWT.IMAGE_COPY);
+
+            GC gc = new GC(image);
+
+            //		        Color color = new Color(display, 0, 0, 0);
+            //		        Color color2 = new Color(display, 255, 255, 255);
+            //		        gc.setForeground(color2);
+            //		        gc.setBackground(color2);
+            //		        gc.setFillRule(SWT.FILL_WINDING);
+            //		        gc.fillRoundRectangle(2, 1, base-1, base, 2, 2);
+            //		        gc.setForeground(color);
+            //		        gc.drawRoundRectangle(6, 0, base, base+1, 2, 2);
+            //		        color2.dispose();
+            //		        color.dispose();
+
+            Color colorBackground = new Color(display, 255, 255, 255);
+            Color colorForeground = new Color(display, 0, 83, 41);
+
+            // get TextFont from preferences
+            FontData fontData = FontUtils.getFontData(IFontUsage.IMAGECACHE, true);
+            fontData.setStyle(SWT.BOLD);
+            Font font = new Font(display, fontData);
+
+            try {
+                gc.setForeground(colorForeground);
+                gc.setBackground(colorBackground);
+                gc.setTextAntialias(SWT.ON);
+                gc.setFont(font);
+                gc.drawText(stringToAddToDecoration, 5, 0, true);
+            } catch (Exception e) {
+                Log.log(e);
+            } finally {
+                colorBackground.dispose();
+                colorForeground.dispose();
+                font.dispose();
+                gc.dispose();
             }
-            return image;
+            image = putOnImageHash(cacheKey, image);
+
         }
+        return image;
     }
 
     /**
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/SharedUiPlugin.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/SharedUiPlugin.java
index b07253e..74f4e3a 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/SharedUiPlugin.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/SharedUiPlugin.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
@@ -8,6 +8,8 @@ package org.python.pydev.shared_ui;
 
 import java.lang.reflect.Field;
 
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
 import org.eclipse.e4.ui.services.IStylingEngine;
 import org.eclipse.jface.resource.ImageDescriptor;
@@ -130,4 +132,15 @@ public class SharedUiPlugin extends AbstractUIPlugin {
             Log.log(e);
         }
     }
+
+    public static IStatus makeErrorStatus(Exception e, boolean useErrorMessage) {
+        String message = "";
+        if (useErrorMessage) {
+            message = e.getMessage();
+            if (message == null) {
+                message = "null";
+            }
+        }
+        return new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, message, e);
+    }
 }
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/UIConstants.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/UIConstants.java
index 6f1e02d..433a3df 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/UIConstants.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/UIConstants.java
@@ -130,6 +130,9 @@ public class UIConstants {
     public static final String BACK = "icons/backward_nav.gif";
     public static final String HOME = "icons/home_nav.gif";
 
+    public static final String CONSOLE_ENABLED = "icons/console_enabled.png";
+    public static final String CONSOLE_DISABLED = "icons/console_disabled.png";
+
     public static final String FORCE_TABS_ACTIVE = "icons/tabs_active.png";
     public static final String FORCE_TABS_INACTIVE = "icons/tabs_inactive.png";
     public static final String PY_LINT_ICON = "icons/pylint.png";
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/debug/ConsoleRestartLaunchPageParticipant.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/debug/ConsoleRestartLaunchPageParticipant.java
index 1901121..ed64c1d 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/debug/ConsoleRestartLaunchPageParticipant.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/debug/ConsoleRestartLaunchPageParticipant.java
@@ -85,6 +85,7 @@ public class ConsoleRestartLaunchPageParticipant implements IConsolePageParticip
         return null;
     }
 
+    @Override
     public void dispose() {
         DebugPlugin.getDefault().removeDebugEventListener(this);
         if (restartLaunchAction != null) {
@@ -97,9 +98,11 @@ public class ConsoleRestartLaunchPageParticipant implements IConsolePageParticip
         }
     }
 
+    @Override
     public void activated() {
     }
 
+    @Override
     public void deactivated() {
     }
 
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/DialogHelpers.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/DialogHelpers.java
index 4ea5b11..618384b 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/DialogHelpers.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/DialogHelpers.java
@@ -60,4 +60,31 @@ public class DialogHelpers {
         }
         return null;
     }
+
+    // Return could be null if user cancelled.
+    public static Integer openAskInt(String title, String message, int initial) {
+        Shell shell = EditorUtils.getShell();
+        String initialValue = "" + initial;
+        IInputValidator validator = new IInputValidator() {
+
+            @Override
+            public String isValid(String newText) {
+                if (newText.length() == 0) {
+                    return "At least 1 char must be provided.";
+                }
+                try {
+                    Integer.parseInt(newText);
+                } catch (Exception e) {
+                    return "A number is required.";
+                }
+                return null;
+            }
+        };
+        InputDialog dialog = new InputDialog(shell, title, message, initialValue, validator);
+        dialog.setBlockOnOpen(true);
+        if (dialog.open() == Window.OK) {
+            return Integer.parseInt(dialog.getValue());
+        }
+        return null;
+    }
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/ProjectSelectionDialog.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/ProjectSelectionDialog.java
similarity index 75%
rename from plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/ProjectSelectionDialog.java
rename to plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/ProjectSelectionDialog.java
index b6d78a8..2402c91 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/ProjectSelectionDialog.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/ProjectSelectionDialog.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.ui.dialogs;
+package org.python.pydev.shared_ui.dialogs;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -13,8 +13,10 @@ import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
@@ -34,7 +36,7 @@ import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.ui.dialogs.PatternFilter;
 import org.eclipse.ui.dialogs.SelectionStatusDialog;
 import org.eclipse.ui.model.WorkbenchLabelProvider;
-import org.python.pydev.plugin.StatusInfo;
+import org.python.pydev.shared_ui.SharedUiPlugin;
 import org.python.pydev.shared_ui.tree.PyFilteredTree;
 
 public class ProjectSelectionDialog extends SelectionStatusDialog {
@@ -50,10 +52,24 @@ public class ProjectSelectionDialog extends SelectionStatusDialog {
 
     private PyFilteredTree filteredTree;
 
+    private boolean multipleSelection;
+
+    /**
+     * May be set by the user to show projects differently (default is WorkbenchLabelProvider).
+     * Must be set before the dialog is opened.
+     */
+    public IBaseLabelProvider labelProvider;
+
     public ProjectSelectionDialog(Shell parentShell, String natureId) {
+        this(parentShell, natureId, false);
+    }
+
+    public ProjectSelectionDialog(Shell parentShell, String natureId, boolean multipleSelection) {
         super(parentShell);
+        this.labelProvider = new WorkbenchLabelProvider();
         setTitle("Select project");
         setMessage("Select project");
+        this.multipleSelection = multipleSelection;
         this.natureId = natureId;
         int shellStyle = getShellStyle();
         setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
@@ -91,7 +107,7 @@ public class ProjectSelectionDialog extends SelectionStatusDialog {
         data.widthHint = WIDGET_WIDTH;
         fTreeViewer.getTree().setLayoutData(data);
 
-        fTreeViewer.setLabelProvider(new WorkbenchLabelProvider());
+        fTreeViewer.setLabelProvider(labelProvider);
         fTreeViewer.setContentProvider(new ArrayContentProvider());
 
         fTreeViewer.getControl().setFont(font);
@@ -118,16 +134,36 @@ public class ProjectSelectionDialog extends SelectionStatusDialog {
 
         doSelectionChanged(new Object[0]);
         Dialog.applyDialogFont(composite);
+        SharedUiPlugin.setCssId(parent, "py-project-selection-dialog", true);
         return composite;
     }
 
     private void doSelectionChanged(Object[] objects) {
-        if (objects.length != 1) {
-            updateStatus(new StatusInfo(IStatus.ERROR, "")); //$NON-NLS-1$
-            setSelectionResult(null);
+        if (multipleSelection) {
+            if (objects.length == 0) {
+                updateStatus(new Status(IStatus.ERROR, "org.python.pydev.shared_ui", "Select one or more projects")); //$NON-NLS-1$
+                setSelectionResult(null);
+            } else {
+                updateStatus(new Status(IStatus.OK, "org.python.pydev.shared_ui", objects.length + " selected"));
+                setSelectionResult(objects);
+            }
         } else {
-            updateStatus(new StatusInfo());
-            setSelectionResult(objects);
+            if (objects.length != 1) {
+                updateStatus(new Status(IStatus.ERROR, "org.python.pydev.shared_ui", "Select one project")); //$NON-NLS-1$
+                setSelectionResult(null);
+            } else {
+                updateStatus(new Status(IStatus.OK, "org.python.pydev.shared_ui", objects.length + " selected"));
+                setSelectionResult(objects);
+            }
+        }
+    }
+
+    @Override
+    protected void updateStatus(IStatus status) {
+        super.updateStatus(status);
+        Control area = this.getDialogArea();
+        if (area != null) {
+            SharedUiPlugin.fixSelectionStatusDialogStatusLineColor(this, area.getBackground());
         }
     }
 
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/SelectElementDialog.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/SelectElementDialog.java
index 970bce3..e64f208 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/SelectElementDialog.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/dialogs/SelectElementDialog.java
@@ -58,8 +58,10 @@ public class SelectElementDialog extends ElementListSelectionDialog {
     @Override
     protected void updateStatus(IStatus status) {
         super.updateStatus(status);
-        SharedUiPlugin.fixSelectionStatusDialogStatusLineColor(this, this.getDialogArea()
-                .getBackground());
+        Control area = this.getDialogArea();
+        if (area != null) {
+            SharedUiPlugin.fixSelectionStatusDialogStatusLineColor(this, area.getBackground());
+        }
     }
 
     /**
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/BooleanFieldEditorCustom.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/BooleanFieldEditorCustom.java
index 27275bc..a5d2ecd 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/BooleanFieldEditorCustom.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/BooleanFieldEditorCustom.java
@@ -6,12 +6,28 @@ import org.eclipse.swt.widgets.Composite;
 
 public class BooleanFieldEditorCustom extends BooleanFieldEditor {
 
+    private Button checkBox;
+
     public BooleanFieldEditorCustom(String name, String labelText, int style, Composite parent) {
         super(name, labelText, style, parent);
+        this.checkBox = getCheckBox(parent);
+    }
+
+    public BooleanFieldEditorCustom(String name, String labelText, Composite parent) {
+        super(name, labelText, parent);
+        this.checkBox = getCheckBox(parent);
+    }
+
+    public Button getCheckBox() {
+        return checkBox;
     }
 
     public Button getCheckBox(Composite parent) {
         return getChangeControl(parent);
     }
 
+    public void setTooltip(Composite parent, String tooltip) {
+        getChangeControl(parent).setToolTipText(tooltip);
+    }
+
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/utils/ComboFieldEditor.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ComboFieldEditor.java
similarity index 93%
rename from plugins/org.python.pydev/src/org/python/pydev/utils/ComboFieldEditor.java
rename to plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ComboFieldEditor.java
index dc05cfa..4e8f8ea 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/utils/ComboFieldEditor.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ComboFieldEditor.java
@@ -4,7 +4,7 @@
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
  */
-package org.python.pydev.utils;
+package org.python.pydev.shared_ui.field_editors;
 
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.preference.FieldEditor;
@@ -12,9 +12,11 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.python.pydev.shared_core.log.Log;
 
 /**
  * A field editor for a combo box that allows the drop-down selection of one of
@@ -77,6 +79,13 @@ public class ComboFieldEditor extends FieldEditor {
         return true;
     }
 
+    @Override
+    public void fillIntoGrid(Composite parent, int numColumns) {
+        Assert.isTrue(parent.getLayout() instanceof GridLayout);
+        doFillIntoGrid(parent, numColumns);
+        adjustForNumColumns(numColumns);
+    }
+
     /* (non-Javadoc)
      * @see org.eclipse.jface.preference.FieldEditor#adjustForNumColumns(int)
      */
@@ -199,13 +208,15 @@ public class ComboFieldEditor extends FieldEditor {
                 return entry[1];
             }
         }
-        return fEntryNamesAndValues[0][0];
+
+        Log.log("Unable to find entry for: " + name + " returning default.");
+        return fEntryNamesAndValues[0][1];
     }
 
     /*
      * Set the name in the combo widget to match the specified value.
      */
-    private void updateComboForValue(String value) {
+    public void updateComboForValue(String value) {
         fValue = value;
         for (int i = 0; i < fEntryNamesAndValues.length; i++) {
             if (value.equals(fEntryNamesAndValues[i][1])) {
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/FileFieldEditorCustom.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/FileFieldEditorCustom.java
new file mode 100644
index 0000000..064c875
--- /dev/null
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/FileFieldEditorCustom.java
@@ -0,0 +1,54 @@
+package org.python.pydev.shared_ui.field_editors;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+public class FileFieldEditorCustom extends FileFieldEditor {
+
+    public FileFieldEditorCustom(String name, String labelText, Composite parent) {
+        super(name, labelText, parent);
+    }
+
+    @Override
+    public void fillIntoGrid(Composite parent, int numColumns) {
+        Assert.isTrue(parent.getLayout() instanceof GridLayout);
+        doFillIntoGrid(parent, numColumns);
+        adjustForNumColumns(numColumns);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void adjustForNumColumns(int numColumns) {
+        if (numColumns == 2) {
+            // Label will take 2 cols and text/button the other 2
+            Label labelControl = getLabelControl();
+            GridData layoutData = (GridData) labelControl.getLayoutData();
+            if (layoutData == null) {
+                layoutData = new GridData();
+                labelControl.setLayoutData(layoutData);
+            }
+            layoutData.horizontalSpan = 2;
+            ((GridData) getTextControl().getLayoutData()).horizontalSpan = 1;
+
+        } else if (numColumns == 1) {
+            // 1 column each.
+            Label labelControl = getLabelControl();
+            GridData layoutData = (GridData) labelControl.getLayoutData();
+            if (layoutData == null) {
+                layoutData = new GridData();
+                labelControl.setLayoutData(layoutData);
+            }
+            layoutData.horizontalSpan = 1;
+            ((GridData) getTextControl().getLayoutData()).horizontalSpan = 1;
+
+        } else {
+            ((GridData) getTextControl().getLayoutData()).horizontalSpan = numColumns - 2;
+        }
+    }
+}
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/RadioGroupFieldEditor.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/RadioGroupFieldEditor.java
new file mode 100644
index 0000000..f2d5f43
--- /dev/null
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/RadioGroupFieldEditor.java
@@ -0,0 +1,357 @@
+package org.python.pydev.shared_ui.field_editors;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+
+/**
+ * A field editor for an enumeration type preference.
+ * The choices are presented as a list of radio buttons.
+ */
+public class RadioGroupFieldEditor extends FieldEditor {
+
+    /**
+     * List of radio button entries of the form [label,value].
+     */
+    private String[][] labelsAndValues;
+
+    /**
+     * Number of columns into which to arrange the radio buttons.
+     */
+    private int numColumns;
+
+    /**
+     * Indent used for the first column of the radion button matrix.
+     */
+    private int indent = HORIZONTAL_GAP;
+
+    /**
+     * The current value, or <code>null</code> if none.
+     */
+    private String value;
+
+    /**
+     * The box of radio buttons, or <code>null</code> if none
+     * (before creation and after disposal).
+     */
+    private Composite radioBox;
+
+    /**
+     * The radio buttons, or <code>null</code> if none
+     * (before creation and after disposal).
+     */
+    private Button[] radioButtons;
+
+    /**
+     * Whether to use a Group control.
+     */
+    private boolean useGroup;
+
+    /**
+     * Creates a new radio group field editor 
+     */
+    protected RadioGroupFieldEditor() {
+    }
+
+    /**
+     * Creates a radio group field editor.  
+     * This constructor does not use a <code>Group</code> to contain the radio buttons.
+     * It is equivalent to using the following constructor with <code>false</code>
+     * for the <code>useGroup</code> argument.
+     * <p>
+     * Example usage:
+     * <pre>
+     *		RadioGroupFieldEditor editor= new RadioGroupFieldEditor(
+     *			"GeneralPage.DoubleClick", resName, 1,
+     *			new String[][] {
+     *				{"Open Browser", "open"},
+     *				{"Expand Tree", "expand"}
+     *			},
+     *          parent);	
+     * </pre>
+     * </p>
+     * 
+     * @param name the name of the preference this field editor works on
+     * @param labelText the label text of the field editor
+     * @param numColumns the number of columns for the radio button presentation
+     * @param labelAndValues list of radio button [label, value] entries;
+     *  the value is returned when the radio button is selected
+     * @param parent the parent of the field editor's control
+     */
+    public RadioGroupFieldEditor(String name, String labelText, int numColumns,
+            String[][] labelAndValues, Composite parent) {
+        this(name, labelText, numColumns, labelAndValues, parent, false);
+    }
+
+    /**
+     * Creates a radio group field editor.
+     * <p>
+     * Example usage:
+     * <pre>
+     *		RadioGroupFieldEditor editor= new RadioGroupFieldEditor(
+     *			"GeneralPage.DoubleClick", resName, 1,
+     *			new String[][] {
+     *				{"Open Browser", "open"},
+     *				{"Expand Tree", "expand"}
+     *			},
+     *          parent,
+     *          true);	
+     * </pre>
+     * </p>
+     * 
+     * @param name the name of the preference this field editor works on
+     * @param labelText the label text of the field editor
+     * @param numColumns the number of columns for the radio button presentation
+     * @param labelAndValues list of radio button [label, value] entries;
+     *  the value is returned when the radio button is selected
+     * @param parent the parent of the field editor's control
+     * @param useGroup whether to use a Group control to contain the radio buttons
+     */
+    public RadioGroupFieldEditor(String name, String labelText, int numColumns,
+            String[][] labelAndValues, Composite parent, boolean useGroup) {
+        init(name, labelText);
+        Assert.isTrue(checkArray(labelAndValues));
+        this.labelsAndValues = labelAndValues;
+        this.numColumns = numColumns;
+        this.useGroup = useGroup;
+        createControl(parent);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void adjustForNumColumns(int numColumns) {
+        Control control = getLabelControl();
+        if (control != null) {
+            ((GridData) control.getLayoutData()).horizontalSpan = numColumns;
+        }
+        ((GridData) radioBox.getLayoutData()).horizontalSpan = numColumns;
+    }
+
+    /**
+     * Checks whether given <code>String[][]</code> is of "type" 
+     * <code>String[][2]</code>.
+     * @param table
+     *
+     * @return <code>true</code> if it is ok, and <code>false</code> otherwise
+     */
+    private boolean checkArray(String[][] table) {
+        if (table == null) {
+            return false;
+        }
+        for (int i = 0; i < table.length; i++) {
+            String[] array = table[i];
+            if (array == null || array.length != 2) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void doFillIntoGrid(Composite parent, int numColumns) {
+        if (useGroup) {
+            Control control = getRadioBoxControl(parent);
+            GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+            control.setLayoutData(gd);
+        } else {
+            Control control = getLabelControl(parent);
+            GridData gd = new GridData();
+            gd.horizontalSpan = numColumns;
+            control.setLayoutData(gd);
+            control = getRadioBoxControl(parent);
+            gd = new GridData();
+            gd.horizontalSpan = numColumns;
+            gd.horizontalIndent = indent;
+            control.setLayoutData(gd);
+        }
+
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void doLoad() {
+        updateValue(getPreferenceStore().getString(getPreferenceName()));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void doLoadDefault() {
+        updateValue(getPreferenceStore().getDefaultString(getPreferenceName()));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    protected void doStore() {
+        if (value == null) {
+            getPreferenceStore().setToDefault(getPreferenceName());
+            return;
+        }
+
+        getPreferenceStore().setValue(getPreferenceName(), value);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on FieldEditor.
+     */
+    @Override
+    public int getNumberOfControls() {
+        return 1;
+    }
+
+    /**
+     * Returns this field editor's radio group control.
+     * @param parent The parent to create the radioBox in
+     * @return the radio group control
+     */
+    public Composite getRadioBoxControl(Composite parent) {
+        if (radioBox == null) {
+
+            Font font = parent.getFont();
+
+            if (useGroup) {
+                Group group = new Group(parent, SWT.NONE);
+                group.setFont(font);
+                String text = getLabelText();
+                if (text != null) {
+                    group.setText(text);
+                }
+                radioBox = group;
+                GridLayout layout = new GridLayout();
+                layout.horizontalSpacing = HORIZONTAL_GAP;
+                layout.numColumns = numColumns;
+                radioBox.setLayout(layout);
+            } else {
+                radioBox = new Composite(parent, SWT.NONE);
+                GridLayout layout = new GridLayout();
+                layout.marginWidth = 0;
+                layout.marginHeight = 0;
+                layout.horizontalSpacing = HORIZONTAL_GAP;
+                layout.numColumns = numColumns;
+                radioBox.setLayout(layout);
+                radioBox.setFont(font);
+            }
+
+            radioButtons = new Button[labelsAndValues.length];
+            for (int i = 0; i < labelsAndValues.length; i++) {
+                Button radio = new Button(radioBox, SWT.RADIO | SWT.LEFT);
+                radioButtons[i] = radio;
+                String[] labelAndValue = labelsAndValues[i];
+                radio.setText(labelAndValue[0]);
+                radio.setData(labelAndValue[1]);
+                radio.setFont(font);
+                radio.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent event) {
+                        String oldValue = value;
+                        value = (String) event.widget.getData();
+                        setPresentsDefaultValue(false);
+                        fireValueChanged(VALUE, oldValue, value);
+                    }
+                });
+            }
+            radioBox.addDisposeListener(new DisposeListener() {
+                @Override
+                public void widgetDisposed(DisposeEvent event) {
+                    radioBox = null;
+                    radioButtons = null;
+                }
+            });
+        } else {
+            checkParent(radioBox, parent);
+        }
+        return radioBox;
+    }
+
+    /**
+     * Sets the indent used for the first column of the radion button matrix.
+     *
+     * @param indent the indent (in pixels)
+     */
+    public void setIndent(int indent) {
+        if (indent < 0) {
+            this.indent = 0;
+        } else {
+            this.indent = indent;
+        }
+    }
+
+    /**
+     * Select the radio button that conforms to the given value.
+     *
+     * @param selectedValue the selected value
+     */
+    private void updateValue(String selectedValue) {
+        this.value = selectedValue;
+        if (radioButtons == null) {
+            return;
+        }
+
+        if (this.value != null) {
+            boolean found = false;
+            for (int i = 0; i < radioButtons.length; i++) {
+                Button radio = radioButtons[i];
+                boolean selection = false;
+                if (((String) radio.getData()).equals(this.value)) {
+                    selection = true;
+                    found = true;
+                }
+                radio.setSelection(selection);
+            }
+            if (found) {
+                return;
+            }
+        }
+
+        // We weren't able to find the value. So we select the first
+        // radio button as a default.
+        if (radioButtons.length > 0) {
+            radioButtons[0].setSelection(true);
+            this.value = (String) radioButtons[0].getData();
+        }
+        return;
+    }
+
+    /*
+     * @see FieldEditor.setEnabled(boolean,Composite).
+     */
+    @Override
+    public void setEnabled(boolean enabled, Composite parent) {
+        if (!useGroup) {
+            super.setEnabled(enabled, parent);
+        }
+        for (int i = 0; i < radioButtons.length; i++) {
+            radioButtons[i].setEnabled(enabled);
+        }
+
+    }
+
+    public String getRadioValue() {
+        return value;
+    }
+
+    public void updateRadioForValue(String value) {
+        updateValue(value);
+    }
+}
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedFieldEditorPreferencePage.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedFieldEditorPreferencePage.java
new file mode 100644
index 0000000..840696a
--- /dev/null
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedFieldEditorPreferencePage.java
@@ -0,0 +1,303 @@
+package org.python.pydev.shared_ui.field_editors;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.widgets.Button;
+import org.python.pydev.shared_core.log.Log;
+import org.python.pydev.shared_core.preferences.IScopedPreferences;
+import org.python.pydev.shared_core.string.StringUtils;
+import org.python.pydev.shared_core.structure.Tuple;
+import org.python.pydev.shared_core.utils.Reflection;
+import org.python.pydev.shared_ui.EditorUtils;
+import org.python.pydev.shared_ui.SharedUiPlugin;
+import org.python.pydev.shared_ui.dialogs.DialogHelpers;
+
+public abstract class ScopedFieldEditorPreferencePage extends FieldEditorPreferencePage {
+
+    private List<FieldEditor> fields;
+
+    public ScopedFieldEditorPreferencePage(int style) {
+        super(style);
+    }
+
+    public ScopedFieldEditorPreferencePage(String title, int style) {
+        super(title, style);
+    }
+
+    @Override
+    protected void addField(FieldEditor editor) {
+        super.addField(editor);
+        if (fields == null) {
+            fields = new ArrayList<FieldEditor>();
+        }
+        fields.add(editor);
+    }
+
+    public void saveToUserSettings(IScopedPreferences iScopedPreferences) {
+        Map<String, Object> saveData = getFieldEditorsSaveData();
+        if (saveData.size() > 0) {
+            try {
+                String message = iScopedPreferences.saveToUserSettings(saveData);
+                DialogHelpers.openInfo("Results", message);
+            } catch (Exception e) {
+                Log.log(e);
+                ErrorDialog.openError(EditorUtils.getShell(),
+                        "Error: unable to save requested settings to user settings",
+                        e.getMessage(),
+                        SharedUiPlugin.makeErrorStatus(e, false));
+            }
+        } else {
+            // This shouldn't happen
+            DialogHelpers.openCritical("Error: No preferences to save",
+                    "Error: No preferences to save (please report this as an error).");
+        }
+    }
+
+    public void loadFromUserSettings(IScopedPreferences iScopedPreferences) {
+        Map<String, Object> saveData = getFieldEditorsSaveData();
+        if (saveData.size() > 0) {
+            try {
+                Tuple<Map<String, Object>, Set<String>> loadedFromUserSettings = iScopedPreferences
+                        .loadFromUserSettings(saveData);
+
+                updateFieldEditorsData(loadedFromUserSettings.o1);
+
+                if (loadedFromUserSettings.o1.size() == 0) {
+                    DialogHelpers.openInfo("No saved preferences",
+                            "Unable to load any contents from the user settings.");
+
+                } else if (loadedFromUserSettings.o2.size() > 0) {
+                    DialogHelpers.openInfo("Partially loaded contents",
+                            "Partially loaded contents. Did not find the keys below in the user settings:\n  "
+                                    + StringUtils.join("\n  ", loadedFromUserSettings.o2));
+
+                } else {
+                    DialogHelpers.openInfo("Loaded contents", "Showing contents loaded from user settings.");
+
+                }
+            } catch (Exception e) {
+                Log.log(e);
+                ErrorDialog.openError(EditorUtils.getShell(),
+                        "Error: unable to load requested settings from user settings",
+                        e.getMessage(),
+                        SharedUiPlugin.makeErrorStatus(e, false));
+            }
+        } else {
+            // This shouldn't happen
+            DialogHelpers.openCritical("Error: No preferences to load",
+                    "Error: No preferences to load (please report this as an error).");
+        }
+    }
+
+    public void loadFromProjectSettings(IScopedPreferences iScopedPreferences, IProject project) {
+        Map<String, Object> saveData = getFieldEditorsSaveData();
+        if (saveData.size() > 0) {
+            try {
+                Tuple<Map<String, Object>, Set<String>> loadedFromUserSettings = iScopedPreferences
+                        .loadFromProjectSettings(saveData, project);
+
+                updateFieldEditorsData(loadedFromUserSettings.o1);
+
+                if (loadedFromUserSettings.o1.size() == 0) {
+                    DialogHelpers.openInfo("No saved preferences",
+                            "Unable to load any contents from the settings for the project: " + project.getName());
+
+                } else if (loadedFromUserSettings.o2.size() > 0) {
+                    DialogHelpers.openInfo("Partially loaded contents",
+                            "Partially loaded contents. Did not find the keys below in the settings for the project "
+                                    + project.getName() + ":\n  "
+                                    + StringUtils.join("\n  ", loadedFromUserSettings.o2));
+
+                } else {
+                    DialogHelpers.openInfo("Loaded contents", "Showing contents loaded from settings in project: "
+                            + project.getName());
+
+                }
+            } catch (Exception e) {
+                Log.log(e);
+                ErrorDialog.openError(EditorUtils.getShell(),
+                        "Error: unable to load requested settings from settings in project: " + project.getName(),
+                        e.getMessage(),
+                        SharedUiPlugin.makeErrorStatus(e, false));
+            }
+        } else {
+            // This shouldn't happen
+            DialogHelpers.openCritical("Error: No preferences to load",
+                    "Error: No preferences to load (please report this as an error).");
+        }
+    }
+
+    private void updateFieldEditorsData(Map<String, Object> loadData) throws IllegalArgumentException,
+            IllegalAccessException {
+        if (fields != null) {
+            Iterator<FieldEditor> e = fields.iterator();
+            while (e.hasNext()) {
+                FieldEditor pe = e.next();
+                if (pe instanceof BooleanFieldEditor) {
+                    BooleanFieldEditor booleanFieldEditor = (BooleanFieldEditor) pe;
+                    String preferenceName = booleanFieldEditor.getPreferenceName();
+                    Boolean value = (Boolean) loadData.get(preferenceName);
+                    if (value == null) {
+                        continue;
+                    }
+
+                    // Hack because the BooleanFieldEditor does not have a way to set the value in the view!
+                    Field field = Reflection.getAttrFromClass(BooleanFieldEditor.class, "checkBox");
+                    field.setAccessible(true);
+                    Button checkbox = (Button) field.get(booleanFieldEditor);
+                    checkbox.setSelection(value);
+
+                } else if (pe instanceof IntegerFieldEditor) { //IntegerFieldEditor is a subclass of StringFieldEditor (so, must come before)
+                    IntegerFieldEditor intFieldEditor = (IntegerFieldEditor) pe;
+                    String preferenceName = intFieldEditor.getPreferenceName();
+                    Object loaded = loadData.get(preferenceName);
+                    if (loaded == null) {
+                        continue;
+                    }
+                    if (loaded instanceof Integer) {
+                        Integer value = (Integer) loaded;
+                        intFieldEditor.setStringValue(Integer.toString(value));
+                    } else {
+                        intFieldEditor.setStringValue(loaded.toString());
+                    }
+
+                } else if (pe instanceof StringFieldEditor) { //IntegerFieldEditor is a subclass
+                    StringFieldEditor stringFieldEditor = (StringFieldEditor) pe;
+                    String preferenceName = stringFieldEditor.getPreferenceName();
+                    String value = (String) loadData.get(preferenceName);
+                    if (value == null) {
+                        continue;
+                    }
+                    stringFieldEditor.setStringValue(value);
+
+                } else if (pe instanceof ComboFieldEditor) {
+                    ComboFieldEditor comboFieldEditor = (ComboFieldEditor) pe;
+                    String preferenceName = comboFieldEditor.getPreferenceName();
+                    String value = (String) loadData.get(preferenceName);
+                    if (value == null) {
+                        continue;
+                    }
+                    comboFieldEditor.updateComboForValue(value);
+
+                } else if (pe instanceof RadioGroupFieldEditor) {
+                    RadioGroupFieldEditor radioGroupFieldEditor = (RadioGroupFieldEditor) pe;
+                    String preferenceName = radioGroupFieldEditor.getPreferenceName();
+                    String value = (String) loadData.get(preferenceName);
+                    if (value == null) {
+                        continue;
+                    }
+                    radioGroupFieldEditor.updateRadioForValue(value);
+
+                } else if (pe instanceof ScopedPreferencesFieldEditor || pe instanceof LinkFieldEditor
+                        || pe instanceof LabelFieldEditor) {
+                    // Ignore these ones
+
+                } else {
+                    Log.log("Unhandled field editor:" + pe);
+                }
+            }
+        }
+
+    }
+
+    public Map<String, Object> getFieldEditorsSaveData() {
+        Map<String, Object> saveData = new HashMap<>();
+        if (fields != null) {
+            Iterator<FieldEditor> e = fields.iterator();
+            while (e.hasNext()) {
+                FieldEditor pe = e.next();
+                if (pe instanceof BooleanFieldEditor) {
+                    BooleanFieldEditor booleanFieldEditor = (BooleanFieldEditor) pe;
+                    boolean booleanValue = booleanFieldEditor.getBooleanValue();
+                    String preferenceName = booleanFieldEditor.getPreferenceName();
+                    saveData.put(preferenceName, booleanValue);
+
+                } else if (pe instanceof IntegerFieldEditor) { //IntegerFieldEditor is a subclass of StringFieldEditor, so, must come first
+                    IntegerFieldEditor intFieldEditor = (IntegerFieldEditor) pe;
+                    String stringValue = intFieldEditor.getStringValue();
+                    String preferenceName = intFieldEditor.getPreferenceName();
+                    try {
+                        saveData.put(preferenceName, Integer.parseInt(stringValue));
+                    } catch (Exception e1) {
+                        saveData.put(preferenceName, 0);
+                    }
+
+                } else if (pe instanceof StringFieldEditor) { //IntegerFieldEditor is a subclass
+                    StringFieldEditor stringFieldEditor = (StringFieldEditor) pe;
+                    String stringValue = stringFieldEditor.getStringValue();
+                    String preferenceName = stringFieldEditor.getPreferenceName();
+                    saveData.put(preferenceName, stringValue);
+
+                } else if (pe instanceof ComboFieldEditor) {
+                    ComboFieldEditor comboFieldEditor = (ComboFieldEditor) pe;
+                    String stringValue = comboFieldEditor.getComboValue();
+                    String preferenceName = comboFieldEditor.getPreferenceName();
+                    saveData.put(preferenceName, stringValue);
+
+                } else if (pe instanceof RadioGroupFieldEditor) {
+                    RadioGroupFieldEditor radioGroupFieldEditor = (RadioGroupFieldEditor) pe;
+                    String stringValue = radioGroupFieldEditor.getRadioValue();
+                    String preferenceName = radioGroupFieldEditor.getPreferenceName();
+                    saveData.put(preferenceName, stringValue);
+
+                } else if (pe instanceof ScopedPreferencesFieldEditor || pe instanceof LinkFieldEditor
+                        || pe instanceof LabelFieldEditor) {
+                    // Ignore these ones
+
+                } else {
+                    Log.log("Unhandled field editor:" + pe);
+                }
+            }
+        }
+        return saveData;
+    }
+
+    public void saveToProjectSettings(IScopedPreferences iScopedPreferences, IProject[] projects) {
+        Map<String, Object> saveData = getFieldEditorsSaveData();
+        if (saveData.size() > 0) {
+            try {
+                String message = iScopedPreferences.saveToProjectSettings(saveData, projects);
+                DialogHelpers.openInfo("Contents saved", message);
+            } catch (Exception e) {
+                Log.log(e);
+                ErrorDialog.openError(EditorUtils.getShell(),
+                        "Error: unable to save requested settings to user settings",
+                        e.getMessage(),
+                        SharedUiPlugin.makeErrorStatus(e, false));
+            }
+        } else {
+            // This shouldn't happen
+            DialogHelpers.openCritical("Error: No preferences to save",
+                    "Error: No preferences to save (please report this as an error).");
+        }
+
+    }
+
+    public void saveToWorkspace() {
+        super.performApply();
+    }
+
+    public void loadFromWorkspace() {
+        if (fields != null) {
+            Iterator<FieldEditor> e = fields.iterator();
+            while (e.hasNext()) {
+                FieldEditor pe = e.next();
+                pe.load();
+            }
+        }
+    }
+
+}
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedPreferencesFieldEditor.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedPreferencesFieldEditor.java
new file mode 100644
index 0000000..dc58543
--- /dev/null
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/field_editors/ScopedPreferencesFieldEditor.java
@@ -0,0 +1,325 @@
+package org.python.pydev.shared_ui.field_editors;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.python.pydev.shared_core.preferences.IScopedPreferences;
+import org.python.pydev.shared_core.preferences.ScopedPreferences;
+import org.python.pydev.shared_core.structure.Tuple;
+import org.python.pydev.shared_ui.EditorUtils;
+import org.python.pydev.shared_ui.dialogs.ProjectSelectionDialog;
+
+public class ScopedPreferencesFieldEditor extends FieldEditor {
+
+    private Composite toolBar;
+    private IScopedPreferences iScopedPreferences;
+    private WeakReference<ScopedFieldEditorPreferencePage> preferencesPage;
+    private Label showingFrom;
+
+    /**
+     * @param name the name of the property
+     * @param linkText the text that'll appear to the user
+     * @param parent the parent composite
+     * @param selectionListener a listener that'll be executed when the linked text is clicked
+     */
+    public ScopedPreferencesFieldEditor(Composite parent, String pluginName,
+            ScopedFieldEditorPreferencePage preferencesPage) {
+        init("__UNUSED__", "Some text");
+        createControl(parent);
+        iScopedPreferences = ScopedPreferences.get(pluginName);
+        this.preferencesPage = new WeakReference<ScopedFieldEditorPreferencePage>(preferencesPage);
+    }
+
+    @Override
+    protected void adjustForNumColumns(int numColumns) {
+        GridData gd = (GridData) toolBar.getLayoutData();
+        gd.horizontalSpan = numColumns;
+    }
+
+    @Override
+    protected void doFillIntoGrid(Composite parent, int numColumns) {
+        toolBar = new Composite(parent, SWT.NONE);
+        toolBar.setLayout(new GridLayout(3, true));
+
+        final Button bt = getButtonControl(toolBar, "Save to ...");
+        bt.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Menu menu = new Menu(bt);
+
+                MenuItem item1 = new MenuItem(menu, SWT.PUSH);
+                item1.setText("User settings");
+                item1.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        preferencesPage.get().saveToUserSettings(iScopedPreferences);
+                    }
+                });
+
+                MenuItem item2 = new MenuItem(menu, SWT.PUSH);
+                item2.setText("Project settings ...");
+                item2.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        ProjectSelectionDialog dialog = new ProjectSelectionDialog(EditorUtils.getShell(), null, true);
+                        dialog.labelProvider = createProjectsLabelProvider();
+                        dialog.setMessage("Choose the projects to which the preferences should be applied.\n"
+                                + createDecorationLabel());
+                        if (dialog.open() == Window.OK) {
+                            Object[] result = dialog.getResult();
+                            IProject[] projects = new IProject[result.length];
+                            for (int i = 0; i < result.length; i++) {
+                                projects[i] = (IProject) result[i];
+                            }
+                            preferencesPage.get().saveToProjectSettings(iScopedPreferences, projects);
+                        }
+                    }
+                });
+
+                MenuItem item3 = new MenuItem(menu, SWT.PUSH);
+                item3.setText("Workspace");
+                item3.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        preferencesPage.get().saveToWorkspace();
+                    }
+                });
+
+                Point loc = bt.getLocation();
+                Rectangle rect = bt.getBounds();
+
+                Point mLoc = new Point(loc.x, loc.y + rect.height);
+
+                menu.setLocation(bt.getShell().getDisplay().map(bt.getParent(), null, mLoc));
+
+                menu.setVisible(true);
+            }
+        });
+
+        final Button bt2 = getButtonControl(toolBar, "Show from ...");
+        bt2.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Menu menu = new Menu(bt2);
+
+                MenuItem item1 = new MenuItem(menu, SWT.PUSH);
+                item1.setText("User settings");
+                item1.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        preferencesPage.get().loadFromUserSettings(iScopedPreferences);
+                        showingFrom.setText("Showing from: User Settings");
+                    }
+                });
+
+                MenuItem item2 = new MenuItem(menu, SWT.PUSH);
+                item2.setText("Project settings ...");
+                item2.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        ProjectSelectionDialog dialog = new ProjectSelectionDialog(EditorUtils.getShell(), null, false);
+                        dialog.labelProvider = createProjectsLabelProvider();
+                        dialog.setMessage("Choose the project from which the preferences should be shown.\n"
+                                + createDecorationLabel());
+                        if (dialog.open() == Window.OK) {
+                            IProject project = (IProject) dialog.getFirstResult();
+                            preferencesPage.get().loadFromProjectSettings(iScopedPreferences, project);
+                            showingFrom.setText("Showing from: " + project.getName());
+                        }
+                    }
+                });
+
+                MenuItem item3 = new MenuItem(menu, SWT.PUSH);
+                item3.setText("Workspace");
+                item3.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        preferencesPage.get().loadFromWorkspace();
+                        showingFrom.setText("Showing from: Workspace");
+                    }
+                });
+
+                Point loc = bt2.getLocation();
+                Rectangle rect = bt2.getBounds();
+
+                Point mLoc = new Point(loc.x, loc.y + rect.height);
+
+                menu.setLocation(bt2.getShell().getDisplay().map(bt2.getParent(), null, mLoc));
+
+                menu.setVisible(true);
+            }
+        });
+
+        final Button bt3 = getButtonControl(toolBar, "Open location ...");
+        bt3.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Menu menu = new Menu(bt3);
+
+                MenuItem item1 = new MenuItem(menu, SWT.PUSH);
+                final File userSettingsLocation = iScopedPreferences.getUserSettingsLocation();
+                item1.setText("User settings: " + userSettingsLocation);
+                item1.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        EditorUtils.openFile(userSettingsLocation);
+                    }
+                });
+
+                MenuItem item2 = new MenuItem(menu, SWT.PUSH);
+                item2.setText("Project settings ...");
+                item2.addSelectionListener(new SelectionAdapter() {
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        ProjectSelectionDialog dialog = new ProjectSelectionDialog(EditorUtils.getShell(), null, true);
+                        dialog.labelProvider = createProjectsLabelProvider();
+                        dialog.setMessage("Choose the projects from which the preference files should be opened.\n"
+                                + createDecorationLabel());
+                        if (dialog.open() == Window.OK) {
+                            for (Object o : dialog.getResult()) {
+                                IProject p = (IProject) o;
+                                IFile projectSettingsLocation = iScopedPreferences.getProjectSettingsLocation(p);
+                                EditorUtils.openFile(projectSettingsLocation);
+                            }
+                        }
+                    }
+
+                });
+
+                Point loc = bt3.getLocation();
+                Rectangle rect = bt3.getBounds();
+
+                Point mLoc = new Point(loc.x, loc.y + rect.height);
+
+                menu.setLocation(bt3.getShell().getDisplay().map(bt3.getParent(), null, mLoc));
+
+                menu.setVisible(true);
+            }
+        });
+
+        GridData gd = createFillGridData();
+        gd.horizontalSpan = numColumns;
+        toolBar.setLayoutData(gd);
+
+        showingFrom = new Label(parent, SWT.NONE);
+        showingFrom.setText("Showing from: Workspace");
+
+    }
+
+    private GridData createFillGridData() {
+        GridData gd = new GridData();
+        gd.horizontalAlignment = GridData.FILL;
+        gd.grabExcessHorizontalSpace = true;
+        return gd;
+    }
+
+    private String createDecorationLabel() {
+        return "Legend:\n  *   project has all settings in this page\n  +   project has some settings in this page\n  ?  project has settings with errors";
+    }
+
+    private IBaseLabelProvider createProjectsLabelProvider() {
+        return new WorkbenchLabelProvider() {
+
+            private Map<Object, String> elementToDecorationCache = new HashMap<Object, String>();
+
+            @Override
+            protected String decorateText(String input, Object element) {
+                String ret = super.decorateText(input, element);
+                String decoration = getDecoration(element);
+                ret += (" " + decoration);
+                return ret;
+            }
+
+            private String getDecoration(Object element) {
+                String ret = elementToDecorationCache.get(element);
+                if (ret != null) {
+                    return ret;
+                }
+                ScopedFieldEditorPreferencePage preferencePage = preferencesPage.get();
+                Map<String, Object> saveData = preferencePage.getFieldEditorsSaveData();
+
+                String decoration;
+                try {
+                    Tuple<Map<String, Object>, Set<String>> loadFromProjectSettings = iScopedPreferences
+                            .loadFromProjectSettings(saveData, (IProject) element);
+                    if (loadFromProjectSettings.o1.size() == 0) {
+                        decoration = "";
+                    } else {
+                        if (loadFromProjectSettings.o2.size() == 0) {
+                            decoration = "*";
+                        } else {
+                            decoration = "+";
+                        }
+                    }
+                } catch (Exception e) {
+                    decoration = "?";
+                }
+                elementToDecorationCache.put(element, ret);
+                return decoration;
+            }
+        };
+    }
+
+    /**
+     * Returns this field editor's link component.
+     * <p>
+     * The link is created if it does not already exist
+     * </p>
+     *
+     * @param parent the parent
+     * @return the label control
+     */
+    private Button getButtonControl(Composite parent, String text) {
+        Button button = new Button(parent, SWT.PUSH);
+        button.setText(text);
+        button.setFont(parent.getFont());
+
+        GridData gd = createFillGridData();
+        button.setLayoutData(gd);
+        return button;
+    }
+
+    @Override
+    protected void doLoad() {
+    }
+
+    @Override
+    protected void doLoadDefault() {
+    }
+
+    @Override
+    protected void doStore() {
+    }
+
+    @Override
+    public int getNumberOfControls() {
+        return 1;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled, Composite parent) {
+        //super.setEnabled(enabled, parent); -- don't call super!
+        toolBar.setEnabled(enabled);
+    }
+}
diff --git a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/utils/UIUtils.java b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/utils/UIUtils.java
index 9dfbb83..a461084 100644
--- a/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/utils/UIUtils.java
+++ b/plugins/org.python.pydev.shared_ui/src/org/python/pydev/shared_ui/utils/UIUtils.java
@@ -10,6 +10,7 @@ import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchWindow;
@@ -35,7 +36,14 @@ public class UIUtils {
     }
 
     public static IWorkbenchWindow getActiveWorkbenchWindow() {
-        return PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+        if (!PlatformUI.isWorkbenchRunning()) {
+            return null;
+        }
+        IWorkbench workbench = PlatformUI.getWorkbench();
+        if (workbench == null) {
+            return null;
+        }
+        return workbench.getActiveWorkbenchWindow();
     }
 
     public static IEditorPart getActiveEditor() {
diff --git a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapOverviewRuler.java b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapOverviewRuler.java
index d996465..fbb36ec 100644
--- a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapOverviewRuler.java
+++ b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapOverviewRuler.java
@@ -318,6 +318,10 @@ public class MinimapOverviewRuler extends CopiedOverviewRuler {
             List<Parameters> stackedParametersClone;
 
             synchronized (lockStackedParameters) {
+                if (stackedParameters.empty()) {
+                    //Not much to do in this case...
+                    return Status.OK_STATUS;
+                }
                 parameters = stackedParameters.pop();
                 stackedParametersClone = fetchStackedParameters();
             }
diff --git a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapPreferenceInitializer.java b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapPreferenceInitializer.java
index 04349b0..641a1a0 100644
--- a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapPreferenceInitializer.java
+++ b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/MinimapPreferenceInitializer.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/StyledTextWithoutVerticalBar.java b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/StyledTextWithoutVerticalBar.java
index e4ac292..5660d19 100644
--- a/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/StyledTextWithoutVerticalBar.java
+++ b/plugins/org.python.pydev.shared_ui/src_overview_ruler/org/python/pydev/overview_ruler/StyledTextWithoutVerticalBar.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev.shared_ui/win32/listtasks.exe b/plugins/org.python.pydev.shared_ui/win32/listtasks.exe
deleted file mode 100644
index a31d3b2..0000000
Binary files a/plugins/org.python.pydev.shared_ui/win32/listtasks.exe and /dev/null differ
diff --git a/plugins/org.python.pydev/META-INF/MANIFEST.MF b/plugins/org.python.pydev/META-INF/MANIFEST.MF
index 0f858cb..8d087b4 100644
--- a/plugins/org.python.pydev/META-INF/MANIFEST.MF
+++ b/plugins/org.python.pydev/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: PyDev - Python Development Environment
 Bundle-SymbolicName: org.python.pydev; singleton:=true
-Bundle-Version: 3.9.0.qualifier
+Bundle-Version: 3.9.2.qualifier
 Bundle-ClassPath: pydev.jar,
  libs/WinRegistry-4.5.jar
 Bundle-Activator: org.python.pydev.plugin.PydevPlugin
diff --git a/plugins/org.python.pydev/icons/python_file.gif b/plugins/org.python.pydev/icons/python_file.gif
index eb6e0b6..248eb74 100644
Binary files a/plugins/org.python.pydev/icons/python_file.gif and b/plugins/org.python.pydev/icons/python_file.gif differ
diff --git a/plugins/org.python.pydev/plugin.xml b/plugins/org.python.pydev/plugin.xml
index ed2dfce..c9b3d99 100644
--- a/plugins/org.python.pydev/plugin.xml
+++ b/plugins/org.python.pydev/plugin.xml
@@ -286,6 +286,9 @@
 	<extension point="org.eclipse.ui.keywords" name="Typing">
 	    <keyword id="org.python.pydev.typing"  label="indentation new line parentheses"/>
 	</extension>
+	<extension point="org.eclipse.ui.keywords" name="Tabs">
+	    <keyword id="org.python.pydev.tabs"  label="tabs indentation"/>
+	</extension>
 	<extension point="org.eclipse.ui.keywords" name="Minimap">
 	    <keyword id="org.python.pydev.minimap"  label="minimap horizontal vertical scrollbar ruler birds"/>
 	</extension>
@@ -331,6 +334,13 @@
             <keywordReference id="org.python.pydev.typing"/>
       </page>
       <page
+            name="Tabs"
+            category="org.python.pydev.prefs.editor"
+            class="org.python.pydev.editor.preferences.PyTabPreferencesPage"
+            id="org.python.pydev.editor.preferences.PyTabPreferencesPage">
+            <keywordReference id="org.python.pydev.tabs"/>
+      </page>
+      <page
             name="Interpreters"
             category="org.python.pydev.prefs"
             class="org.python.pydev.ui.pythonpathconf.InterpreterGeneralPreferencesPage"
@@ -960,6 +970,7 @@
             commandId="org.python.pydev.editor.actions.navigation.nextMethod"
             schemeId="org.eclipse.ui.defaultAcceleratorConfiguration">
       </key>
+      <!-- Note: bound in pyedit_exec_line_in_shell.py -->
       <key
             sequence="F2"
             contextId="org.python.pydev.ui.editor.scope"
@@ -1537,7 +1548,7 @@
 	  	  id="org.python.pydev.navigator.filters.hidePyTildaFiles"
 	  	  class="org.python.pydev.navigator.filters.PyTildaFilter">
 	  </commonFilter>
-	  
+
   	  <commonFilter activeByDefault="true"
 	  	  name="PyDev: __pycache__"
 	  	  description="PyDev: __pycache__ folders"
diff --git a/plugins/org.python.pydev/pom.xml b/plugins/org.python.pydev/pom.xml
index b4c8731..a76931b 100644
--- a/plugins/org.python.pydev/pom.xml
+++ b/plugins/org.python.pydev/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>plugins</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.python.pydev</groupId>
diff --git a/plugins/org.python.pydev/pysrc/_pydev_imps/_pydev_pluginbase.py b/plugins/org.python.pydev/pysrc/_pydev_imps/_pydev_pluginbase.py
index ed4203f..ccf2c08 100644
--- a/plugins/org.python.pydev/pysrc/_pydev_imps/_pydev_pluginbase.py
+++ b/plugins/org.python.pydev/pysrc/_pydev_imps/_pydev_pluginbase.py
@@ -14,7 +14,6 @@ import sys
 
 from pydevd_constants import IS_PY24, IS_PY3K, IS_JYTHON
 
-
 if IS_PY24:
     from _pydev_imps._pydev_uuid_old import uuid4
 else:
@@ -96,7 +95,11 @@ def _discover_space(name, globals):
     if '__pluginbase_state__' in globals:
         return globals['__pluginbase_state__'].source
 
-    mod_name = globals.get('__name__')
+    mod_name = None
+    if globals:
+        # in unidecode package they pass [] as globals arg
+        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)
@@ -394,63 +397,3 @@ class PluginBaseState(object):
         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
-        if IS_JYTHON:
-            import_name = name
-        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/plugins/org.python.pydev/pysrc/_pydev_threading.py b/plugins/org.python.pydev/pysrc/_pydev_threading.py
index e9fad51..3dd47f6 100644
--- a/plugins/org.python.pydev/pysrc/_pydev_threading.py
+++ b/plugins/org.python.pydev/pysrc/_pydev_threading.py
@@ -1,11 +1,15 @@
 from threading import * # Make up for things we may forget @UnusedWildImport
 
 # Force what we know we need
-from threading import enumerate, currentThread, Condition, Event, Timer, Thread, Lock
+from threading import enumerate, currentThread, Condition, Event, Thread, Lock
 try:
     from threading import settrace
 except:
     pass
+try:
+    from threading import Timer
+except:
+    pass # Jython 2.1
 
 
 try:
diff --git a/plugins/org.python.pydev/pysrc/interpreterInfo.py b/plugins/org.python.pydev/pysrc/interpreterInfo.py
index 103253e..6abb8ac 100644
--- a/plugins/org.python.pydev/pysrc/interpreterInfo.py
+++ b/plugins/org.python.pydev/pysrc/interpreterInfo.py
@@ -63,6 +63,7 @@ if sys.platform == "cygwin":
 
         retval = ctypes.create_string_buffer(MAX_PATH)
         path = fullyNormalizePath(path)
+        path = tobytes(path)
         CCP_POSIX_TO_WIN_A = 0
         ctypes.cdll.cygwin1.cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, retval, MAX_PATH)
         
@@ -115,15 +116,26 @@ def getfilesystemencoding():
     
 file_system_encoding = getfilesystemencoding()
 
+if IS_PYTHON_3K:
+    unicode_type = str
+    bytes_type = bytes
+    
+else:
+    unicode_type = unicode
+    bytes_type = str
+    
+
 def tounicode(s):
     if hasattr(s, 'decode'):
-        # Depending on the platform variant we may have decode on string or not.
-        return s.decode(file_system_encoding)
+        if not isinstance(s, unicode_type):
+            # Depending on the platform variant we may have decode on string or not.
+            return s.decode(file_system_encoding)
     return s
 
-def toutf8(s):
+def tobytes(s):
     if hasattr(s, 'encode'):
-        return s.encode('utf-8')
+        if not isinstance(s, bytes_type):
+            return s.encode(file_system_encoding)
     return s
 
 def toasciimxl(s):
@@ -160,12 +172,12 @@ if __name__ == '__main__':
         pass
 
     try:
-        executable = nativePath(sys.executable)
+        executable = tounicode(nativePath(sys.executable))
     except:
-        executable = sys.executable
+        executable = tounicode(sys.executable)
 
-    if sys.platform == "cygwin" and not executable.endswith('.exe'):
-        executable += '.exe'
+    if sys.platform == "cygwin" and not executable.endswith(tounicode('.exe')):
+        executable += tounicode('.exe')
 
 
     try:
diff --git a/plugins/org.python.pydev/pysrc/pydev_console_utils.py b/plugins/org.python.pydev/pysrc/pydev_console_utils.py
index 6e53218..bfab1d0 100644
--- a/plugins/org.python.pydev/pysrc/pydev_console_utils.py
+++ b/plugins/org.python.pydev/pysrc/pydev_console_utils.py
@@ -129,6 +129,13 @@ class BaseInterpreterInterface:
         self.buffer = None
 
     def needMoreForCode(self, source):
+        # PyDev-502: PyDev 3.9 F2 doesn't support backslash continuations
+
+        # Strangely even the IPython console is_complete said it was complete
+        # even with a continuation char at the end.
+        if source.endswith('\\'):
+            return True
+
         if hasattr(self.interpreter, 'is_complete'):
             return not self.interpreter.is_complete(source)
         try:
@@ -330,10 +337,45 @@ class BaseInterpreterInterface:
         self.buffer = None # Also clear the buffer when it's interrupted.
         try:
             if self.interruptable:
-                if hasattr(thread, 'interrupt_main'): #Jython doesn't have it
-                    thread.interrupt_main()
-                else:
-                    self.mainThread._thread.interrupt() #Jython
+                called = False
+                try:
+                    # Fix for #PyDev-500: Console interrupt can't interrupt on sleep
+                    import os
+                    import signal
+                    if os.name == 'posix':
+                        # On Linux we can't interrupt 0 as in Windows because it's
+                        # actually owned by a process -- on the good side, signals
+                        # work much better on Linux!
+                        os.kill(os.getpid(), signal.SIGINT)
+                        called = True
+
+                    elif os.name == 'nt':
+                        # Stupid windows: sending a Ctrl+C to a process given its pid
+                        # is absurdly difficult.
+                        # There are utilities to make it work such as
+                        # http://www.latenighthacking.com/projects/2003/sendSignal/
+                        # but fortunately for us, it seems Python does allow a CTRL_C_EVENT
+                        # for the current process in Windows if pid 0 is passed... if we needed
+                        # to send a signal to another process the approach would be
+                        # much more difficult.
+                        # Still, note that CTRL_C_EVENT is only Python 2.7 onwards...
+                        # Also, this doesn't seem to be documented anywhere!? (stumbled
+                        # upon it by chance after digging quite a lot).
+                        os.kill(0, signal.CTRL_C_EVENT)
+                        called = True
+                except:
+                    # Many things to go wrong (from CTRL_C_EVENT not being there
+                    # to failing import signal)... if that's the case, ask for
+                    # forgiveness and go on to the approach which will interrupt
+                    # the main thread (but it'll only work when it's executing some Python
+                    # code -- not on sleep() for instance).
+                    pass
+
+                if not called:
+                    if hasattr(thread, 'interrupt_main'): #Jython doesn't have it
+                        thread.interrupt_main()
+                    else:
+                        self.mainThread._thread.interrupt() #Jython
             return True
         except:
             traceback.print_exc()
@@ -385,6 +427,32 @@ class BaseInterpreterInterface:
 
         return xml
 
+    def getArray(self, attr, roffset, coffset, rows, cols, format):
+        xml = "<xml>"
+        name = attr.split("\t")[-1]
+        array = pydevd_vars.evalInContext(name, self.getNamespace(), self.getNamespace())
+
+        array, metaxml, r, c, f = pydevd_vars.array_to_meta_xml(array, name, format)
+        xml += metaxml
+        format = '%' + f
+        if rows == -1 and cols == -1:
+            rows = r
+            cols = c
+        xml += pydevd_vars.array_to_xml(array, roffset, coffset, rows, cols, format)
+        xml += "</xml>"
+
+        return xml
+
+    def evaluate(self, expression):
+        xml = "<xml>"
+        result = pydevd_vars.evalInContext(expression, self.getNamespace(), self.getNamespace())
+
+        xml += pydevd_vars.varToXML(result, expression)
+
+        xml += "</xml>"
+
+        return xml
+
     def changeVariable(self, attr, value):
         def do_change_variable():
             Exec('%s=%s' % (attr, value), self.getNamespace(), self.getNamespace())
diff --git a/plugins/org.python.pydev/pysrc/pydev_import_hook.py b/plugins/org.python.pydev/pysrc/pydev_import_hook.py
new file mode 100644
index 0000000..a1c04f7
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydev_import_hook.py
@@ -0,0 +1,37 @@
+
+import sys
+from pydevd_constants import DictContains
+from types import ModuleType
+
+
+class ImportHookManager(ModuleType):
+    def __init__(self, name, system_import):
+        ModuleType.__init__(self, name)
+        self._system_import = system_import
+        self._modules_to_patch = {}
+
+    def add_module_name(self, module_name, activate_function):
+        self._modules_to_patch[module_name] = activate_function
+
+    def do_import(self, name, *args, **kwargs):
+        activate_func = None
+        if DictContains(self._modules_to_patch, name):
+            activate_func = self._modules_to_patch.pop(name)
+
+        module = self._system_import(name, *args, **kwargs)
+        try:
+            if activate_func:
+                activate_func() #call activate function
+        except:
+            sys.stderr.write("Matplotlib support failed")
+        return module
+
+try:
+    import __builtin__ as builtins
+except ImportError:
+    import builtins
+
+import_hook_manager = ImportHookManager(__name__ + '.import_hook', builtins.__import__)
+builtins.__import__ = import_hook_manager.do_import
+sys.modules[import_hook_manager.__name__] = import_hook_manager
+del builtins
\ No newline at end of file
diff --git a/plugins/org.python.pydev/pysrc/pydev_ipython/matplotlibtools.py b/plugins/org.python.pydev/pysrc/pydev_ipython/matplotlibtools.py
new file mode 100644
index 0000000..31a7f06
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydev_ipython/matplotlibtools.py
@@ -0,0 +1,130 @@
+
+import sys
+
+backends = {'tk': 'TkAgg',
+            'gtk': 'GTKAgg',
+            'wx': 'WXAgg',
+            'qt': 'Qt4Agg', # qt3 not supported
+            'qt4': 'Qt4Agg',
+            'osx': 'MacOSX'}
+
+# We also need a reverse backends2guis mapping that will properly choose which
+# GUI support to activate based on the desired matplotlib backend.  For the
+# most part it's just a reverse of the above dict, but we also need to add a
+# few others that map to the same GUI manually:
+backend2gui = dict(zip(backends.values(), backends.keys()))
+backend2gui['Qt4Agg'] = 'qt'
+# In the reverse mapping, there are a few extra valid matplotlib backends that
+# map to the same GUI support
+backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
+backend2gui['WX'] = 'wx'
+backend2gui['CocoaAgg'] = 'osx'
+
+
+def find_gui_and_backend():
+    """Return the gui and mpl backend."""
+    matplotlib = sys.modules['matplotlib']
+    # WARNING: this assumes matplotlib 1.1 or newer!!
+    backend = matplotlib.rcParams['backend']
+    # In this case, we need to find what the appropriate gui selection call
+    # should be for IPython, so we can activate inputhook accordingly
+    gui = backend2gui.get(backend, None)
+    return gui, backend
+
+
+def is_interactive_backend(backend):
+    """ Check if backend is interactive """
+    matplotlib = sys.modules['matplotlib']
+    from matplotlib.rcsetup import interactive_bk, non_interactive_bk
+    if backend in interactive_bk:
+        return True
+    elif backend in non_interactive_bk:
+        return False
+    else:
+        return matplotlib.is_interactive()
+
+
+def patch_use(interpreter):
+    """ Patch matplotlib function 'use' """
+    matplotlib = sys.modules['matplotlib']
+    def patched_use(*args, **kwargs):
+        matplotlib.real_use(*args, **kwargs)
+        gui, backend = find_gui_and_backend()
+        interpreter.enableGui(gui)
+
+    setattr(matplotlib, "real_use", getattr(matplotlib, "use"))
+    setattr(matplotlib, "use", patched_use)
+
+
+def patch_is_interactive():
+    """ Patch matplotlib function 'use' """
+    matplotlib = sys.modules['matplotlib']
+    def patched_is_interactive():
+        return matplotlib.rcParams['interactive']
+
+    setattr(matplotlib, "real_is_interactive", getattr(matplotlib, "is_interactive"))
+    setattr(matplotlib, "is_interactive", patched_is_interactive)
+
+
+def activate_matplotlib(interpreter):
+    """Set interactive to True for interactive backends."""
+    def activate_matplotlib_inner():
+        matplotlib = sys.modules['matplotlib']
+        gui, backend = find_gui_and_backend()
+        is_interactive = is_interactive_backend(backend)
+        if is_interactive:
+            interpreter.enableGui(gui)
+            if not matplotlib.is_interactive():
+                sys.stdout.write("Backend %s is interactive backend. Turning interactive mode on.\n" % backend)
+            matplotlib.interactive(True)
+        else:
+            if matplotlib.is_interactive():
+                sys.stdout.write("Backend %s is non-interactive backend. Turning interactive mode off.\n" % backend)
+            matplotlib.interactive(False)
+        patch_use(interpreter)
+        patch_is_interactive()
+    return activate_matplotlib_inner
+
+
+def flag_calls(func):
+    """Wrap a function to detect and flag when it gets called.
+
+    This is a decorator which takes a function and wraps it in a function with
+    a 'called' attribute. wrapper.called is initialized to False.
+
+    The wrapper.called attribute is set to False right before each call to the
+    wrapped function, so if the call fails it remains False.  After the call
+    completes, wrapper.called is set to True and the output is returned.
+
+    Testing for truth in wrapper.called allows you to determine if a call to
+    func() was attempted and succeeded."""
+
+    # don't wrap twice
+    if hasattr(func, 'called'):
+        return func
+
+    def wrapper(*args,**kw):
+        wrapper.called = False
+        out = func(*args,**kw)
+        wrapper.called = True
+        return out
+
+    wrapper.called = False
+    wrapper.__doc__ = func.__doc__
+    return wrapper
+
+
+def activate_pylab():
+    pylab = sys.modules['pylab']
+    pylab.show._needmain = False
+    # We need to detect at runtime whether show() is called by the user.
+    # For this, we wrap it into a decorator which adds a 'called' flag.
+    pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
+
+
+def activate_pyplot():
+    pyplot = sys.modules['matplotlib.pyplot']
+    pyplot.show._needmain = False
+    # We need to detect at runtime whether show() is called by the user.
+    # For this, we wrap it into a decorator which adds a 'called' flag.
+    pyplot.draw_if_interactive = flag_calls(pyplot.draw_if_interactive)
diff --git a/plugins/org.python.pydev/pysrc/pydev_ipython_console_011.py b/plugins/org.python.pydev/pysrc/pydev_ipython_console_011.py
index 33ea830..0337cbc 100644
--- a/plugins/org.python.pydev/pysrc/pydev_ipython_console_011.py
+++ b/plugins/org.python.pydev/pysrc/pydev_ipython_console_011.py
@@ -52,7 +52,7 @@ def show_in_pager(self, strng):
     print(strng)
 
 def create_editor_hook(pydev_host, pydev_client_port):
-    
+
     def call_editor(filename, line=0, wait=True):
         """ Open an editor in PyDev """
         if line is None:
@@ -64,7 +64,7 @@ def create_editor_hook(pydev_host, pydev_client_port):
 
         # import sys
         # sys.__stderr__.write('Calling editor at: %s:%s\n' % (pydev_host, pydev_client_port))
-        
+
         # Tell PyDev to open the editor
         server = xmlrpclib.Server('http://%s:%s' % (pydev_host, pydev_client_port))
         server.IPythonEditor(filename, str(line))
@@ -411,9 +411,9 @@ class _PyDevFrontEnd:
 
     def getNamespace(self):
         return self.ipython.user_ns
-    
+
     def clearBuffer(self):
-        del self._curr_exec_lines[:] 
+        del self._curr_exec_lines[:]
 
     def addExec(self, line):
         if self._curr_exec_lines:
@@ -470,14 +470,14 @@ for name in pydev_ipython.inputhook.__all__:
 class _PyDevFrontEndContainer:
     _instance = None
     _last_host_port = None
-    
+
 def get_pydev_frontend(pydev_host, pydev_client_port, show_banner=True):
     if _PyDevFrontEndContainer._instance is None:
         _PyDevFrontEndContainer._instance = _PyDevFrontEnd(show_banner=show_banner)
-        
+
     if _PyDevFrontEndContainer._last_host_port != (pydev_host, pydev_client_port):
         _PyDevFrontEndContainer._last_host_port = pydev_host, pydev_client_port
-        
+
         # Back channel to PyDev to open editors (in the future other
         # info may go back this way. This is the same channel that is
         # used to get stdin, see StdIn in pydev_console_utils)
@@ -486,7 +486,7 @@ def get_pydev_frontend(pydev_host, pydev_client_port, show_banner=True):
         # Note: setting the callback directly because setting it with set_hook would actually create a chain instead
         # of ovewriting at each new call).
         # _PyDevFrontEndContainer._instance.ipython.set_hook('editor', create_editor_hook(pydev_host, pydev_client_port))
-        
+
     return _PyDevFrontEndContainer._instance
-        
-    
\ No newline at end of file
+
+    
diff --git a/plugins/org.python.pydev/pysrc/pydev_monkey.py b/plugins/org.python.pydev/pysrc/pydev_monkey.py
index d92378e..b0ea030 100644
--- a/plugins/org.python.pydev/pysrc/pydev_monkey.py
+++ b/plugins/org.python.pydev/pysrc/pydev_monkey.py
@@ -1,15 +1,61 @@
+# License: EPL
 import os
 import sys
-import pydev_log
 import traceback
 
+try:
+    xrange
+except:
+    xrange = range
+
+#===============================================================================
+# Things that are dependent on having the pydevd debugger
+#===============================================================================
+def log_debug(msg):
+    import pydev_log
+    pydev_log.debug(msg)
+
+def log_error_once(msg):
+    import pydev_log
+    pydev_log.error_once(msg)
+
 pydev_src_dir = os.path.dirname(__file__)
 
-from pydevd_constants import xrange
+def _get_python_c_args(host, port, indC, args):
+    return ("import sys; sys.path.append(r'%s'); import pydevd; "
+            "pydevd.settrace(host='%s', port=%s, suspend=False, trace_only_current_thread=False, patch_multiprocessing=True); %s"
+            ) % (
+        pydev_src_dir,
+        host,
+        port,
+        args[indC + 1])
+
+def _get_host_port():
+    import pydevd
+    host, port = pydevd.dispatch()
+    return host, port
+
+def _is_managed_arg(arg):
+    if arg.endswith('pydevd.py'):
+        return True
+    return False
 
+def _on_forked_process():
+    import pydevd
+    pydevd.settrace_forked()
+
+def _on_set_trace_for_new_thread():
+    from pydevd_comm import GetGlobalDebugger
+    global_debugger = GetGlobalDebugger()
+    if global_debugger is not None:
+        global_debugger.SetTrace(global_debugger.trace_dispatch)
+
+#===============================================================================
+# Things related to monkey-patching
+#===============================================================================
 def is_python(path):
     if path.endswith("'") or path.endswith('"'):
-        path = path[1:len(path)-1]
+        path = path[1:len(path) - 1]
     filename = os.path.basename(path).lower()
     for name in ['python', 'jython', 'pypy']:
         if filename.find(name) != -1:
@@ -19,7 +65,7 @@ def is_python(path):
 
 def patch_args(args):
     try:
-        pydev_log.debug("Patching args: %s"% str(args))
+        log_debug("Patching args: %s" % str(args))
 
         import sys
         new_args = []
@@ -34,19 +80,16 @@ def patch_args(args):
                 indC = -1
 
             if indC != -1:
-                import pydevd
-                host, port = pydevd.dispatch()
+                host, port = _get_host_port()
 
                 if port is not None:
                     new_args.extend(args)
-                    new_args[indC + 1] = ("import sys; sys.path.append(r'%s'); import pydevd; "
-                        "pydevd.settrace(host='%s', port=%s, suspend=False, trace_only_current_thread=False, patch_multiprocessing=True); %s") % (
-                        pydev_src_dir, host, port, args[indC + 1])
+                    new_args[indC + 1] = _get_python_c_args(host, port, indC, args)
                     return new_args
             else:
                 new_args.append(args[0])
         else:
-            pydev_log.debug("Process is not python, returning.")
+            log_debug("Process is not python, returning.")
             return args
 
         i = 1
@@ -57,7 +100,7 @@ def patch_args(args):
                 break
             i += 1
 
-        if args[i].endswith('pydevd.py'): #no need to add pydevd twice
+        if _is_managed_arg(args[i]):  # no need to add pydevd twice
             return args
 
         for x in sys.original_argv:
@@ -107,7 +150,7 @@ def str_to_args_windows(args):
     for i in xrange(args_len):
         ch = args[i]
         if (ch == '\\'):
-            backslashes+=1
+            backslashes += 1
             continue
         elif (backslashes != 0):
             if ch == '"':
@@ -128,7 +171,7 @@ def str_to_args_windows(args):
                     state = ARG
 
                 while backslashes > 0:
-                    backslashes-=1
+                    backslashes -= 1
                     buf += '\\'
                 # fall through to switch
         if ch in (' ', '\t'):
@@ -155,9 +198,10 @@ def str_to_args_windows(args):
                     # Two consecutive double quotes inside a double-quoted argument are interpreted as
                     # a single double quote.
                     buf += '"'
-                    i+=1
+                    i += 1
                 elif len(buf) == 0:
-                    # empty string on Windows platform. Account for bug in constructor of JDK's java.lang.ProcessImpl.
+                    # empty string on Windows platform. Account for bug in constructor of
+                    # JDK's java.lang.ProcessImpl.
                     result.append("\"\"")
                     state = DEFAULT
                 else:
@@ -179,9 +223,10 @@ def patch_arg_str_win(arg_str):
     if not is_python(args[0]):
         return arg_str
     arg_str = args_to_str(patch_args(args))
-    pydev_log.debug("New args: %s" % arg_str)
+    log_debug("New args: %s" % arg_str)
     return arg_str
 
+
 def monkey_patch_module(module, funcname, create_func):
     if hasattr(module, funcname):
         original_name = 'original_' + funcname
@@ -195,9 +240,7 @@ def monkey_patch_os(funcname, create_func):
 
 
 def warn_multiproc():
-    import pydev_log
-
-    pydev_log.error_once(
+    log_error_once(
         "pydev debugger: New process is launching (breakpoints won't work in the new process).\n"
         "pydev debugger: To debug that process please enable 'Attach to subprocess automatically while debugging?' option in the debugger settings.\n")
 
@@ -212,6 +255,7 @@ def create_warn_multiproc(original_name):
         return getattr(os, original_name)(*args)
     return new_warn_multiproc
 
+
 def create_execl(original_name):
     def new_execl(path, *args):
         '''
@@ -225,6 +269,7 @@ os.execlpe(file, arg0, arg1, ..., env)
         return getattr(os, original_name)(path, *args)
     return new_execl
 
+
 def create_execv(original_name):
     def new_execv(path, args):
         '''
@@ -235,6 +280,7 @@ os.execvp(file, args)
         return getattr(os, original_name)(path, patch_args(args))
     return new_execv
 
+
 def create_execve(original_name):
     """
 os.execve(path, args, env)
@@ -257,6 +303,7 @@ os.spawnlp(mode, file, arg0, arg1, ...)
         return getattr(os, original_name)(mode, path, *args)
     return new_spawnl
 
+
 def create_spawnv(original_name):
     def new_spawnv(mode, path, args):
         '''
@@ -267,6 +314,7 @@ os.spawnvp(mode, file, args)
         return getattr(os, original_name)(mode, path, patch_args(args))
     return new_spawnv
 
+
 def create_spawnve(original_name):
     """
 os.spawnve(mode, path, args, env)
@@ -277,6 +325,18 @@ os.spawnvpe(mode, file, args, env)
         return getattr(os, original_name)(mode, path, patch_args(args), env)
     return new_spawnve
 
+
+def create_fork_exec(original_name):
+    """
+_posixsubprocess.fork_exec(args, executable_list, close_fds, ... (13 more))
+    """
+    def new_fork_exec(args, *other_args):
+        import _posixsubprocess
+        args = patch_args(args)
+        return getattr(_posixsubprocess, original_name)(args, *other_args)
+    return new_fork_exec
+
+
 def create_CreateProcess(original_name):
     """
 CreateProcess(*args, **kwargs)
@@ -289,6 +349,7 @@ CreateProcess(*args, **kwargs)
         return getattr(_subprocess, original_name)(appName, patch_arg_str_win(commandLine), *args)
     return new_CreateProcess
 
+
 def create_CreateProcessWarnMultiproc(original_name):
     """
 CreateProcess(*args, **kwargs)
@@ -302,26 +363,26 @@ CreateProcess(*args, **kwargs)
         return getattr(_subprocess, original_name)(*args)
     return new_CreateProcess
 
+
 def create_fork(original_name):
     def new_fork():
         import os
-        child_process = getattr(os, original_name)() # fork
+        child_process = getattr(os, original_name)()  # fork
         if not child_process:
-            import pydevd
-
-            pydevd.settrace_forked()
+            _on_forked_process()
         return child_process
     return new_fork
 
+
 def patch_new_process_functions():
-#os.execl(path, arg0, arg1, ...)
-#os.execle(path, arg0, arg1, ..., env)
-#os.execlp(file, arg0, arg1, ...)
-#os.execlpe(file, arg0, arg1, ..., env)
-#os.execv(path, args)
-#os.execve(path, args, env)
-#os.execvp(file, args)
-#os.execvpe(file, args, env)
+    # os.execl(path, arg0, arg1, ...)
+    # os.execle(path, arg0, arg1, ..., env)
+    # os.execlp(file, arg0, arg1, ...)
+    # os.execlpe(file, arg0, arg1, ..., env)
+    # os.execv(path, args)
+    # os.execve(path, args, env)
+    # os.execvp(file, args)
+    # os.execvpe(file, args, env)
     monkey_patch_os('execl', create_execl)
     monkey_patch_os('execle', create_execl)
     monkey_patch_os('execlp', create_execl)
@@ -331,14 +392,14 @@ def patch_new_process_functions():
     monkey_patch_os('execvp', create_execv)
     monkey_patch_os('execvpe', create_execve)
 
-#os.spawnl(mode, path, ...)
-#os.spawnle(mode, path, ..., env)
-#os.spawnlp(mode, file, ...)
-#os.spawnlpe(mode, file, ..., env)
-#os.spawnv(mode, path, args)
-#os.spawnve(mode, path, args, env)
-#os.spawnvp(mode, file, args)
-#os.spawnvpe(mode, file, args, env)
+    # os.spawnl(mode, path, ...)
+    # os.spawnle(mode, path, ..., env)
+    # os.spawnlp(mode, file, ...)
+    # os.spawnlpe(mode, file, ..., env)
+    # os.spawnv(mode, path, args)
+    # os.spawnve(mode, path, args, env)
+    # os.spawnvp(mode, file, args)
+    # os.spawnvpe(mode, file, args, env)
 
     monkey_patch_os('spawnl', create_spawnl)
     monkey_patch_os('spawnle', create_spawnl)
@@ -351,8 +412,13 @@ def patch_new_process_functions():
 
     if sys.platform != 'win32':
         monkey_patch_os('fork', create_fork)
+        try:
+            import _posixsubprocess
+            monkey_patch_module(_posixsubprocess, 'fork_exec', create_fork_exec)
+        except ImportError:
+            pass
     else:
-        #Windows
+        # Windows
         try:
             import _subprocess
         except ImportError:
@@ -380,8 +446,13 @@ def patch_new_process_functions_with_warning():
 
     if sys.platform != 'win32':
         monkey_patch_os('fork', create_warn_multiproc)
+        try:
+            import _posixsubprocess
+            monkey_patch_module(_posixsubprocess, 'fork_exec', create_warn_multiproc)
+        except ImportError:
+            pass
     else:
-        #Windows
+        # Windows
         try:
             import _subprocess
         except ImportError:
@@ -389,7 +460,6 @@ def patch_new_process_functions_with_warning():
         monkey_patch_module(_subprocess, 'CreateProcess', create_CreateProcessWarnMultiproc)
 
 
-
 class _NewThreadStartupWithTrace:
 
     def __init__(self, original_func, args, kwargs):
@@ -398,13 +468,10 @@ class _NewThreadStartupWithTrace:
         self.kwargs = kwargs
 
     def __call__(self):
-        from pydevd_comm import GetGlobalDebugger
-        global_debugger = GetGlobalDebugger()
-        if global_debugger is not None:
-            global_debugger.SetTrace(global_debugger.trace_dispatch)
-
+        _on_set_trace_for_new_thread()
         return self.original_func(*self.args, **self.kwargs)
 
+
 class _NewThreadStartupWithoutTrace:
 
     def __init__(self, original_func, args, kwargs):
@@ -417,6 +484,7 @@ class _NewThreadStartupWithoutTrace:
 
 _UseNewThreadStartup = _NewThreadStartupWithTrace
 
+
 def _get_threading_modules_to_patch():
     threading_modules_to_patch = []
     try:
@@ -430,7 +498,6 @@ def _get_threading_modules_to_patch():
 threading_modules_to_patch = _get_threading_modules_to_patch()
 
 
-
 def patch_thread_module(thread):
 
     if getattr(thread, '_original_start_new_thread', None) is None:
@@ -438,7 +505,6 @@ def patch_thread_module(thread):
     else:
         _original_start_new_thread = thread._original_start_new_thread
 
-
     class ClassWithPydevStartNewThread:
 
         def pydev_start_new_thread(self, function, args=(), kwargs={}):
@@ -466,10 +532,12 @@ def patch_thread_module(thread):
     except:
         pass
 
+
 def patch_thread_modules():
     for t in threading_modules_to_patch:
         patch_thread_module(t)
 
+
 def undo_patch_thread_modules():
     for t in threading_modules_to_patch:
         try:
@@ -482,6 +550,7 @@ def undo_patch_thread_modules():
         except:
             pass
 
+
 def disable_trace_thread_modules():
     '''
     Can be used to temporarily stop tracing threads created with thread.start_new_thread.
@@ -497,6 +566,7 @@ def enable_trace_thread_modules():
     global _UseNewThreadStartup
     _UseNewThreadStartup = _NewThreadStartupWithTrace
 
+
 def get_original_start_new_thread(threading_module):
     try:
         return threading_module._original_start_new_thread
diff --git a/plugins/org.python.pydev/pysrc/pydev_monkey_qt.py b/plugins/org.python.pydev/pysrc/pydev_monkey_qt.py
index 94695bc..0435a15 100644
--- a/plugins/org.python.pydev/pysrc/pydev_monkey_qt.py
+++ b/plugins/org.python.pydev/pysrc/pydev_monkey_qt.py
@@ -57,10 +57,20 @@ def _patch_import_to_patch_pyqt_on_import(patch_qt_on_import):
     
     dotted = patch_qt_on_import + '.'
     original_import = __import__
-    
+    import sys
+    original_exc_info = sys.exc_info
+
+    def patched_exc_info():
+        type, value, traceback = original_exc_info()
+        if type == ImportError:
+            #we should not show frame added by patched_import call
+            return type, value, traceback.tb_next
+        return type, value, traceback
+
     def patched_import(name, *args, **kwargs):
         if patch_qt_on_import == name or name.startswith(dotted):
             builtins.__import__ = original_import
+            sys.exc_info = original_exc_info
             _internal_patch_qt() # Patch it only when the user would import the qt module
         return original_import(name, *args, **kwargs)
     
@@ -68,8 +78,9 @@ def _patch_import_to_patch_pyqt_on_import(patch_qt_on_import):
         import builtins
     except ImportError:
         import __builtin__ as builtins
-    builtins.__import__ = patched_import 
-    
+    builtins.__import__ = patched_import
+    sys.exc_info = patched_exc_info
+
     
 def _internal_patch_qt():
     try:
@@ -85,7 +96,8 @@ def _internal_patch_qt():
     
     _original_thread_init = QtCore.QThread.__init__
     _original_runnable_init = QtCore.QRunnable.__init__
-    
+    _original_QThread = QtCore.QThread
+
     
     class FuncWrapper:
         
@@ -113,15 +125,24 @@ def _internal_patch_qt():
             
     
     class ThreadWrapper(QtCore.QThread):  # Wrapper for QThread
-        
+
         def __init__(self, *args, **kwargs):
             _original_thread_init(self)
-    
-            self._original_run = self.run
-            self.run = self._new_run
+
+            # In PyQt5 the program hangs when we try to call original run method of QThread class.
+            # So we need to distinguish instances of QThread class and instances of QThread inheritors.
+            if self.__class__.run == _original_QThread.run:
+                self.run = self._exec_run
+            else:
+                self._original_run = self.run
+                self.run = self._new_run
             self._original_started = self.started
             self.started = StartedSignalWrapper(self, self.started)
-            
+
+        def _exec_run(self):
+            set_trace_in_qt()
+            return self.exec_()
+
         def _new_run(self):
             set_trace_in_qt()
             return self._original_run()
diff --git a/plugins/org.python.pydev/pysrc/pydev_run_in_console.py b/plugins/org.python.pydev/pysrc/pydev_run_in_console.py
index 731ead6..4224dd1 100644
--- a/plugins/org.python.pydev/pysrc/pydev_run_in_console.py
+++ b/plugins/org.python.pydev/pysrc/pydev_run_in_console.py
@@ -41,6 +41,8 @@ if __name__ == '__main__':
 
     file = sys.argv[1]
 
+    del sys.argv[0]
+
     import pydev_localhost
 
     if int(port) == 0 and int(client_port) == 0:
diff --git a/plugins/org.python.pydev/pysrc/pydev_runfiles_pytest2.py b/plugins/org.python.pydev/pysrc/pydev_runfiles_pytest2.py
index 6a4d94f..d3c5909 100644
--- a/plugins/org.python.pydev/pysrc/pydev_runfiles_pytest2.py
+++ b/plugins/org.python.pydev/pysrc/pydev_runfiles_pytest2.py
@@ -32,6 +32,8 @@ def connect_to_server_for_communication_to_xml_rpc_on_xdist():
         else:
             pydev_runfiles_xml_rpc.InitializeServer(int(port), daemon=True)
 
+PY2 = sys.version_info[0] <= 2
+PY3 = not PY2
 
 #===================================================================================================
 # Mocking to get clickable file representations
@@ -47,7 +49,18 @@ def _MockFileRepresentation():
         if i != -1:
             msg = msg[:i]
 
-        tw.line('File "%s", line %s\n%s' %(os.path.abspath(self.path), self.lineno, msg))
+        path = os.path.abspath(self.path)
+        
+        if PY2:
+            if not isinstance(path, unicode):  # Note: it usually is NOT unicode...
+                path = path.decode(sys.getfilesystemencoding(), 'replace')
+                
+            if not isinstance(msg, unicode):  # Note: it usually is unicode...
+                msg = msg.decode('utf-8', 'replace')
+            unicode_line = unicode('File "%s", line %s\n%s') % (path, self.lineno, msg)
+            tw.line(unicode_line)
+        else:
+            tw.line('File "%s", line %s\n%s' % (path, self.lineno, msg))
 
     code.ReprFileLocation.toterminal = toterminal
 
@@ -123,6 +136,10 @@ def pytest_runtest_makereport(item, call):
             report_outcome = "failed"
             report_longrepr = excinfo
 
+        elif excinfo.errisinstance(pytest.xfail.Exception):
+            report_outcome = "passed"
+            report_longrepr = None
+            
         elif excinfo.errisinstance(py.test.skip.Exception):
             report_outcome = "skipped"
             r = excinfo._getreprcrash()
@@ -209,6 +226,10 @@ def pytest_runtest_setup(item):
     else:
         class_name = None
     for test in accept_tests:
+        # This happens when parameterizing pytest tests.
+        i = name.find('[')
+        if i > 0:
+            name = name[:i]
         if test == name:
             #Direct match of the test (just go on with the default loading)
             return
diff --git a/plugins/org.python.pydev/pysrc/pydev_runfiles_xml_rpc.py b/plugins/org.python.pydev/pysrc/pydev_runfiles_xml_rpc.py
index fccbcad..89d50ba 100644
--- a/plugins/org.python.pydev/pysrc/pydev_runfiles_xml_rpc.py
+++ b/plugins/org.python.pydev/pysrc/pydev_runfiles_xml_rpc.py
@@ -80,6 +80,10 @@ class ServerFacade(object):
 
 
     def notifyTest(self, *args):
+        new_args = []
+        for arg in args:
+            new_args.append(_encode_if_needed(arg))
+        args = tuple(new_args)
         self.notifications_queue.put_nowait(ParallelNotification('notifyTest', args))
 
 
diff --git a/plugins/org.python.pydev/pysrc/pydevconsole.py b/plugins/org.python.pydev/pysrc/pydevconsole.py
index 06abbaf..d5f5520 100644
--- a/plugins/org.python.pydev/pysrc/pydevconsole.py
+++ b/plugins/org.python.pydev/pysrc/pydevconsole.py
@@ -39,10 +39,13 @@ from pydev_console_utils import BaseInterpreterInterface, BaseStdIn
 from pydev_console_utils import CodeFragment
 
 IS_PYTHON_3K = False
+IS_PY24 = False
 
 try:
     if sys.version_info[0] == 3:
         IS_PYTHON_3K = True
+    elif sys.version_info[0] == 2 and sys.version_info[1] == 4:
+        IS_PY24 = True
 except:
     #That's OK, not all versions of python have sys.version_info
     pass
@@ -58,14 +61,14 @@ class Command:
         self.code_fragment = code_fragment
         self.more = None
 
-    
+
     def symbol_for_fragment(code_fragment):
         if code_fragment.is_single_line:
             symbol = 'single'
         else:
             symbol = 'exec' # Jython doesn't support this
         return symbol
-    symbol_for_fragment = staticmethod(symbol_for_fragment) 
+    symbol_for_fragment = staticmethod(symbol_for_fragment)
 
     def run(self):
         text = self.code_fragment.text
@@ -101,7 +104,7 @@ class InterpreterInterface(BaseInterpreterInterface):
         The methods in this class should be registered in the xml-rpc server.
     '''
 
-    def __init__(self, host, client_port, mainThread):
+    def __init__(self, host, client_port, mainThread, show_banner=True):
         BaseInterpreterInterface.__init__(self, mainThread)
         self.client_port = client_port
         self.host = host
@@ -171,6 +174,12 @@ def process_exec_queue(interpreter):
 
     set_return_control_callback(return_control)
 
+    from pydev_import_hook import import_hook_manager
+    from pydev_ipython.matplotlibtools import activate_matplotlib, activate_pylab, activate_pyplot
+    import_hook_manager.add_module_name("matplotlib", activate_matplotlib(interpreter))
+    import_hook_manager.add_module_name("pylab", activate_pylab)
+    import_hook_manager.add_module_name("pyplot", activate_pyplot)
+
     while 1:
         # Running the request may have changed the inputhook in use
         inputhook = get_inputhook()
@@ -266,10 +275,13 @@ def start_server(host, port, interpreter):
     from pydev_imports import SimpleXMLRPCServer as XMLRPCServer  #@Reimport
 
     try:
-        server = XMLRPCServer((host, port), logRequests=False, allow_none=True)
+        if IS_PY24:
+            server = XMLRPCServer((host, port), logRequests=False)
+        else:
+            server = XMLRPCServer((host, port), logRequests=False, allow_none=True)
 
     except:
-        sys.stderr.write('Error starting server with host: %s, port: %s, client_port: %s\n' % (host, port, client_port))
+        sys.stderr.write('Error starting server with host: %s, port: %s, client_port: %s\n' % (host, port, interpreter.client_port))
         raise
 
     # Tell UMD the proper default namespace
@@ -287,6 +299,8 @@ def start_server(host, port, interpreter):
     server.register_function(handshake)
     server.register_function(interpreter.connectToDebugger)
     server.register_function(interpreter.hello)
+    server.register_function(interpreter.getArray)
+    server.register_function(interpreter.evaluate)
 
     # Functions for GUI main loop integration
     server.register_function(interpreter.enableGui)
@@ -295,14 +309,28 @@ def start_server(host, port, interpreter):
         (h, port) = server.socket.getsockname()
 
         print(port)
-        print(client_port)
+        print(interpreter.client_port)
 
 
     sys.stderr.write(interpreter.get_greeting_msg())
     sys.stderr.flush()
 
-    server.serve_forever()
-
+    while True:
+        try:
+            server.serve_forever()
+        except:
+            # Ugly code to be py2/3 compatible
+            # https://sw-brainwy.rhcloud.com/tracker/PyDev/534:
+            # Unhandled "interrupted system call" error in the pydevconsol.py
+            e = sys.exc_info()[1]
+            retry = False
+            try:
+                retry = e.args[0] == 4 #errno.EINTR
+            except:
+                pass
+            if not retry:
+                raise
+            # Otherwise, keep on going
     return server
 
 
@@ -322,7 +350,12 @@ def get_interpreter():
     try:
         interpreterInterface = getattr(__builtin__, 'interpreter')
     except AttributeError:
-        interpreterInterface = InterpreterInterface(None, None, threading.currentThread(), show_banner=False)
+        # fake return_controll_callback function just to prevent exception in PyCharm debug console
+        from pydev_ipython.inputhook import set_return_control_callback
+        set_return_control_callback(lambda x: True)
+
+        interpreterInterface = InterpreterInterface(
+            None, None, threading.currentThread(), show_banner=False)
         setattr(__builtin__, 'interpreter', interpreterInterface)
 
     return interpreterInterface
@@ -458,7 +491,7 @@ if __name__ == '__main__':
     #Important: don't use this module directly as the __main__ module, rather, import itself as pydevconsole
     #so that we don't get multiple pydevconsole modules if it's executed directly (otherwise we'd have multiple
     #representations of its classes).
-    #See: https://sw-brainwy.rhcloud.com/tracker/PyDev/446: 
+    #See: https://sw-brainwy.rhcloud.com/tracker/PyDev/446:
     #'Variables' and 'Expressions' views stopped working when debugging interactive console
     import pydevconsole
     sys.stdin = pydevconsole.BaseStdIn()
diff --git a/plugins/org.python.pydev/pysrc/pydevd.py b/plugins/org.python.pydev/pysrc/pydevd.py
index 2d2989a..0852d19 100644
--- a/plugins/org.python.pydev/pysrc/pydevd.py
+++ b/plugins/org.python.pydev/pysrc/pydevd.py
@@ -19,6 +19,7 @@ from pydevd_comm import  CMD_CHANGE_VARIABLE, \
                          CMD_GET_COMPLETIONS, \
                          CMD_GET_FRAME, \
                          CMD_GET_VARIABLE, \
+                         CMD_GET_ARRAY, \
                          CMD_LIST_THREADS, \
                          CMD_REMOVE_BREAK, \
                          CMD_RUN, \
@@ -47,6 +48,7 @@ from pydevd_comm import  CMD_CHANGE_VARIABLE, \
                          InternalConsoleExec, \
                          InternalGetFrame, \
                          InternalGetVariable, \
+                         InternalGetArray, \
                          InternalTerminateThread, \
                          InternalRunThread, \
                          InternalStepThread, \
@@ -185,14 +187,14 @@ if hasattr(_temp, '_is_stopped'): # Python 3.4 has this
             return not t._is_stopped
         except:
             return t.isAlive()
-    
+
 elif hasattr(_temp, '_Thread__stopped'): # Python 2.7 has this
     def isThreadAlive(t):
         try:
             return not t._Thread__stopped
         except:
             return t.isAlive()
-    
+
 else: # Haven't checked all other versions, so, let's use the regular isAlive call in this case.
     def isThreadAlive(t):
         return t.isAlive()
@@ -241,46 +243,57 @@ def killAllPydevThreads():
 
 
 #=======================================================================================================================
-# PyDBCheckAliveThread
+# CheckOutputThread
+# Non-daemonic thread guaranties that all data is written even if program is finished
 #=======================================================================================================================
-class PyDBCheckAliveThread(PyDBDaemonThread):
+class CheckOutputThread(PyDBDaemonThread):
 
     def __init__(self, pyDb):
         PyDBDaemonThread.__init__(self)
         self.pyDb = pyDb
         self.setName('pydevd.CheckAliveThread')
+        pyDb.output_checker = self
+
+    def start(self):
+        # it should be non daemon
+        thread = threading.Thread(target=self.run)
+        thread.daemon = False
+        thread.start()
 
     def OnRun(self):
-            if self.dontTraceMe:
-
-                disable_tracing = True
-        
-                if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON and sys.hexversion <= 0x020201f0:
-                    # don't run untraced threads if we're in jython 2.2.1 or lower
-                    # jython bug: if we start a thread and another thread changes the tracing facility
-                    # it affects other threads (it's not set only for the thread but globally)
-                    # Bug: http://sourceforge.net/tracker/index.php?func=detail&aid=1870039&group_id=12867&atid=112867
-                    disable_tracing = False
-        
-                if disable_tracing:
-                    pydevd_tracing.SetTrace(None)  # no debugging on this thread
-                    
-            while not self.killReceived:
-                if not self.pyDb.haveAliveThreads():
-                    try:
-                        pydev_log.debug("No alive threads, finishing debug session")
-                        self.pyDb.FinishDebuggingSession()
-                        killAllPydevThreads()
-                    except:
-                        traceback.print_exc()
+        if self.dontTraceMe:
 
-                    self.killReceived = True
-                    return
+            disable_tracing = True
+
+            if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON and sys.hexversion <= 0x020201f0:
+                # don't run untraced threads if we're in jython 2.2.1 or lower
+                # jython bug: if we start a thread and another thread changes the tracing facility
+                # it affects other threads (it's not set only for the thread but globally)
+                # Bug: http://sourceforge.net/tracker/index.php?func=detail&aid=1870039&group_id=12867&atid=112867
+                disable_tracing = False
+
+            if disable_tracing:
+                pydevd_tracing.SetTrace(None)  # no debugging on this thread
+
+        while not self.killReceived:
+            if not self.pyDb.haveAliveThreads() and self.pyDb.writer.empty() \
+                    and not has_data_to_redirect():
+                try:
+                    pydev_log.debug("No alive threads, finishing debug session")
+                    self.pyDb.is_exiting = True
+                    self.pyDb.FinishDebuggingSession()
+                    killAllPydevThreads()
+                except:
+                    traceback.print_exc()
+
+                self.killReceived = True
+
+            self.pyDb.checkOutputRedirect()
 
-                time.sleep(0.3)
+            time.sleep(0.3)
 
     def doKillPydevThread(self):
-        pass
+        self.killReceived = True
 
 
 
@@ -307,6 +320,7 @@ class PyDB:
         pydevd_tracing.ReplaceSysSetTraceFunc()
         self.reader = None
         self.writer = None
+        self.output_checker = None
         self.quitting = None
         self.cmdFactory = NetCommandFactory()
         self._cmd_queue = {}  # the hash of Queues. Key is thread id, value is thread
@@ -357,7 +371,7 @@ class PyDB:
         self.plugin = None
         self.has_plugin_line_breaks = False
         self.has_plugin_exception_breaks = False
-        
+
     def get_plugin_lazy_init(self):
         if self.plugin is None and SUPPORT_PLUGINS:
             self.plugin = PluginManager(self)
@@ -369,13 +383,13 @@ class PyDB:
             if isinstance(t, PyDBDaemonThread):
                 pydev_log.error_once(
                     'Error in debugger: Found PyDBDaemonThread through threading.enumerate().\n')
-                
+
             if getattr(t, 'is_pydev_daemon_thread', False):
                 #Important: Jython 2.5rc4 has a bug where a thread created with thread.start_new_thread won't be
                 #set as a daemon thread, so, we also have to check for the 'is_pydev_daemon_thread' flag.
                 #See: https://github.com/fabioz/PyDev.Debugger/issues/11
                 continue
-            
+
             if isThreadAlive(t) and not t.isDaemon():
                 return True
 
@@ -486,10 +500,10 @@ class PyDB:
 
                     if isinstance(t, PyDBDaemonThread):
                         pydev_log.error_once('Found PyDBDaemonThread in threading.enumerate.')
-                        
+
                     elif getattr(t, 'is_pydev_daemon_thread', False):
                         pass # I.e.: skip the DummyThreads created from pydev daemon threads
-                        
+
                     elif isThreadAlive(t):
                         program_threads_alive[thread_id] = t
 
@@ -790,6 +804,23 @@ class PyDB:
                     except:
                         traceback.print_exc()
 
+                elif cmd_id == CMD_GET_ARRAY:
+                    # we received some command to get an array variable
+                    # the text is: thread_id\tframe_id\tFRAME|GLOBAL\tname\ttemp\troffs\tcoffs\trows\tcols\tformat
+                    try:
+                        roffset, coffset, rows, cols, format, thread_id, frame_id, scopeattrs  = text.split('\t', 7)
+
+                        if scopeattrs.find('\t') != -1:  # there are attributes beyond scope
+                            scope, attrs = scopeattrs.split('\t', 1)
+                        else:
+                            scope, attrs = (scopeattrs, None)
+
+                        int_cmd = InternalGetArray(seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs)
+                        self.postInternalCommand(int_cmd, thread_id)
+
+                    except:
+                        traceback.print_exc()
+
                 elif cmd_id == CMD_GET_COMPLETIONS:
                     # we received some command to get a variable
                     # the text is: thread_id\tframe_id\tactivation token
@@ -828,21 +859,16 @@ class PyDB:
                     else:
                         #Note: this else should be removed after PyCharm migrates to setting
                         #breakpoints by id (and ideally also provides func_name).
-                        type, file, line, condition, expression = text.split('\t', 4)
+                        type, file, line, func_name, condition, expression = text.split('\t', 5)
                         # If we don't have an id given for each breakpoint, consider
                         # the id to be the line.
                         breakpoint_id = line = int(line)
-                        if condition.startswith('**FUNC**'):
-                            func_name, condition = condition.split('\t', 1)
 
-                            # We must restore new lines and tabs as done in
-                            # AbstractDebugTarget.breakpointAdded
-                            condition = condition.replace("@_ at NEW_LINE_CHAR@_@", '\n').\
-                                replace("@_ at TAB_CHAR@_@", '\t').strip()
+                        condition = condition.replace("@_ at NEW_LINE_CHAR@_@", '\n'). \
+                            replace("@_ at TAB_CHAR@_@", '\t').strip()
 
-                            func_name = func_name[8:]
-                        else:
-                            func_name = 'None'  # Match anything if not specified.
+                        expression = expression.replace("@_ at NEW_LINE_CHAR@_@", '\n'). \
+                            replace("@_ at TAB_CHAR@_@", '\t').strip()
 
                     if not IS_PY3K:  # In Python 3, the frame object will have unicode for the file, whereas on python 2 it has a byte-array encoded with the filesystem encoding.
                         file = file.encode(file_system_encoding)
@@ -1110,10 +1136,10 @@ class PyDB:
                         update_exception_hook(self)
                     else:
                         supported_type = False
-                        
+
                         # I.e.: no need to initialize lazy (if we didn't have it in the first place, we can't remove
                         # anything from it anyways).
-                        plugin = self.plugin 
+                        plugin = self.plugin
                         if plugin is not None:
                             supported_type = plugin.remove_exception_breakpoint(self, type, exception)
 
@@ -1154,10 +1180,21 @@ class PyDB:
                     if text != "":
                         thread_id, frame_id, console_command = text.split('\t', 2)
                         console_command, line = console_command.split('\t')
+
                         if console_command == 'EVALUATE':
-                            int_cmd = InternalEvaluateConsoleExpression(seq, thread_id, frame_id, line)
+                            int_cmd = InternalEvaluateConsoleExpression(
+                                seq, thread_id, frame_id, line, buffer_output=True)
+
+                        elif console_command == 'EVALUATE_UNBUFFERED':
+                            int_cmd = InternalEvaluateConsoleExpression(
+                                seq, thread_id, frame_id, line, buffer_output=False)
+
                         elif console_command == 'GET_COMPLETIONS':
                             int_cmd = InternalConsoleGetCompletions(seq, thread_id, frame_id, line)
+
+                        else:
+                            raise ValueError('Unrecognized command: %s' % (console_command,))
+
                         self.postInternalCommand(int_cmd, thread_id)
 
                 elif cmd_id == CMD_RUN_CUSTOM_OPERATION:
@@ -1437,10 +1474,8 @@ class PyDB:
             if self._finishDebuggingSession and not self._terminationEventSent:
                 #that was not working very well because jython gave some socket errors
                 try:
-                    threads = DictKeys(PyDBDaemonThread.created_pydb_daemon_threads)
-                    for t in threads:
-                        if hasattr(t, 'doKillPydevThread'):
-                            t.doKillPydevThread()
+                    if self.output_checker is None:
+                        killAllPydevThreads()
                 except:
                     traceback.print_exc()
                 self._terminationEventSent = True
@@ -1495,6 +1530,8 @@ class PyDB:
             return None
 
         except Exception:
+            if self._finishDebuggingSession:
+                return None # Don't log errors when we're shutting down.
             # Log it
             try:
                 if traceback is not None:
@@ -1502,7 +1539,7 @@ class PyDB:
                     traceback.print_exc()
             except:
                 # Error logging? We're really in the interpreter shutdown...
-                # (https://github.com/fabioz/PyDev.Debugger/issues/8) 
+                # (https://github.com/fabioz/PyDev.Debugger/issues/8)
                 pass
             return None
 
@@ -1561,7 +1598,9 @@ class PyDB:
 
 
         PyDBCommandThread(self).start()
-        PyDBCheckAliveThread(self).start()
+        if self.signature_factory is not None:
+            # we need all data to be sent to IDE even after program finishes
+            CheckOutputThread(self).start()
 
 
     def patch_threads(self):
@@ -1720,13 +1759,26 @@ def usage(doExit=0):
 def initStdoutRedirect():
     if not getattr(sys, 'stdoutBuf', None):
         sys.stdoutBuf = pydevd_io.IOBuf()
+        sys.stdout_original = sys.stdout
         sys.stdout = pydevd_io.IORedirector(sys.stdout, sys.stdoutBuf) #@UndefinedVariable
 
 def initStderrRedirect():
     if not getattr(sys, 'stderrBuf', None):
         sys.stderrBuf = pydevd_io.IOBuf()
+        sys.stderr_original = sys.stderr
         sys.stderr = pydevd_io.IORedirector(sys.stderr, sys.stderrBuf) #@UndefinedVariable
 
+
+def has_data_to_redirect():
+    if getattr(sys, 'stdoutBuf', None):
+        if not sys.stdoutBuf.empty():
+            return True
+    if getattr(sys, 'stderrBuf', None):
+        if not sys.stderrBuf.empty():
+            return True
+
+    return False
+
 #=======================================================================================================================
 # settrace
 #=======================================================================================================================
@@ -1859,13 +1911,13 @@ def _locked_settrace(
 
         # Stop the tracing as the last thing before the actual shutdown for a clean exit.
         atexit.register(stoptrace)
-        
+
         #Suspend as the last thing after all tracing is in place.
         if suspend:
-            debugger.setSuspend(t, CMD_SET_BREAK)
+            debugger.setSuspend(t, CMD_THREAD_SUSPEND)
 
         PyDBCommandThread(debugger).start()
-        PyDBCheckAliveThread(debugger).start()
+        CheckOutputThread(debugger).start()
 
     else:
         # ok, we're already in debug mode, with all set, so, let's just set the break
@@ -1888,7 +1940,7 @@ def _locked_settrace(
 
 
         if suspend:
-            debugger.setSuspend(t, CMD_SET_BREAK)
+            debugger.setSuspend(t, CMD_THREAD_SUSPEND)
 
 
 def stoptrace():
@@ -1904,15 +1956,15 @@ def stoptrace():
 
         from pydev_monkey import undo_patch_thread_modules
         undo_patch_thread_modules()
- 
+
         debugger = GetGlobalDebugger()
- 
+
         if debugger:
-  
+
             debugger.SetTraceForFrameAndParents(
                 GetFrame(), also_add_to_passed_frame=True, overwrite_prev_trace=True, dispatch_func=lambda *args:None)
             debugger.exiting()
-  
+
             killAllPydevThreads()
 
         connected = False
@@ -1944,7 +1996,7 @@ class DispatchReader(ReaderThread):
         dummy_thread = threading.currentThread()
         dummy_thread.is_pydev_daemon_thread = False
         return ReaderThread.OnRun(self)
-        
+
     def handleExcept(self):
         ReaderThread.handleExcept(self)
 
@@ -2008,7 +2060,7 @@ class SetupHolder:
 # main
 #=======================================================================================================================
 if __name__ == '__main__':
-    
+
     # parse the command line. --file is our last argument that is required
     try:
         sys.original_argv = sys.argv[:]
@@ -2033,7 +2085,7 @@ if __name__ == '__main__':
 
     pydevd_vm_type.SetupType(setup.get('vm_type', None))
 
-    if os.getenv('PYCHARM_DEBUG'):
+    if os.getenv('PYCHARM_DEBUG') or os.getenv('PYDEV_DEBUG'):
         set_debug(setup)
 
     DebugInfoHolder.DEBUG_RECORD_SOCKET_READS = setup.get('DEBUG_RECORD_SOCKET_READS', False)
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/add_code_to_python_process.py b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/add_code_to_python_process.py
index d2ca18d..d8dca95 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/add_code_to_python_process.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/add_code_to_python_process.py
@@ -1,526 +1,620 @@
-r'''
-Copyright: Brainwy Software Ltda.
-
-License: EPL.
-=============
-
-Works for Windows relying on a fork of winappdbg which works in py2/3 (at least for the part we're interested in).
-
-See: https://github.com/fabioz/winappdbg (py3 branch).
-Note that the official branch for winappdbg is: https://github.com/MarioVilas/winappdbg, which should be used when it works in Py3.
-A private copy is added here to make deployment easier, but changes should always be done upstream first.
-
-Works for Linux relying on gdb.
-
-Limitations:
-============
-
-    Linux:
-    ------
-
-        1. It possible that ptrace is disabled: /etc/sysctl.d/10-ptrace.conf
-
-        Note that even enabling it in /etc/sysctl.d/10-ptrace.conf (i.e.: making the
-        ptrace_scope=0), it's possible that we need to run the application that'll use ptrace (or
-        gdb in this case) as root (so, we must sudo the python which'll run this module).
-
-        2. It currently doesn't work in debug builds (i.e.: python_d)
-
-
-Other implementations:
-- pyrasite.com:
-    GPL
-    Windows/linux (in Linux it also uses gdb to connect -- although specifics are different as we use a dll to execute
-    code with other threads stopped). It's Windows approach is more limited because it doesn't seem to deal properly with 
-    Python 3 if threading is disabled. 
-
-- https://github.com/google/pyringe:
-    Apache v2.
-    Only linux/Python 2.
-
-- http://pytools.codeplex.com:
-    Apache V2
-    Windows Only (but supports mixed mode debugging)
-    Our own code relies heavily on a part of it: http://pytools.codeplex.com/SourceControl/latest#Python/Product/PyDebugAttach/PyDebugAttach.cpp
-    to overcome some limitations of attaching and running code in the target python executable on Python 3.
-    See: attach.cpp
-
-Linux: References if we wanted to use a pure-python debugger:
-    https://bitbucket.org/haypo/python-ptrace/
-    http://stackoverflow.com/questions/7841573/how-to-get-an-error-message-for-errno-value-in-python
-    Jugaad:
-        https://www.defcon.org/images/defcon-19/dc-19-presentations/Jakhar/DEFCON-19-Jakhar-Jugaad-Linux-Thread-Injection.pdf
-        https://github.com/aseemjakhar/jugaad
-
-Something else (general and not Python related):
-- http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
-
-Other references:
-- https://github.com/haypo/faulthandler
-- http://nedbatchelder.com/text/trace-function.html
-- https://github.com/python-git/python/blob/master/Python/sysmodule.c (sys_settrace)
-- https://github.com/python-git/python/blob/master/Python/ceval.c (PyEval_SetTrace)
-- https://github.com/python-git/python/blob/master/Python/thread.c (PyThread_get_key_value)
-
-
-To build the dlls needed on windows, visual studio express 13 was used (see compile_dll.bat)
-
-See: attach_pydevd.py to attach the pydev debugger to a running python process.
-'''
-
-# Note: to work with nasm compiling asm to code and decompiling to see asm with shellcode:
-# x:\nasm\nasm-2.07-win32\nasm-2.07\nasm.exe
-# nasm.asm&x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe -b arch nasm
-import ctypes
-import os
-import struct
-import subprocess
-import sys
-import time
-
-class AutoExit(object):
-
-    def __init__(self, on_exit):
-        self.on_exit = on_exit
-
-    def __enter__(self):
-        pass
-
-    def __exit__(self, *args):
-        self.on_exit()
-
-
-class GenShellCodeHelper(object):
-
-    def __init__(self, is_64):
-        from winappdbg import compat
-        self.is_64 = is_64
-        self._code = []
-        if not is_64:
-            self._translations = {
-                'push esi': compat.b('\x56'),
-                'push eax': compat.b('\x50'),
-                'push ebp': compat.b('\x55'),
-                'push ebx': compat.b('\x53'),
-
-                'pop esi': compat.b('\x5E'),
-                'pop eax': compat.b('\x58'),
-                'pop ebp': compat.b('\x5D'),
-                'pop ebx': compat.b('\x5B'),
-
-                'mov esi': compat.b('\xBE'),
-                'mov eax': compat.b('\xB8'),
-                'mov ebp': compat.b('\xBD'),
-                'mov ebx': compat.b('\xBB'),
-
-                'call ebp': compat.b('\xFF\xD5'),
-                'call eax': compat.b('\xFF\xD0'),
-                'call ebx': compat.b('\xFF\xD3'),
-
-                'mov ebx,eax': compat.b('\x89\xC3'),
-                'mov eax,ebx': compat.b('\x89\xD8'),
-                'mov ebp,esp': compat.b('\x89\xE5'),
-                'mov esp,ebp': compat.b('\x89\xEC'),
-                'push dword': compat.b('\x68'),
-
-                'mov ebp,eax': compat.b('\x89\xC5'),
-                'mov eax,ebp': compat.b('\x89\xE8'),
-
-                'ret': compat.b('\xc3'),
-            }
-        else:
-            # Translate 64 bits
-            self._translations = {
-                'push rsi': compat.b('\x56'),
-                'push rax': compat.b('\x50'),
-                'push rbp': compat.b('\x55'),
-                'push rbx': compat.b('\x53'),
-                'push rsp': compat.b('\x54'),
-                'push rdi': compat.b('\x57'),
-
-                'pop rsi': compat.b('\x5E'),
-                'pop rax': compat.b('\x58'),
-                'pop rbp': compat.b('\x5D'),
-                'pop rbx': compat.b('\x5B'),
-                'pop rsp': compat.b('\x5C'),
-                'pop rdi': compat.b('\x5F'),
-
-                'mov rsi': compat.b('\x48\xBE'),
-                'mov rax': compat.b('\x48\xB8'),
-                'mov rbp': compat.b('\x48\xBD'),
-                'mov rbx': compat.b('\x48\xBB'),
-                'mov rdi': compat.b('\x48\xBF'),
-                'mov rcx': compat.b('\x48\xB9'),
-                'mov rdx': compat.b('\x48\xBA'),
-
-                'call rbp': compat.b('\xFF\xD5'),
-                'call rax': compat.b('\xFF\xD0'),
-                'call rbx': compat.b('\xFF\xD3'),
-
-                'mov rbx,rax': compat.b('\x48\x89\xC3'),
-                'mov rax,rbx': compat.b('\x48\x89\xD8'),
-                'mov rbp,rsp': compat.b('\x48\x89\xE5'),
-                'mov rsp,rbp': compat.b('\x48\x89\xEC'),
-                'mov rcx,rbp': compat.b('\x48\x89\xE9'),
-
-                'mov rbp,rax': compat.b('\x48\x89\xC5'),
-                'mov rax,rbp': compat.b('\x48\x89\xE8'),
-
-                'mov rdi,rbp': compat.b('\x48\x89\xEF'),
-
-                'ret': compat.b('\xc3'),
-            }
-
-    def push_addr(self, addr):
-        self._code.append(self.translate('push dword'))
-        self._code.append(addr)
-
-    def push(self, register):
-        self._code.append(self.translate('push %s' % register))
-        return AutoExit(lambda: self.pop(register))
-
-    def pop(self, register):
-        self._code.append(self.translate('pop %s' % register))
-
-    def mov_to_register_addr(self, register, addr):
-        self._code.append(self.translate('mov %s' % register))
-        self._code.append(addr)
-
-    def mov_register_to_from(self, register_to, register_from):
-        self._code.append(self.translate('mov %s,%s' % (register_to, register_from)))
-
-    def call(self, register):
-        self._code.append(self.translate('call %s' % register))
-
-    def preserve_stack(self):
-        self.mov_register_to_from('ebp', 'esp')
-        return AutoExit(lambda: self.restore_stack())
-
-    def restore_stack(self):
-        self.mov_register_to_from('esp', 'ebp')
-
-    def ret(self):
-        self._code.append(self.translate('ret'))
-
-    def get_code(self):
-        from winappdbg import compat
-        return compat.b('').join(self._code)
-
-    def translate(self, code):
-        return self._translations[code]
-
-    def pack_address(self, address):
-        if self.is_64:
-            return struct.pack('<q', address)
-        else:
-            return struct.pack('<L', address)
-
-    def convert(self, code):
-        '''
-        Note:
-
-        If the shellcode starts with '66' controls, it needs to be changed to add [BITS 32] or
-        [BITS 64] to the start.
-
-        To use:
-
-        convert("""
-            55
-            53
-            50
-            BDE97F071E
-            FFD5
-            BDD67B071E
-            FFD5
-            5D
-            5B
-            58
-            C3
-            """)
-        '''
-        code = code.replace(' ', '')
-        lines = []
-        for l in code.splitlines(False):
-            lines.append(l)
-        code = ''.join(lines)  # Remove new lines
-        return code.decode('hex')
-
-def resolve_label(process, label):
-    for i in range(3):
-        try:
-            address = process.resolve_label(label)
-            assert address
-            return address
-        except:
-            try:
-                process.scan_modules()
-            except:
-                pass
-            if i == 2:
-                raise
-            time.sleep(2)
-
-def is_python_64bit():
-    return (struct.calcsize('P') == 8)
-
-def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
-    assert '\'' not in python_code, 'Having a single quote messes with our command.'
-    from winappdbg import compat
-    from winappdbg.process import Process
-    if not isinstance(python_code, compat.bytes):
-        python_code = compat.b(python_code)
-
-    process = Process(pid)
-    bits = process.get_bits()
-    is_64 = bits == 64
-
-    if is_64 != is_python_64bit():
-        raise RuntimeError("The architecture of the Python used to connect doesn't match the architecture of the target.\n"
-        "Target 64 bits: %s\n"
-        "Current Python 64 bits: %s" % (is_64, is_python_64bit()))
-
-    print('Connecting to %s bits target' % (bits,))
-    assert resolve_label(process, compat.b('PyGILState_Ensure'))
-
-
-    filedir = os.path.dirname(__file__)
-    if is_64:
-        suffix = 'amd64'
-    else:
-        suffix = 'x86'
-    target_dll = os.path.join(filedir, 'attach_%s.dll' % suffix)
-    if not os.path.exists(target_dll):
-        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
-    print('Injecting dll')
-    process.inject_dll(target_dll.encode('mbcs'))
-    print('Dll injected')
-
-    process.scan_modules()
-    attach_func = resolve_label(process, compat.b('AttachAndRunPythonCode'))
-    assert attach_func
-
-    print('Allocating code in target process')
-    code_address = process.malloc(len(python_code))
-    assert code_address
-    print('Writing code in target process')
-    process.write(code_address, python_code)
-
-    print('Allocating return value memory in target process')
-    return_code_address = process.malloc(ctypes.sizeof(ctypes.c_int))
-    assert return_code_address
-
-    CONNECT_DEBUGGER = 2
-
-    startup_info = 0
-    if show_debug_info:
-        SHOW_DEBUG_INFO = 1
-        startup_info |= SHOW_DEBUG_INFO # Uncomment to show debug info
-
-    if connect_debugger_tracing:
-        startup_info |= CONNECT_DEBUGGER
-
-    process.write_int(return_code_address, startup_info)
-
-    helper = GenShellCodeHelper(is_64)
-    if is_64:
-        # Interesting read: http://msdn.microsoft.com/en-us/library/ms235286.aspx
-        # Overview of x64 Calling Conventions (for windows: Linux is different!)
-        # Register Usage: http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
-        # The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile and must be considered destroyed on function calls (unless otherwise safety-provable by analysis such as whole program optimization).
-        #
-        # The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.
-        #
-        # Important: RCX: first int argument
-
-        with helper.push('rdi'):  # This one REALLY must be pushed/poped
-            with helper.push('rsp'):
-                with helper.push('rbp'):
-                    with helper.push('rbx'):
-
-                        with helper.push('rdi'):  # Note: pop is automatic.
-                            helper.mov_to_register_addr('rcx', helper.pack_address(code_address))
-                            helper.mov_to_register_addr('rdx', helper.pack_address(return_code_address))
-                            helper.mov_to_register_addr('rbx', helper.pack_address(attach_func))
-                            helper.call('rbx')
-
-    else:
-        with helper.push('eax'):  # Note: pop is automatic.
-            with helper.push('ebp'):
-                with helper.push('ebx'):
-
-                    with helper.preserve_stack():
-                        # Put our code as a parameter in the stack (on x86, we push parameters to
-                        # the stack)
-                        helper.push_addr(helper.pack_address(return_code_address))
-                        helper.push_addr(helper.pack_address(code_address))
-                        helper.mov_to_register_addr('ebx', helper.pack_address(attach_func))
-                        helper.call('ebx')
-
-    helper.ret()
-
-    code = helper.get_code()
-
-
-    # Uncomment to see the disassembled version of what we just did...
-#     with open('f.asm', 'wb') as stream:
-#         stream.write(code)
-#
-#     exe = r'x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe'
-#     if is_64:
-#         arch = '64'
-#     else:
-#         arch = '32'
-#
-#     subprocess.call((exe + ' -b %s f.asm' % arch).split())
-
-    print('Injecting code to target process')
-    thread, _thread_address = process.inject_code(code, 0)
-
-    timeout = None  # Could receive timeout in millis.
-    print('Waiting for code to complete')
-    thread.wait(timeout)
-
-    return_code = process.read_int(return_code_address)
-    if return_code == 0:
-        print('Attach finished successfully.')
-    else:
-        print('Error when injecting code in target process. Error code: %s (on windows)' % (return_code,))
-
-    process.free(thread.pInjectedMemory)
-    process.free(code_address)
-    process.free(return_code_address)
-    return return_code
-
-
-def run_python_code_linux(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
-    assert '\'' not in python_code, 'Having a single quote messes with our command.'
-    filedir = os.path.dirname(__file__)
-    
-    # Valid arguments for arch are i386, i386:x86-64, i386:x64-32, i8086,
-    #   i386:intel, i386:x86-64:intel, i386:x64-32:intel, i386:nacl,
-    #   i386:x86-64:nacl, i386:x64-32:nacl, auto.
-    
-    if is_python_64bit():
-        suffix = 'amd64'
-        arch = 'i386:x86-64'
-    else:
-        suffix = 'x86'
-        arch = 'i386'
-
-    print('Attaching with arch: %s'% (arch,))
-        
-    target_dll = os.path.join(filedir, 'attach_linux_%s.so' % suffix)
-    target_dll = os.path.normpath(target_dll)
-    if not os.path.exists(target_dll):
-        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
-
-    gdb_threads_settrace_file = os.path.join(filedir, 'linux', 'gdb_threads_settrace.py')
-    gdb_threads_settrace_file = os.path.normpath(gdb_threads_settrace_file)
-    if not os.path.exists(gdb_threads_settrace_file):
-        raise RuntimeError('Could not find file to settrace: %s' % gdb_threads_settrace_file)
-
-    # Note: we currently don't support debug builds 
-    is_debug = 0
-    # Note that the space in the beginning of each line in the multi-line is important!
-    cmd = [
-        'gdb',
-        '--nw',  # no gui interface
-        '--nh',  # no ~/.gdbinit
-        '--nx',  # no .gdbinit
-#         '--quiet',  # no version number on startup
-        '--pid',
-        str(pid),
-        '--batch',
-#         '--batch-silent',
-    ]
-
-    cmd.extend(["--eval-command='set scheduler-locking off'"])  # If on we'll deadlock.
-
-    cmd.extend(["--eval-command='set architecture %s'" % arch])
-
-    cmd.extend([
-        "--eval-command='call dlopen(\"%s\", 2)'" % target_dll,
-        "--eval-command='call DoAttach(%s, \"%s\", %s)'" % (
-            is_debug, python_code, show_debug_info)
-    ])
-    
-
-    if connect_debugger_tracing:
-        cmd.extend([
-            "--command='%s'" % (gdb_threads_settrace_file,),
-        ])
-
-    #print ' '.join(cmd)
-
-    env = os.environ.copy()
-    # Remove the PYTHONPATH (if gdb has a builtin Python it could fail if we
-    # have the PYTHONPATH for a different python version or some forced encoding).
-    env.pop('PYTHONIOENCODING', None)
-    env.pop('PYTHONPATH', None)
-    print('Running: %s' % (' '.join(cmd)))
-    p = subprocess.Popen(
-        ' '.join(cmd),
-        shell=True,
-        env=env,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE,
-    )
-    print('Running gdb in target process.')
-    out, err = p.communicate()
-    print('stdout: %s' % (out,))
-    print('stderr: %s' % (err,))
-    return out, err
-
-
-if sys.platform == 'win32':
-    run_python_code = run_python_code_windows
-else:
-    run_python_code = run_python_code_linux
-
-def test():
-    print('Running with: %s' % (sys.executable,))
-    code = '''
-import os, time, sys
-print(os.getpid())
-#from threading import Thread
-#Thread(target=str).start()
-if __name__ == '__main__':
-    while True:
-        time.sleep(.5)
-        sys.stdout.write('.\\n')
-        sys.stdout.flush()
-'''
-
-    p = subprocess.Popen([sys.executable, '-u', '-c', code])
-    try:
-        code = 'print("It worked!")\n'
-
-        # Real code will be something as:
-        # code = '''import sys;sys.path.append(r'X:\winappdbg-code\examples'); import imported;'''
-        run_python_code(p.pid, python_code=code)
-
-        time.sleep(3)
-    finally:
-        p.kill()
-
-def main(args):
-    # Otherwise, assume the first parameter is the pid and anything else is code to be executed
-    # in the target process.
-    pid = int(args[0])
-    del args[0]
-    python_code = ';'.join(args)
-
-    # Note: on Linux the python code may not have a single quote char: '
-    run_python_code(pid, python_code)
-
-if __name__ == '__main__':
-    args = sys.argv[1:]
-    if not args:
-        print('Expected pid and Python code to execute in target process.')
-    else:
-        if '--test' == args[0]:
-            test()
-        else:
-            main(args)
-
-
+r'''
+Copyright: Brainwy Software Ltda.
+
+License: EPL.
+=============
+
+Works for Windows relying on a fork of winappdbg which works in py2/3 (at least for the part we're interested in).
+
+See: https://github.com/fabioz/winappdbg (py3 branch).
+Note that the official branch for winappdbg is: https://github.com/MarioVilas/winappdbg, which should be used when it works in Py3.
+A private copy is added here to make deployment easier, but changes should always be done upstream first.
+
+Works for Linux relying on gdb.
+
+Limitations:
+============
+
+    Linux:
+    ------
+
+        1. It possible that ptrace is disabled: /etc/sysctl.d/10-ptrace.conf
+
+        Note that even enabling it in /etc/sysctl.d/10-ptrace.conf (i.e.: making the
+        ptrace_scope=0), it's possible that we need to run the application that'll use ptrace (or
+        gdb in this case) as root (so, we must sudo the python which'll run this module).
+
+        2. It currently doesn't work in debug builds (i.e.: python_d)
+
+
+Other implementations:
+- pyrasite.com:
+    GPL
+    Windows/linux (in Linux it also uses gdb to connect -- although specifics are different as we use a dll to execute
+    code with other threads stopped). It's Windows approach is more limited because it doesn't seem to deal properly with 
+    Python 3 if threading is disabled. 
+
+- https://github.com/google/pyringe:
+    Apache v2.
+    Only linux/Python 2.
+
+- http://pytools.codeplex.com:
+    Apache V2
+    Windows Only (but supports mixed mode debugging)
+    Our own code relies heavily on a part of it: http://pytools.codeplex.com/SourceControl/latest#Python/Product/PyDebugAttach/PyDebugAttach.cpp
+    to overcome some limitations of attaching and running code in the target python executable on Python 3.
+    See: attach.cpp
+
+Linux: References if we wanted to use a pure-python debugger:
+    https://bitbucket.org/haypo/python-ptrace/
+    http://stackoverflow.com/questions/7841573/how-to-get-an-error-message-for-errno-value-in-python
+    Jugaad:
+        https://www.defcon.org/images/defcon-19/dc-19-presentations/Jakhar/DEFCON-19-Jakhar-Jugaad-Linux-Thread-Injection.pdf
+        https://github.com/aseemjakhar/jugaad
+
+Something else (general and not Python related):
+- http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
+
+Other references:
+- https://github.com/haypo/faulthandler
+- http://nedbatchelder.com/text/trace-function.html
+- https://github.com/python-git/python/blob/master/Python/sysmodule.c (sys_settrace)
+- https://github.com/python-git/python/blob/master/Python/ceval.c (PyEval_SetTrace)
+- https://github.com/python-git/python/blob/master/Python/thread.c (PyThread_get_key_value)
+
+
+To build the dlls needed on windows, visual studio express 13 was used (see compile_dll.bat)
+
+See: attach_pydevd.py to attach the pydev debugger to a running python process.
+'''
+
+# Note: to work with nasm compiling asm to code and decompiling to see asm with shellcode:
+# x:\nasm\nasm-2.07-win32\nasm-2.07\nasm.exe
+# nasm.asm&x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe -b arch nasm
+import ctypes
+import os
+import struct
+import subprocess
+import sys
+import time
+
+class AutoExit(object):
+
+    def __init__(self, on_exit):
+        self.on_exit = on_exit
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, *args):
+        self.on_exit()
+
+
+class GenShellCodeHelper(object):
+
+    def __init__(self, is_64):
+        from winappdbg import compat
+        self.is_64 = is_64
+        self._code = []
+        if not is_64:
+            self._translations = {
+                'push esi': compat.b('\x56'),
+                'push eax': compat.b('\x50'),
+                'push ebp': compat.b('\x55'),
+                'push ebx': compat.b('\x53'),
+
+                'pop esi': compat.b('\x5E'),
+                'pop eax': compat.b('\x58'),
+                'pop ebp': compat.b('\x5D'),
+                'pop ebx': compat.b('\x5B'),
+
+                'mov esi': compat.b('\xBE'),
+                'mov eax': compat.b('\xB8'),
+                'mov ebp': compat.b('\xBD'),
+                'mov ebx': compat.b('\xBB'),
+
+                'call ebp': compat.b('\xFF\xD5'),
+                'call eax': compat.b('\xFF\xD0'),
+                'call ebx': compat.b('\xFF\xD3'),
+
+                'mov ebx,eax': compat.b('\x89\xC3'),
+                'mov eax,ebx': compat.b('\x89\xD8'),
+                'mov ebp,esp': compat.b('\x89\xE5'),
+                'mov esp,ebp': compat.b('\x89\xEC'),
+                'push dword': compat.b('\x68'),
+
+                'mov ebp,eax': compat.b('\x89\xC5'),
+                'mov eax,ebp': compat.b('\x89\xE8'),
+
+                'ret': compat.b('\xc3'),
+            }
+        else:
+            # Translate 64 bits
+            self._translations = {
+                'push rsi': compat.b('\x56'),
+                'push rax': compat.b('\x50'),
+                'push rbp': compat.b('\x55'),
+                'push rbx': compat.b('\x53'),
+                'push rsp': compat.b('\x54'),
+                'push rdi': compat.b('\x57'),
+
+                'pop rsi': compat.b('\x5E'),
+                'pop rax': compat.b('\x58'),
+                'pop rbp': compat.b('\x5D'),
+                'pop rbx': compat.b('\x5B'),
+                'pop rsp': compat.b('\x5C'),
+                'pop rdi': compat.b('\x5F'),
+
+                'mov rsi': compat.b('\x48\xBE'),
+                'mov rax': compat.b('\x48\xB8'),
+                'mov rbp': compat.b('\x48\xBD'),
+                'mov rbx': compat.b('\x48\xBB'),
+                'mov rdi': compat.b('\x48\xBF'),
+                'mov rcx': compat.b('\x48\xB9'),
+                'mov rdx': compat.b('\x48\xBA'),
+
+                'call rbp': compat.b('\xFF\xD5'),
+                'call rax': compat.b('\xFF\xD0'),
+                'call rbx': compat.b('\xFF\xD3'),
+
+                'mov rbx,rax': compat.b('\x48\x89\xC3'),
+                'mov rax,rbx': compat.b('\x48\x89\xD8'),
+                'mov rbp,rsp': compat.b('\x48\x89\xE5'),
+                'mov rsp,rbp': compat.b('\x48\x89\xEC'),
+                'mov rcx,rbp': compat.b('\x48\x89\xE9'),
+
+                'mov rbp,rax': compat.b('\x48\x89\xC5'),
+                'mov rax,rbp': compat.b('\x48\x89\xE8'),
+
+                'mov rdi,rbp': compat.b('\x48\x89\xEF'),
+
+                'ret': compat.b('\xc3'),
+            }
+
+    def push_addr(self, addr):
+        self._code.append(self.translate('push dword'))
+        self._code.append(addr)
+
+    def push(self, register):
+        self._code.append(self.translate('push %s' % register))
+        return AutoExit(lambda: self.pop(register))
+
+    def pop(self, register):
+        self._code.append(self.translate('pop %s' % register))
+
+    def mov_to_register_addr(self, register, addr):
+        self._code.append(self.translate('mov %s' % register))
+        self._code.append(addr)
+
+    def mov_register_to_from(self, register_to, register_from):
+        self._code.append(self.translate('mov %s,%s' % (register_to, register_from)))
+
+    def call(self, register):
+        self._code.append(self.translate('call %s' % register))
+
+    def preserve_stack(self):
+        self.mov_register_to_from('ebp', 'esp')
+        return AutoExit(lambda: self.restore_stack())
+
+    def restore_stack(self):
+        self.mov_register_to_from('esp', 'ebp')
+
+    def ret(self):
+        self._code.append(self.translate('ret'))
+
+    def get_code(self):
+        from winappdbg import compat
+        return compat.b('').join(self._code)
+
+    def translate(self, code):
+        return self._translations[code]
+
+    def pack_address(self, address):
+        if self.is_64:
+            return struct.pack('<q', address)
+        else:
+            return struct.pack('<L', address)
+
+    def convert(self, code):
+        '''
+        Note:
+
+        If the shellcode starts with '66' controls, it needs to be changed to add [BITS 32] or
+        [BITS 64] to the start.
+
+        To use:
+
+        convert("""
+            55
+            53
+            50
+            BDE97F071E
+            FFD5
+            BDD67B071E
+            FFD5
+            5D
+            5B
+            58
+            C3
+            """)
+        '''
+        code = code.replace(' ', '')
+        lines = []
+        for l in code.splitlines(False):
+            lines.append(l)
+        code = ''.join(lines)  # Remove new lines
+        return code.decode('hex')
+
+def resolve_label(process, label):
+    for i in range(3):
+        try:
+            address = process.resolve_label(label)
+            assert address
+            return address
+        except:
+            try:
+                process.scan_modules()
+            except:
+                pass
+            if i == 2:
+                raise
+            time.sleep(2)
+
+def is_python_64bit():
+    return (struct.calcsize('P') == 8)
+
+def is_mac():
+    import platform
+    return platform.system() == 'Darwin'
+
+def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
+    assert '\'' not in python_code, 'Having a single quote messes with our command.'
+    from winappdbg import compat
+    from winappdbg.process import Process
+    if not isinstance(python_code, compat.bytes):
+        python_code = compat.b(python_code)
+
+    process = Process(pid)
+    bits = process.get_bits()
+    is_64 = bits == 64
+
+    if is_64 != is_python_64bit():
+        raise RuntimeError("The architecture of the Python used to connect doesn't match the architecture of the target.\n"
+        "Target 64 bits: %s\n"
+        "Current Python 64 bits: %s" % (is_64, is_python_64bit()))
+
+    print('Connecting to %s bits target' % (bits,))
+    assert resolve_label(process, compat.b('PyGILState_Ensure'))
+
+
+    filedir = os.path.dirname(__file__)
+    if is_64:
+        suffix = 'amd64'
+    else:
+        suffix = 'x86'
+    target_dll = os.path.join(filedir, 'attach_%s.dll' % suffix)
+    if not os.path.exists(target_dll):
+        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
+    print('Injecting dll')
+    process.inject_dll(target_dll.encode('mbcs'))
+    print('Dll injected')
+
+    process.scan_modules()
+    attach_func = resolve_label(process, compat.b('AttachAndRunPythonCode'))
+    assert attach_func
+
+    print('Allocating code in target process')
+    code_address = process.malloc(len(python_code))
+    assert code_address
+    print('Writing code in target process')
+    process.write(code_address, python_code)
+
+    print('Allocating return value memory in target process')
+    return_code_address = process.malloc(ctypes.sizeof(ctypes.c_int))
+    assert return_code_address
+
+    CONNECT_DEBUGGER = 2
+
+    startup_info = 0
+    if show_debug_info:
+        SHOW_DEBUG_INFO = 1
+        startup_info |= SHOW_DEBUG_INFO # Uncomment to show debug info
+
+    if connect_debugger_tracing:
+        startup_info |= CONNECT_DEBUGGER
+
+    process.write_int(return_code_address, startup_info)
+
+    helper = GenShellCodeHelper(is_64)
+    if is_64:
+        # Interesting read: http://msdn.microsoft.com/en-us/library/ms235286.aspx
+        # Overview of x64 Calling Conventions (for windows: Linux is different!)
+        # Register Usage: http://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
+        # The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile and must be considered destroyed on function calls (unless otherwise safety-provable by analysis such as whole program optimization).
+        #
+        # The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile and must be saved and restored by a function that uses them.
+        #
+        # Important: RCX: first int argument
+
+        with helper.push('rdi'):  # This one REALLY must be pushed/poped
+            with helper.push('rsp'):
+                with helper.push('rbp'):
+                    with helper.push('rbx'):
+
+                        with helper.push('rdi'):  # Note: pop is automatic.
+                            helper.mov_to_register_addr('rcx', helper.pack_address(code_address))
+                            helper.mov_to_register_addr('rdx', helper.pack_address(return_code_address))
+                            helper.mov_to_register_addr('rbx', helper.pack_address(attach_func))
+                            helper.call('rbx')
+
+    else:
+        with helper.push('eax'):  # Note: pop is automatic.
+            with helper.push('ebp'):
+                with helper.push('ebx'):
+
+                    with helper.preserve_stack():
+                        # Put our code as a parameter in the stack (on x86, we push parameters to
+                        # the stack)
+                        helper.push_addr(helper.pack_address(return_code_address))
+                        helper.push_addr(helper.pack_address(code_address))
+                        helper.mov_to_register_addr('ebx', helper.pack_address(attach_func))
+                        helper.call('ebx')
+
+    helper.ret()
+
+    code = helper.get_code()
+
+
+    # Uncomment to see the disassembled version of what we just did...
+#     with open('f.asm', 'wb') as stream:
+#         stream.write(code)
+#
+#     exe = r'x:\nasm\nasm-2.07-win32\nasm-2.07\ndisasm.exe'
+#     if is_64:
+#         arch = '64'
+#     else:
+#         arch = '32'
+#
+#     subprocess.call((exe + ' -b %s f.asm' % arch).split())
+
+    print('Injecting code to target process')
+    thread, _thread_address = process.inject_code(code, 0)
+
+    timeout = None  # Could receive timeout in millis.
+    print('Waiting for code to complete')
+    thread.wait(timeout)
+
+    return_code = process.read_int(return_code_address)
+    if return_code == 0:
+        print('Attach finished successfully.')
+    else:
+        print('Error when injecting code in target process. Error code: %s (on windows)' % (return_code,))
+
+    process.free(thread.pInjectedMemory)
+    process.free(code_address)
+    process.free(return_code_address)
+    return return_code
+
+
+def run_python_code_linux(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
+    assert '\'' not in python_code, 'Having a single quote messes with our command.'
+    filedir = os.path.dirname(__file__)
+
+    # Valid arguments for arch are i386, i386:x86-64, i386:x64-32, i8086,
+    #   i386:intel, i386:x86-64:intel, i386:x64-32:intel, i386:nacl,
+    #   i386:x86-64:nacl, i386:x64-32:nacl, auto.
+
+    if is_python_64bit():
+        suffix = 'amd64'
+        arch = 'i386:x86-64'
+    else:
+        suffix = 'x86'
+        arch = 'i386'
+
+    print('Attaching with arch: %s'% (arch,))
+
+    target_dll = os.path.join(filedir, 'attach_linux_%s.so' % suffix)
+    target_dll = os.path.normpath(target_dll)
+    if not os.path.exists(target_dll):
+        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
+
+    gdb_threads_settrace_file = find_helper_script(filedir, 'gdb_threads_settrace.py')
+
+    # Note: we currently don't support debug builds 
+    is_debug = 0
+    # Note that the space in the beginning of each line in the multi-line is important!
+    cmd = [
+        'gdb',
+        '--nw',  # no gui interface
+        '--nh',  # no ~/.gdbinit
+        '--nx',  # no .gdbinit
+#         '--quiet',  # no version number on startup
+        '--pid',
+        str(pid),
+        '--batch',
+#         '--batch-silent',
+    ]
+
+    cmd.extend(["--eval-command='set scheduler-locking off'"])  # If on we'll deadlock.
+
+    cmd.extend(["--eval-command='set architecture %s'" % arch])
+
+    cmd.extend([
+        "--eval-command='call dlopen(\"%s\", 2)'" % target_dll,
+        "--eval-command='call DoAttach(%s, \"%s\", %s)'" % (
+            is_debug, python_code, show_debug_info)
+    ])
+
+
+    if connect_debugger_tracing:
+        cmd.extend([
+            "--command='%s'" % (gdb_threads_settrace_file,),
+        ])
+
+    #print ' '.join(cmd)
+
+    env = os.environ.copy()
+    # Remove the PYTHONPATH (if gdb has a builtin Python it could fail if we
+    # have the PYTHONPATH for a different python version or some forced encoding).
+    env.pop('PYTHONIOENCODING', None)
+    env.pop('PYTHONPATH', None)
+    print('Running: %s' % (' '.join(cmd)))
+    p = subprocess.Popen(
+        ' '.join(cmd),
+        shell=True,
+        env=env,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+    )
+    print('Running gdb in target process.')
+    out, err = p.communicate()
+    print('stdout: %s' % (out,))
+    print('stderr: %s' % (err,))
+    return out, err
+
+
+def find_helper_script(filedir, script_name):
+    lldb_threads_settrace_file = os.path.join(filedir, 'linux', script_name)
+    lldb_threads_settrace_file = os.path.normpath(lldb_threads_settrace_file)
+    if not os.path.exists(lldb_threads_settrace_file):
+        raise RuntimeError('Could not find file to settrace: %s' % lldb_threads_settrace_file)
+
+    return lldb_threads_settrace_file
+
+
+def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):
+    assert '\'' not in python_code, 'Having a single quote messes with our command.'
+    filedir = os.path.dirname(__file__)
+
+    # Valid arguments for arch are i386, i386:x86-64, i386:x64-32, i8086,
+    #   i386:intel, i386:x86-64:intel, i386:x64-32:intel, i386:nacl,
+    #   i386:x86-64:nacl, i386:x64-32:nacl, auto.
+
+    if is_python_64bit():
+        suffix = 'x86_64.dylib'
+        arch = 'i386:x86-64'
+    else:
+        suffix = 'x86.dylib'
+        arch = 'i386'
+
+    print('Attaching with arch: %s'% (arch,))
+
+    target_dll = os.path.join(filedir, 'attach_%s' % suffix)
+    target_dll = os.path.normpath(target_dll)
+    if not os.path.exists(target_dll):
+        raise RuntimeError('Could not find dll file to inject: %s' % target_dll)
+
+    lldb_threads_settrace_file = find_helper_script(filedir, 'lldb_threads_settrace.py')
+    lldb_prepare_file = find_helper_script(filedir, 'lldb_prepare.py')
+    # Note: we currently don't support debug builds
+
+    is_debug = 0
+    # Note that the space in the beginning of each line in the multi-line is important!
+    cmd = [
+        'lldb',
+        '--no-lldbinit',  # Do not automatically parse any '.lldbinit' files.
+        # '--attach-pid',
+        # str(pid),
+        # '--arch',
+        # arch,
+        '--script-language',
+        'Python'
+        #         '--batch-silent',
+    ]
+
+
+    cmd.extend([
+        "-o 'process attach --pid %d'"%pid,
+        "-o 'command script import \"%s\"'" % (lldb_prepare_file,),
+        "-o 'load_lib_and_attach \"%s\" %s \"%s\" %s'" % (target_dll,
+            is_debug, python_code, show_debug_info),
+    ])
+
+
+    if connect_debugger_tracing:
+        cmd.extend([
+            # "-o 'expr (int) SetSysTraceFunc(0, 0);'",
+            "-o 'command script import \"%s\"'" % (lldb_threads_settrace_file,),
+            ])
+
+    cmd.extend([
+        "-o 'process detach'",
+        "-o 'script import os; os._exit(1)'",
+    ])
+
+    #print ' '.join(cmd)
+
+    env = os.environ.copy()
+    # Remove the PYTHONPATH (if gdb has a builtin Python it could fail if we
+    # have the PYTHONPATH for a different python version or some forced encoding).
+    env.pop('PYTHONIOENCODING', None)
+    env.pop('PYTHONPATH', None)
+    print('Running: %s' % (' '.join(cmd)))
+    p = subprocess.Popen(
+        ' '.join(cmd),
+        shell=True,
+        env=env,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        )
+    print('Running lldb in target process.')
+    out, err = p.communicate()
+    print('stdout: %s' % (out,))
+    print('stderr: %s' % (err,))
+    return out, err
+
+
+if sys.platform == 'win32':
+    run_python_code = run_python_code_windows
+elif is_mac():
+    run_python_code = run_python_code_mac
+else:
+    run_python_code = run_python_code_linux
+
+def test():
+    print('Running with: %s' % (sys.executable,))
+    code = '''
+import os, time, sys
+print(os.getpid())
+#from threading import Thread
+#Thread(target=str).start()
+if __name__ == '__main__':
+    while True:
+        time.sleep(.5)
+        sys.stdout.write('.\\n')
+        sys.stdout.flush()
+'''
+
+    p = subprocess.Popen([sys.executable, '-u', '-c', code])
+    try:
+        code = 'print("It worked!")\n'
+
+        # Real code will be something as:
+        # code = '''import sys;sys.path.append(r'X:\winappdbg-code\examples'); import imported;'''
+        run_python_code(p.pid, python_code=code)
+
+        time.sleep(3)
+    finally:
+        p.kill()
+
+def main(args):
+    # Otherwise, assume the first parameter is the pid and anything else is code to be executed
+    # in the target process.
+    pid = int(args[0])
+    del args[0]
+    python_code = ';'.join(args)
+
+    # Note: on Linux the python code may not have a single quote char: '
+    run_python_code(pid, python_code)
+
+if __name__ == '__main__':
+    args = sys.argv[1:]
+    if not args:
+        print('Expected pid and Python code to execute in target process.')
+    else:
+        if '--test' == args[0]:
+            test()
+        else:
+            main(args)
+
+
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_script.py b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_script.py
index 163c50f..fb2ecc2 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_script.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_script.py
@@ -8,6 +8,8 @@ def attach(port, host):
         pydevd.settrace(
             port=port,
             host=host,
+            stdoutToServer=True,
+            stderrToServer=True,
             overwrite_prev_trace=True,
             suspend=False,
             trace_only_current_thread=False,
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86.dylib b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86.dylib
new file mode 100644
index 0000000..ffa9f1d
Binary files /dev/null and b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86.dylib differ
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86_64.dylib b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86_64.dylib
new file mode 100644
index 0000000..60e0741
Binary files /dev/null and b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/attach_x86_64.dylib differ
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/Makefile b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/Makefile
new file mode 100644
index 0000000..aedfe16
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/Makefile
@@ -0,0 +1,64 @@
+# Defaults which can be overridden.
+OS = macosx
+ARCH_X86 = x86
+ARCH_X86_64 = x86_64
+
+CC=g++
+LD=libtool
+CPPFLAGS = -I.
+CFLAGS +=-fPIC -D_REENTRANT -nostartfiles
+
+ARCH_FLAG_X86 = -arch i386
+ARCH_FLAG_X86_64 = -arch x86_64
+
+INSTALL_DIR_X86 = ../os/$(OS)/$(ARCH_X86)
+INSTALL_DIR_X86_64 = ../os/$(OS)/$(ARCH_X86_64)
+INSTALL_DIR_LINUX_X86 = ../os/$(LINUX)/$(ARCH_X86)
+INSTALL_DIR_LINUX_X86_64 = ../os/$(LINUX)/$(ARCH_X86_64)
+
+ATTACH = attach_mac.so
+ATTACH_NAME_FULL_X86 = $(INSTALL_DIR_X86)/attach_x86.dylib
+ATTACH_NAME_FULL_X86_64 = $(INSTALL_DIR_X86_64)/attach_x86_64.dylib
+
+OBJS_ATTACH_X86 = attach_linux_$(ARCH_X86).o
+OBJS_ATTACH_X86_64 = attach_linux_$(ARCH_X86_64).o
+
+OBJS_X86 = $(OBJS_ATTACH_X86)
+OBJS_X86_64 = $(OBJS_ATTACH_X86_64)
+
+all: x86 x86_64
+
+x86: $(ATTACH_NAME_FULL_X86)
+
+x86_64: $(ATTACH_NAME_FULL_X86_64)
+
+linux_x86: $(ATTACH_NAME_FULL_LINUX_X86)
+linux_x86_64: $(ATTACH_NAME_FULL_LINUX_X86_64)
+
+rebuild: clean all
+
+$(ATTACH_NAME_FULL_X86): $(OBJS_ATTACH_X86)
+	mkdir -p $(INSTALL_DIR_X86)
+	$(CC) -dynamiclib  $(ARCH_FLAG_X86) -o $(ATTACH_NAME_FULL_X86) $(OBJS_ATTACH_X86) -lc
+
+$(ATTACH_NAME_FULL_X86_64): $(OBJS_ATTACH_X86_64)
+	mkdir -p $(INSTALL_DIR_X86_64)
+	$(CC) -dynamiclib  $(ARCH_FLAG_X86_64) -o $(ATTACH_NAME_FULL_X86_64) $(OBJS_ATTACH_X86_64) -lc
+
+$(ATTACH_NAME_FULL_LINUX_X86): $(OBJS_ATTACH_X86)
+	mkdir -p $(INSTALL_DIR_LINUX_X86)
+	$(CC) -m32 -g -shared -Wl,-soname,$(ATTACH) $(LDFLAGS) -o $(ATTACH_NAME_FULL_LINUX_X86) $(OBJS_ATTACH_X86)
+
+$(ATTACH_NAME_FULL_LINUX_X86_64): $(OBJS_ATTACH_X86_64)
+	mkdir -p $(INSTALL_DIR_LINUX_X86_64)
+	$(CC) -g -shared -Wl,-soname,$(ATTACH) $(LDFLAGS) -o $(ATTACH_NAME_FULL_LINUX_X86_64) $(OBJS_ATTACH_X86_64)
+
+attach_linux_$(ARCH_X86).o: attach_linux.c
+	$(CC) $(CFLAGS) $(ARCH_FLAG_X86) $(CPPFLAGS) -c -o $@ attach_linux.c
+
+attach_linux_$(ARCH_X86_64).o: attach_linux.c
+	$(CC) $(CFLAGS) $(ARCH_FLAG_X86_64) $(CPPFLAGS) -c -o $@ attach_linux.c
+
+clean :
+	$(RM) $(OBJS_X86) $(ATTACH_NAME_FULL_X86)
+	$(RM) $(OBJS_X86_64) $(ATTACH_NAME_FULL_X86_64)
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/attach_linux.c b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/attach_linux.c
index f5e0c2a..46b170f 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/attach_linux.c
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/attach_linux.c
@@ -12,19 +12,22 @@
 
 // Exported function: hello(): Just to print something and check that we've been
 // able to connect.
-extern int hello(void);
+extern "C" int hello(void);
 
 int hello()
 {
     printf("Hello world!\n");
-    void *hndl = dlsym (NULL, "PyGILState_Ensure");
+
+    void *main_hndl = dlopen(NULL, 0x2);
+
+    void *hndl = dlsym (main_hndl, "PyGILState_Ensure");
     if(hndl == NULL){
         printf("NULL\n");
 
     }else{
         printf("Worked (found PyGILState_Ensure)!\n");
-
     }
+
     printf("%d", GetPythonVersion());
 
 
@@ -36,8 +39,8 @@ int hello()
 // which are already running.
 // isDebug is pretty important! Must be true on python debug builds (python_d)
 // If this value is passed wrongly the program will crash.
-extern int SetSysTraceFunc(bool showDebugInfo, bool isDebug);
-extern int DoAttach(bool isDebug, const char *command, bool showDebugInfo);
+extern "C" int SetSysTraceFunc(bool showDebugInfo, bool isDebug);
+extern "C" int DoAttach(bool isDebug, const char *command, bool showDebugInfo);
 
 // Internal function to keep on the tracing
 int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug);
@@ -123,7 +126,8 @@ public:
 int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
 {
     Py_IsInitialized isInitFunc;
-    *(void**)(&isInitFunc) = dlsym(0, "Py_IsInitialized");
+    void *main_hndl = dlopen(NULL, 0x2);
+    *(void**)(&isInitFunc) = dlsym(main_hndl, "Py_IsInitialized");
     CHECK_NULL(isInitFunc, "Py_IsInitialized not found.\n", 1);
 
     if(!isInitFunc()){
@@ -136,7 +140,7 @@ int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
     PythonVersion version = GetPythonVersion();
 
     PyInterpreterState_Head interpHeadFunc;
-    *(void**)(&interpHeadFunc) = dlsym(0, "PyInterpreterState_Head");
+    *(void**)(&interpHeadFunc) = dlsym(main_hndl, "PyInterpreterState_Head");
     CHECK_NULL(interpHeadFunc, "PyInterpreterState_Head not found.\n", 3);
 
     PyInterpreterState* head = interpHeadFunc();
@@ -148,15 +152,15 @@ int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
     // have any more problems.
 
     PyGILState_Ensure pyGilStateEnsureFunc;
-    *(void**)(&pyGilStateEnsureFunc) = dlsym(0, "PyGILState_Ensure");
+    *(void**)(&pyGilStateEnsureFunc) = dlsym(main_hndl, "PyGILState_Ensure");
     CHECK_NULL(pyGilStateEnsureFunc, "PyGILState_Ensure not found.\n", 5);
 
     PyGILState_Release pyGilStateReleaseFunc;
-    *(void**)(&pyGilStateReleaseFunc) = dlsym(0, "PyGILState_Release");
+    *(void**)(&pyGilStateReleaseFunc) = dlsym(main_hndl, "PyGILState_Release");
     CHECK_NULL(pyGilStateReleaseFunc, "PyGILState_Release not found.\n", 6);
 
     PyRun_SimpleString pyRun_SimpleString;
-    *(void**)(&pyRun_SimpleString) = dlsym(0, "PyRun_SimpleString");
+    *(void**)(&pyRun_SimpleString) = dlsym(main_hndl, "PyRun_SimpleString");
     CHECK_NULL(pyRun_SimpleString, "PyRun_SimpleString not found.\n", 6);
 
     PyGILState_STATE pyGILState = pyGilStateEnsureFunc();
@@ -176,7 +180,8 @@ int SetSysTraceFunc(bool showDebugInfo, bool isDebug)
         printf("SetSysTraceFunc started.\n");
     }
     Py_IsInitialized isInitFunc;
-    *(void**)(&isInitFunc) = dlsym(0, "Py_IsInitialized");
+    void *main_hndl = dlopen(NULL, 0x2);
+    *(void**)(&isInitFunc) = dlsym(main_hndl, "Py_IsInitialized");
     CHECK_NULL(isInitFunc, "Py_IsInitialized not found.\n", 1);
 
     if(!isInitFunc()){
@@ -189,18 +194,18 @@ int SetSysTraceFunc(bool showDebugInfo, bool isDebug)
     PythonVersion version = GetPythonVersion();
 
     PyInterpreterState_Head interpHeadFunc;
-    *(void**)(&interpHeadFunc) = dlsym(0, "PyInterpreterState_Head");
+    *(void**)(&interpHeadFunc) = dlsym(main_hndl, "PyInterpreterState_Head");
     CHECK_NULL(interpHeadFunc, "PyInterpreterState_Head not found.\n", 3);
 
     PyInterpreterState* head = interpHeadFunc();
     CHECK_NULL(head, "Interpreter not initialized.\n", 4);
 
     PyGILState_Ensure pyGilStateEnsureFunc;
-    *(void**)(&pyGilStateEnsureFunc) = dlsym(0, "PyGILState_Ensure");
+    *(void**)(&pyGilStateEnsureFunc) = dlsym(main_hndl, "PyGILState_Ensure");
     CHECK_NULL(pyGilStateEnsureFunc, "PyGILState_Ensure not found.\n", 5);
 
     PyGILState_Release pyGilStateReleaseFunc;
-    *(void**)(&pyGilStateReleaseFunc) = dlsym(0, "PyGILState_Release");
+    *(void**)(&pyGilStateReleaseFunc) = dlsym(main_hndl, "PyGILState_Release");
     CHECK_NULL(pyGilStateReleaseFunc, "PyGILState_Release not found.\n", 6);
 
     PyGILState_STATE pyGILState = pyGilStateEnsureFunc();
@@ -213,17 +218,19 @@ int SetSysTraceFunc(bool showDebugInfo, bool isDebug)
 
 int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug){
     PyBool_FromLong boolFromLongFunc;
-    *(void**)(&boolFromLongFunc) = dlsym(0, "PyBool_FromLong");
+    void *main_hndl = dlopen(NULL, 0x2);
+
+    *(void**)(&boolFromLongFunc) = dlsym(main_hndl, "PyBool_FromLong");
     CHECK_NULL(boolFromLongFunc, "PyBool_FromLong not found.\n", 7);
 
     PyObject_HasAttrString pyHasAttrFunc;
-    *(void**)(&pyHasAttrFunc) = dlsym(0, "PyObject_HasAttrString");
+    *(void**)(&pyHasAttrFunc) = dlsym(main_hndl, "PyObject_HasAttrString");
     CHECK_NULL(pyHasAttrFunc, "PyObject_HasAttrString not found.\n", 7);
 
     //Important: we need a non-blocking import here: PyImport_ImportModule
     //could end up crashing (this makes us work only from 2.6 onwards).
     PyImport_ImportModuleNoBlock pyImportModFunc;
-    *(void**)(&pyImportModFunc) = dlsym(0, "PyImport_ImportModuleNoBlock");
+    *(void**)(&pyImportModFunc) = dlsym(main_hndl, "PyImport_ImportModuleNoBlock");
     CHECK_NULL(pyImportModFunc, "PyImport_ImportModuleNoBlock not found.\n", 8);
 
 
@@ -232,14 +239,14 @@ int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug){
 
     if(!pyHasAttrFunc(pydevdTracingMod.ToPython(), "_original_settrace")){
         if(showDebugInfo){
-            printf("pydevd_tracing module has no _original_settrace! ");
+            printf("pydevd_tracing module has no _original_settrace!\n");
         }
         return 8;
     }
 
 
     PyObject_GetAttrString pyGetAttr;
-    *(void**)(&pyGetAttr) = dlsym(0, "PyObject_GetAttrString");
+    *(void**)(&pyGetAttr) = dlsym(main_hndl, "PyObject_GetAttrString");
     CHECK_NULL(pyGetAttr, "PyObject_GetAttrString not found.\n", 8);
 
     auto PyObjectHolder settrace = PyObjectHolder(isDebug, pyGetAttr(pydevdTracingMod.ToPython(), "_original_settrace"));
@@ -252,7 +259,7 @@ int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug){
     CHECK_NULL(getGlobalDebugger.ToPython(), "pydevd.GetGlobalDebugger null.\n", 11);
 
     PyObject_CallFunctionObjArgs call;
-    *(void**)(&call) = dlsym(0, "PyObject_CallFunctionObjArgs");
+    *(void**)(&call) = dlsym(main_hndl, "PyObject_CallFunctionObjArgs");
     CHECK_NULL(call, "PyObject_CallFunctionObjArgs not found.\n", 11);
 
     auto PyObjectHolder globalDbg = PyObjectHolder(isDebug, call(getGlobalDebugger.ToPython(), NULL));
@@ -270,7 +277,7 @@ int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug){
     
     DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
     if(showDebugInfo){
-        printf("sys.settrace(pydevd.GetGlobalDebugger().trace_dispatch) worked.");
+        printf("sys.settrace(pydevd.GetGlobalDebugger().trace_dispatch) worked.\n");
     }
 
     return 0;
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/compile_mac.sh b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/compile_mac.sh
new file mode 100644
index 0000000..635330d
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/compile_mac.sh
@@ -0,0 +1,8 @@
+g++ -fPIC -D_REENTRANT -arch x86_64 I. -c -o attach_linux_x86_64.o attach_linux.c
+g++ -dynamiclib -arch x86_64 -o attach_x86_64.dylib attach_linux_x86_64.o -lc
+
+
+g++ -fPIC -D_REENTRANT -arch i386 -I. -c -o attach_linux_x86.o attach_linux.c
+g++ -dynamiclib -arch i386 -o attach_x86.dylib attach_linux_x86.o -lc
+
+
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_prepare.py b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_prepare.py
new file mode 100644
index 0000000..8a22054
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_prepare.py
@@ -0,0 +1,54 @@
+# This file is meant to be run inside lldb
+# It registers command to load library and invoke attach function
+# Also it marks process threads to to distinguish them from debugger
+# threads later while settings trace in threads
+
+def load_lib_and_attach(debugger, command, result, internal_dict):
+    import shlex
+    args = shlex.split(command)
+
+    dll = args[0]
+    is_debug = args[1]
+    python_code = args[2]
+    show_debug_info = args[3]
+
+    import lldb
+    options = lldb.SBExpressionOptions()
+    options.SetFetchDynamicValue()
+    options.SetTryAllThreads(run_others=False)
+    options.SetTimeoutInMicroSeconds(timeout=10000000)
+
+    print(dll)
+    target = debugger.GetSelectedTarget()
+    res = target.EvaluateExpression("(void*)dlopen(\"%s\", 2);" % (
+        dll), options)
+    error = res.GetError()
+    if error:
+        print(error)
+
+    print(python_code)
+    res = target.EvaluateExpression("(int)DoAttach(%s, \"%s\", %s);" % (
+        is_debug, python_code.replace('"', "'"), show_debug_info), options)
+    error = res.GetError()
+    if error:
+        print(error)
+
+def __lldb_init_module(debugger, internal_dict):
+    import lldb
+
+    debugger.HandleCommand('command script add -f lldb_prepare.load_lib_and_attach load_lib_and_attach')
+
+    try:
+        target = debugger.GetSelectedTarget()
+        if target:
+            process = target.GetProcess()
+            if process:
+                for thread in process:
+                    # print('Marking process thread %d'%thread.GetThreadID())
+                    internal_dict['_thread_%d' % thread.GetThreadID()] = True
+                    # thread.Suspend()
+    except:
+        import traceback;traceback.print_exc()
+
+
+
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_threads_settrace.py b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_threads_settrace.py
new file mode 100644
index 0000000..e6ceb91
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/lldb_threads_settrace.py
@@ -0,0 +1,52 @@
+# This file is meant to be run inside lldb as a command after
+# the attach_linux.dylib dll has already been loaded to settrace for all threads.
+def __lldb_init_module(debugger, internal_dict):
+    # Command Initialization code goes here
+    # print('Startup LLDB in Python!')
+    import lldb
+
+    try:
+        show_debug_info = 1
+        is_debug = 0
+
+        options = lldb.SBExpressionOptions()
+        options.SetFetchDynamicValue()
+        options.SetTryAllThreads(run_others=False)
+        options.SetTimeoutInMicroSeconds(timeout=10000000)
+
+        target = debugger.GetSelectedTarget()
+        if target:
+            process = target.GetProcess()
+            if process:
+                for thread in process:
+                    # Get the first frame
+                    # print('Thread %s, suspended %s\n'%(thread, thread.IsStopped()))
+
+                    if internal_dict.get('_thread_%d' % thread.GetThreadID(), False):
+                        process.SetSelectedThread(thread)
+                        if not thread.IsStopped():
+                            # thread.Suspend()
+                            error = process.Stop()
+
+                        frame = thread.GetSelectedFrame()
+
+                        if frame.GetFunctionName() == '__select':
+                            # print('We are in __select')
+                            # Step over select, otherwise evaluating expression there can terminate thread
+                            thread.StepOver()
+                            frame = thread.GetSelectedFrame()
+
+                        print('Will settrace in: %s' % (frame,))
+
+                        for f in thread:
+                            print(f)
+
+                        res = frame.EvaluateExpression("(int) SetSysTraceFunc(%s, %s)" % (
+                            show_debug_info, is_debug), options)
+                        error = res.GetError()
+                        if error:
+                            print(error)
+
+                        thread.Resume()
+    except:
+        import traceback;traceback.print_exc()
diff --git a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/python.h b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/python.h
index 2c9b86a..93bfe6e 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/python.h
+++ b/plugins/org.python.pydev/pysrc/pydevd_attach_to_process/linux/python.h
@@ -1,575 +1,576 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * vspython at microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- * ***************************************************************************/
-
-#ifndef __PYTHON_H__
-#define __PYTHON_H__
-#include <string.h>
-
-// must be kept in sync with PythonLanguageVersion.cs
-enum PythonVersion {
-    PythonVersion_Unknown,
-    PythonVersion_25 = 0x0205,
-    PythonVersion_26 = 0x0206,
-    PythonVersion_27 = 0x0207,
-    PythonVersion_30 = 0x0300,
-    PythonVersion_31 = 0x0301,
-    PythonVersion_32 = 0x0302,
-    PythonVersion_33 = 0x0303,
-    PythonVersion_34 = 0x0304
-};
-
-
-// defines limited header of Python API for compatible access across a number of Pythons.
-
-class PyTypeObject;
-class PyThreadState;
-
-#define PyObject_HEAD           \
-    size_t ob_refcnt;           \
-    PyTypeObject *ob_type;
-
-#define PyObject_VAR_HEAD       \
-    PyObject_HEAD               \
-    size_t ob_size; /* Number of items in variable part */
-
-class PyObject {
-public:
-    PyObject_HEAD
-};
-
-class PyVarObject : public PyObject {
-public:
-    size_t ob_size; /* Number of items in variable part */
-};
-
-// 2.4 - 2.7 compatible
-class PyCodeObject25_27 : public PyObject {
-public:
-    int co_argcount;        /* #arguments, except *args */
-    int co_nlocals;         /* #local variables */
-    int co_stacksize;       /* #entries needed for evaluation stack */
-    int co_flags;           /* CO_..., see below */
-    PyObject *co_code;      /* instruction opcodes */
-    PyObject *co_consts;    /* list (constants used) */
-    PyObject *co_names;     /* list of strings (names used) */
-    PyObject *co_varnames;  /* tuple of strings (local variable names) */
-    PyObject *co_freevars;  /* tuple of strings (free variable names) */
-    PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
-    /* The rest doesn't count for hash/cmp */
-    PyObject *co_filename;  /* string (where it was loaded from) */
-    PyObject *co_name;      /* string (name, for reference) */
-    int co_firstlineno;     /* first source line number */
-    PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
-
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version >= PythonVersion_25 && version <= PythonVersion_27;
-    }
-};
-
-// 3.0-3.2
-class PyCodeObject30_32 : public PyObject {
-public:
-    int co_argcount;        /* #arguments, except *args */
-    int co_kwonlyargcount;  /* #keyword only arguments */
-    int co_nlocals;         /* #local variables */
-    int co_stacksize;       /* #entries needed for evaluation stack */
-    int co_flags;           /* CO_..., see below */
-    PyObject *co_code;      /* instruction opcodes */
-    PyObject *co_consts;    /* list (constants used) */
-    PyObject *co_names;     /* list of strings (names used) */
-    PyObject *co_varnames;  /* tuple of strings (local variable names) */
-    PyObject *co_freevars;  /* tuple of strings (free variable names) */
-    PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
-    /* The rest doesn't count for hash or comparisons */
-    PyObject *co_filename;  /* unicode (where it was loaded from) */
-    PyObject *co_name;      /* unicode (name, for reference) */
-    int co_firstlineno;     /* first source line number */
-    PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
-    void *co_zombieframe;   /* for optimization only (see frameobject.c) */
-
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 2);
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version >= PythonVersion_30 && version <= PythonVersion_32;
-    }
-};
-
-// 3.3-3.4
-class PyCodeObject33_34 : public PyObject {
-public:
-    int co_argcount;            /* #arguments, except *args */
-    int co_kwonlyargcount;      /* #keyword only arguments */
-    int co_nlocals;             /* #local variables */
-    int co_stacksize;           /* #entries needed for evaluation stack */
-    int co_flags;               /* CO_..., see below */
-    PyObject *co_code;          /* instruction opcodes */
-    PyObject *co_consts;        /* list (constants used) */
-    PyObject *co_names;         /* list of strings (names used) */
-    PyObject *co_varnames;      /* tuple of strings (local variable names) */
-    PyObject *co_freevars;      /* tuple of strings (free variable names) */
-    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
-    /* The rest doesn't count for hash or comparisons */
-    unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
-    PyObject *co_filename;      /* unicode (where it was loaded from) */
-    PyObject *co_name;          /* unicode (name, for reference) */
-    int co_firstlineno;         /* first source line number */
-    PyObject *co_lnotab;        /* string (encoding addr<->lineno mapping) */
-    void *co_zombieframe;       /* for optimization only (see frameobject.c) */
-
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 3 && (minorVersion >= 3 && minorVersion <= 4);
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version >= PythonVersion_33 && version <= PythonVersion_34;
-    }
-};
-
-// 2.5 - 3.1
-class PyFunctionObject : public PyObject {
-public:
-    PyObject *func_code;    /* A code object */
-};
-
-// 2.5 - 2.7 compatible
-class PyStringObject : public PyVarObject {
-public:
-    long ob_shash;
-    int ob_sstate;
-    char ob_sval[1];
-
-    /* Invariants:
-     *     ob_sval contains space for 'ob_size+1' elements.
-     *     ob_sval[ob_size] == 0.
-     *     ob_shash is the hash of the string or -1 if not computed yet.
-     *     ob_sstate != 0 iff the string object is in stringobject.c's
-     *       'interned' dictionary; in this case the two references
-     *       from 'interned' to this object are *not counted* in ob_refcnt.
-     */
-};
-
-// 2.4 - 3.2 compatible
-typedef struct {
-    PyObject_HEAD
-    size_t length;      /* Length of raw Unicode data in buffer */
-    wchar_t *str;       /* Raw Unicode buffer */
-    long hash;          /* Hash value; -1 if not set */
-} PyUnicodeObject;
-
-// 2.4 - 3.4 compatible
-class PyFrameObject : public PyVarObject {
-public:
-    PyFrameObject *f_back;  /* previous frame, or NULL */
-    PyObject *f_code;           /* code segment */
-    PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
-    PyObject *f_globals;        /* global symbol table (PyDictObject) */
-    PyObject *f_locals;         /* local symbol table (any mapping) */
-    PyObject **f_valuestack;    /* points after the last local */
-    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
-       Frame evaluation usually NULLs it, but a frame that yields sets it
-       to the current stack top. */
-    PyObject **f_stacktop;
-    PyObject *f_trace;          /* Trace function */
-    PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
-};
-
-#define CO_MAXBLOCKS 20
-typedef struct {
-    int b_type;         /* what kind of block this is */
-    int b_handler;      /* where to jump to find handler */
-    int b_level;        /* value stack level to pop to */
-} PyTryBlock;
-
-class PyFrameObject25_33 : public PyFrameObject {
-public:
-    PyThreadState* f_tstate;
-    int f_lasti;                /* Last instruction if called */
-    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
-       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
-    int f_lineno;               /* Current line number */
-    int f_iblock;       /* index in f_blockstack */
-    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
-    PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
-
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7) ||
-            majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
-    }
-};
-
-class PyFrameObject34 : public PyFrameObject {
-public:
-    /* Borrowed reference to a generator, or NULL */
-    PyObject *f_gen;
-
-    int f_lasti;                /* Last instruction if called */
-    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
-       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
-    int f_lineno;               /* Current line number */
-    int f_iblock;       /* index in f_blockstack */
-    char f_executing;           /* whether the frame is still executing */
-    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
-    PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
-
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 3 && minorVersion == 4;
-    }
-};
-
-
-typedef void (*destructor)(PyObject *);
-
-// 2.4 - 3.4
-class PyMethodDef {
-public:
-    char    *ml_name;    /* The name of the built-in function/method */
-};
-
-
-//
-// 2.4 - 3.4, 2.4 has different compat in 64-bit but we don't support any of the released 64-bit platforms (which includes only IA-64)
-// While these are compatible there are fields only available on later versions.
-class PyTypeObject : public PyVarObject {
-public:
-    const char *tp_name; /* For printing, in format "<module>.<name>" */
-    size_t tp_basicsize, tp_itemsize; /* For allocation */
-
-    /* Methods to implement standard operations */
-
-    destructor tp_dealloc;
-    void* tp_print;
-    void* tp_getattr;
-    void* tp_setattr;
-    void* tp_compare;
-    void* tp_repr;
-
-    /* Method suites for standard classes */
-
-    void *tp_as_number;
-    void*tp_as_sequence;
-    void*tp_as_mapping;
-
-    /* More standard operations (here for binary compatibility) */
-
-    void* tp_hash;
-    void* tp_call;
-    void* tp_str;
-    void* tp_getattro;
-    void* tp_setattro;
-
-    /* Functions to access object as input/output buffer */
-    void*tp_as_buffer;
-
-    /* Flags to define presence of optional/expanded features */
-    long tp_flags;
-
-    const char *tp_doc; /* Documentation string */
-
-    /* Assigned meaning in release 2.0 */
-    /* call function for all accessible objects */
-    void*  tp_traverse;
-
-    /* delete references to contained objects */
-    void* tp_clear;
-
-    /* Assigned meaning in release 2.1 */
-    /* rich comparisons */
-    void*  tp_richcompare;
-
-    /* weak reference enabler */
-    size_t tp_weaklistoffset;
-
-    /* Added in release 2.2 */
-    /* Iterators */
-    void*  tp_iter;
-    void*  tp_iternext;
-
-    /* Attribute descriptor and subclassing stuff */
-    PyMethodDef *tp_methods;
-    struct PyMemberDef *tp_members;
-    struct PyGetSetDef *tp_getset;
-    struct _typeobject *tp_base;
-    PyObject *tp_dict;
-    void*  tp_descr_get;
-    void*  tp_descr_set;
-    size_t tp_dictoffset;
-    void* tp_init;
-    void* tp_alloc;
-    void* tp_new;
-    void* tp_free; /* Low-level free-memory routine */
-    void* tp_is_gc; /* For PyObject_IS_GC */
-    PyObject *tp_bases;
-    PyObject *tp_mro; /* method resolution order */
-    PyObject *tp_cache;
-    PyObject *tp_subclasses;
-    PyObject *tp_weaklist;
-    void*  tp_del;
-
-    /* Type attribute cache version tag. Added in version 2.6 */
-    unsigned int tp_version_tag;
-};
-
-// 2.4 - 3.4
-class PyTupleObject : public PyVarObject {
-public:
-    PyObject *ob_item[1];
-
-    /* ob_item contains space for 'ob_size' elements.
-     * Items must normally not be NULL, except during construction when
-     * the tuple is not yet visible outside the function that builds it.
-     */
-};
-
-// 2.4 - 3.4
-class PyCFunctionObject : public PyObject {
-public:
-    PyMethodDef *m_ml;      /* Description of the C function to call */
-    PyObject    *m_self;    /* Passed as 'self' arg to the C func, can be NULL */
-    PyObject    *m_module;  /* The __module__ attribute, can be anything */
-};
-
-typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
-
-#define PyTrace_CALL 0
-#define PyTrace_EXCEPTION 1
-#define PyTrace_LINE 2
-#define PyTrace_RETURN 3
-#define PyTrace_C_CALL 4
-#define PyTrace_C_EXCEPTION 5
-#define PyTrace_C_RETURN 6
-
-class PyInterpreterState {
-};
-
-class PyThreadState { };
-
-class PyThreadState_25_27 : public PyThreadState {
-public:
-    /* See Python/ceval.c for comments explaining most fields */
-
-    PyThreadState *next;
-    PyInterpreterState *interp;
-
-    PyFrameObject *frame;
-    int recursion_depth;
-    /* 'tracing' keeps track of the execution depth when tracing/profiling.
-       This is to prevent the actual trace/profile code from being recorded in
-       the trace/profile. */
-    int tracing;
-    int use_tracing;
-
-    Py_tracefunc c_profilefunc;
-    Py_tracefunc c_tracefunc;
-    PyObject *c_profileobj;
-    PyObject *c_traceobj;
-
-    PyObject *curexc_type;
-    PyObject *curexc_value;
-    PyObject *curexc_traceback;
-
-    PyObject *exc_type;
-    PyObject *exc_value;
-    PyObject *exc_traceback;
-
-    PyObject *dict;  /* Stores per-thread state */
-
-    /* tick_counter is incremented whenever the check_interval ticker
-     * reaches zero. The purpose is to give a useful measure of the number
-     * of interpreted bytecode instructions in a given thread.  This
-     * extremely lightweight statistic collector may be of interest to
-     * profilers (like psyco.jit()), although nothing in the core uses it.
-     */
-    int tick_counter;
-
-    int gilstate_counter;
-
-    PyObject *async_exc; /* Asynchronous exception to raise */
-    long thread_id; /* Thread id where this tstate was created */
-
-    /* XXX signal handlers should also be here */
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version >= PythonVersion_25 && version <= PythonVersion_27;
-    }
-};
-
-class PyThreadState_30_33 : public PyThreadState {
-public:
-    PyThreadState *next;
-    PyInterpreterState *interp;
-
-    PyFrameObject *frame;
-    int recursion_depth;
-    char overflowed; /* The stack has overflowed. Allow 50 more calls
-                        to handle the runtime error. */
-    char recursion_critical; /* The current calls must not cause
-                                a stack overflow. */
-    /* 'tracing' keeps track of the execution depth when tracing/profiling.
-       This is to prevent the actual trace/profile code from being recorded in
-       the trace/profile. */
-    int tracing;
-    int use_tracing;
-
-    Py_tracefunc c_profilefunc;
-    Py_tracefunc c_tracefunc;
-    PyObject *c_profileobj;
-    PyObject *c_traceobj;
-
-    PyObject *curexc_type;
-    PyObject *curexc_value;
-    PyObject *curexc_traceback;
-
-    PyObject *exc_type;
-    PyObject *exc_value;
-    PyObject *exc_traceback;
-
-    PyObject *dict;  /* Stores per-thread state */
-
-    /* tick_counter is incremented whenever the check_interval ticker
-     * reaches zero. The purpose is to give a useful measure of the number
-     * of interpreted bytecode instructions in a given thread.  This
-     * extremely lightweight statistic collector may be of interest to
-     * profilers (like psyco.jit()), although nothing in the core uses it.
-     */
-    int tick_counter;
-
-    int gilstate_counter;
-
-    PyObject *async_exc; /* Asynchronous exception to raise */
-    long thread_id; /* Thread id where this tstate was created */
-
-    /* XXX signal handlers should also be here */
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version >= PythonVersion_30 && version <= PythonVersion_33;
-    }
-};
-
-class PyThreadState_34 : public PyThreadState {
-public:
-    PyThreadState *prev;
-    PyThreadState *next;
-    PyInterpreterState *interp;
-
-    PyFrameObject *frame;
-    int recursion_depth;
-    char overflowed; /* The stack has overflowed. Allow 50 more calls
-                        to handle the runtime error. */
-    char recursion_critical; /* The current calls must not cause
-                                a stack overflow. */
-    /* 'tracing' keeps track of the execution depth when tracing/profiling.
-       This is to prevent the actual trace/profile code from being recorded in
-       the trace/profile. */
-    int tracing;
-    int use_tracing;
-
-    Py_tracefunc c_profilefunc;
-    Py_tracefunc c_tracefunc;
-    PyObject *c_profileobj;
-    PyObject *c_traceobj;
-
-    PyObject *curexc_type;
-    PyObject *curexc_value;
-    PyObject *curexc_traceback;
-
-    PyObject *exc_type;
-    PyObject *exc_value;
-    PyObject *exc_traceback;
-
-    PyObject *dict;  /* Stores per-thread state */
-
-    int gilstate_counter;
-
-    PyObject *async_exc; /* Asynchronous exception to raise */
-    long thread_id; /* Thread id where this tstate was created */
-
-    /* XXX signal handlers should also be here */
-    static bool IsFor(int majorVersion, int minorVersion) {
-        return majorVersion == 3 && minorVersion == 4;
-    }
-
-    static bool IsFor(PythonVersion version) {
-        return version == PythonVersion_34;
-    }
-};
-
-class PyIntObject : public PyObject {
-public:
-    long ob_ival;
-};
-
-//class Py3kLongObject : public PyVarObject {
-//public:
-//    DWORD ob_digit[1];
-//};
-
-class PyOldStyleClassObject : public PyObject {
-public:
-    PyObject *cl_bases; /* A tuple of class objects */
-    PyObject *cl_dict; /* A dictionary */
-    PyObject *cl_name; /* A string */
-    /* The following three are functions or NULL */
-    PyObject *cl_getattr;
-    PyObject *cl_setattr;
-    PyObject *cl_delattr;
-};
-
-class PyInstanceObject : public PyObject {
-public:
-    PyOldStyleClassObject *in_class; /* The class object */
-    PyObject *in_dict; /* A dictionary */
-    PyObject *in_weakreflist; /* List of weak references */
-};
-
-typedef const char* (*GetVersionFunc) ();
-
-static PythonVersion GetPythonVersion() {
-    GetVersionFunc versionFunc;
-    *(void**)(&versionFunc) = dlsym(0, "Py_GetVersion");
-    if(versionFunc != NULL) {
-        const char* version = versionFunc();
-        if(version != NULL && strlen(version) >= 3 && version[1] == '.') {
-            if(version[0] == '2') {
-                switch(version[2]) {
-                case '5': return PythonVersion_25;
-                case '6': return PythonVersion_26;
-                case '7': return PythonVersion_27;
-                }
-            } else if(version[0] == '3') {
-                switch(version[2]) {
-                case '0': return PythonVersion_30;
-                case '1': return PythonVersion_31;
-                case '2': return PythonVersion_32;
-                case '3': return PythonVersion_33;
-                case '4': return PythonVersion_34;
-                }
-            }
-        }
-    }
-    return PythonVersion_Unknown;
-}
-
-#endif
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * vspython at microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ * ***************************************************************************/
+
+#ifndef __PYTHON_H__
+#define __PYTHON_H__
+#include <string.h>
+
+// must be kept in sync with PythonLanguageVersion.cs
+enum PythonVersion {
+    PythonVersion_Unknown,
+    PythonVersion_25 = 0x0205,
+    PythonVersion_26 = 0x0206,
+    PythonVersion_27 = 0x0207,
+    PythonVersion_30 = 0x0300,
+    PythonVersion_31 = 0x0301,
+    PythonVersion_32 = 0x0302,
+    PythonVersion_33 = 0x0303,
+    PythonVersion_34 = 0x0304
+};
+
+
+// defines limited header of Python API for compatible access across a number of Pythons.
+
+class PyTypeObject;
+class PyThreadState;
+
+#define PyObject_HEAD           \
+    size_t ob_refcnt;           \
+    PyTypeObject *ob_type;
+
+#define PyObject_VAR_HEAD       \
+    PyObject_HEAD               \
+    size_t ob_size; /* Number of items in variable part */
+
+class PyObject {
+public:
+    PyObject_HEAD
+};
+
+class PyVarObject : public PyObject {
+public:
+    size_t ob_size; /* Number of items in variable part */
+};
+
+// 2.4 - 2.7 compatible
+class PyCodeObject25_27 : public PyObject {
+public:
+    int co_argcount;        /* #arguments, except *args */
+    int co_nlocals;         /* #local variables */
+    int co_stacksize;       /* #entries needed for evaluation stack */
+    int co_flags;           /* CO_..., see below */
+    PyObject *co_code;      /* instruction opcodes */
+    PyObject *co_consts;    /* list (constants used) */
+    PyObject *co_names;     /* list of strings (names used) */
+    PyObject *co_varnames;  /* tuple of strings (local variable names) */
+    PyObject *co_freevars;  /* tuple of strings (free variable names) */
+    PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
+    /* The rest doesn't count for hash/cmp */
+    PyObject *co_filename;  /* string (where it was loaded from) */
+    PyObject *co_name;      /* string (name, for reference) */
+    int co_firstlineno;     /* first source line number */
+    PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
+
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version >= PythonVersion_25 && version <= PythonVersion_27;
+    }
+};
+
+// 3.0-3.2
+class PyCodeObject30_32 : public PyObject {
+public:
+    int co_argcount;        /* #arguments, except *args */
+    int co_kwonlyargcount;  /* #keyword only arguments */
+    int co_nlocals;         /* #local variables */
+    int co_stacksize;       /* #entries needed for evaluation stack */
+    int co_flags;           /* CO_..., see below */
+    PyObject *co_code;      /* instruction opcodes */
+    PyObject *co_consts;    /* list (constants used) */
+    PyObject *co_names;     /* list of strings (names used) */
+    PyObject *co_varnames;  /* tuple of strings (local variable names) */
+    PyObject *co_freevars;  /* tuple of strings (free variable names) */
+    PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
+    /* The rest doesn't count for hash or comparisons */
+    PyObject *co_filename;  /* unicode (where it was loaded from) */
+    PyObject *co_name;      /* unicode (name, for reference) */
+    int co_firstlineno;     /* first source line number */
+    PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
+    void *co_zombieframe;   /* for optimization only (see frameobject.c) */
+
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 2);
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version >= PythonVersion_30 && version <= PythonVersion_32;
+    }
+};
+
+// 3.3-3.4
+class PyCodeObject33_34 : public PyObject {
+public:
+    int co_argcount;            /* #arguments, except *args */
+    int co_kwonlyargcount;      /* #keyword only arguments */
+    int co_nlocals;             /* #local variables */
+    int co_stacksize;           /* #entries needed for evaluation stack */
+    int co_flags;               /* CO_..., see below */
+    PyObject *co_code;          /* instruction opcodes */
+    PyObject *co_consts;        /* list (constants used) */
+    PyObject *co_names;         /* list of strings (names used) */
+    PyObject *co_varnames;      /* tuple of strings (local variable names) */
+    PyObject *co_freevars;      /* tuple of strings (free variable names) */
+    PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
+    /* The rest doesn't count for hash or comparisons */
+    unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
+    PyObject *co_filename;      /* unicode (where it was loaded from) */
+    PyObject *co_name;          /* unicode (name, for reference) */
+    int co_firstlineno;         /* first source line number */
+    PyObject *co_lnotab;        /* string (encoding addr<->lineno mapping) */
+    void *co_zombieframe;       /* for optimization only (see frameobject.c) */
+
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 3 && (minorVersion >= 3 && minorVersion <= 4);
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version >= PythonVersion_33 && version <= PythonVersion_34;
+    }
+};
+
+// 2.5 - 3.1
+class PyFunctionObject : public PyObject {
+public:
+    PyObject *func_code;    /* A code object */
+};
+
+// 2.5 - 2.7 compatible
+class PyStringObject : public PyVarObject {
+public:
+    long ob_shash;
+    int ob_sstate;
+    char ob_sval[1];
+
+    /* Invariants:
+     *     ob_sval contains space for 'ob_size+1' elements.
+     *     ob_sval[ob_size] == 0.
+     *     ob_shash is the hash of the string or -1 if not computed yet.
+     *     ob_sstate != 0 iff the string object is in stringobject.c's
+     *       'interned' dictionary; in this case the two references
+     *       from 'interned' to this object are *not counted* in ob_refcnt.
+     */
+};
+
+// 2.4 - 3.2 compatible
+typedef struct {
+    PyObject_HEAD
+    size_t length;      /* Length of raw Unicode data in buffer */
+    wchar_t *str;       /* Raw Unicode buffer */
+    long hash;          /* Hash value; -1 if not set */
+} PyUnicodeObject;
+
+// 2.4 - 3.4 compatible
+class PyFrameObject : public PyVarObject {
+public:
+    PyFrameObject *f_back;  /* previous frame, or NULL */
+    PyObject *f_code;           /* code segment */
+    PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
+    PyObject *f_globals;        /* global symbol table (PyDictObject) */
+    PyObject *f_locals;         /* local symbol table (any mapping) */
+    PyObject **f_valuestack;    /* points after the last local */
+    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
+       Frame evaluation usually NULLs it, but a frame that yields sets it
+       to the current stack top. */
+    PyObject **f_stacktop;
+    PyObject *f_trace;          /* Trace function */
+    PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
+};
+
+#define CO_MAXBLOCKS 20
+typedef struct {
+    int b_type;         /* what kind of block this is */
+    int b_handler;      /* where to jump to find handler */
+    int b_level;        /* value stack level to pop to */
+} PyTryBlock;
+
+class PyFrameObject25_33 : public PyFrameObject {
+public:
+    PyThreadState* f_tstate;
+    int f_lasti;                /* Last instruction if called */
+    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
+       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
+    int f_lineno;               /* Current line number */
+    int f_iblock;       /* index in f_blockstack */
+    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
+    PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
+
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7) ||
+            majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
+    }
+};
+
+class PyFrameObject34 : public PyFrameObject {
+public:
+    /* Borrowed reference to a generator, or NULL */
+    PyObject *f_gen;
+
+    int f_lasti;                /* Last instruction if called */
+    /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
+       f_trace is set) -- at other times use PyCode_Addr2Line instead. */
+    int f_lineno;               /* Current line number */
+    int f_iblock;       /* index in f_blockstack */
+    char f_executing;           /* whether the frame is still executing */
+    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
+    PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
+
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 3 && minorVersion == 4;
+    }
+};
+
+
+typedef void (*destructor)(PyObject *);
+
+// 2.4 - 3.4
+class PyMethodDef {
+public:
+    char    *ml_name;    /* The name of the built-in function/method */
+};
+
+
+//
+// 2.4 - 3.4, 2.4 has different compat in 64-bit but we don't support any of the released 64-bit platforms (which includes only IA-64)
+// While these are compatible there are fields only available on later versions.
+class PyTypeObject : public PyVarObject {
+public:
+    const char *tp_name; /* For printing, in format "<module>.<name>" */
+    size_t tp_basicsize, tp_itemsize; /* For allocation */
+
+    /* Methods to implement standard operations */
+
+    destructor tp_dealloc;
+    void* tp_print;
+    void* tp_getattr;
+    void* tp_setattr;
+    void* tp_compare;
+    void* tp_repr;
+
+    /* Method suites for standard classes */
+
+    void *tp_as_number;
+    void*tp_as_sequence;
+    void*tp_as_mapping;
+
+    /* More standard operations (here for binary compatibility) */
+
+    void* tp_hash;
+    void* tp_call;
+    void* tp_str;
+    void* tp_getattro;
+    void* tp_setattro;
+
+    /* Functions to access object as input/output buffer */
+    void*tp_as_buffer;
+
+    /* Flags to define presence of optional/expanded features */
+    long tp_flags;
+
+    const char *tp_doc; /* Documentation string */
+
+    /* Assigned meaning in release 2.0 */
+    /* call function for all accessible objects */
+    void*  tp_traverse;
+
+    /* delete references to contained objects */
+    void* tp_clear;
+
+    /* Assigned meaning in release 2.1 */
+    /* rich comparisons */
+    void*  tp_richcompare;
+
+    /* weak reference enabler */
+    size_t tp_weaklistoffset;
+
+    /* Added in release 2.2 */
+    /* Iterators */
+    void*  tp_iter;
+    void*  tp_iternext;
+
+    /* Attribute descriptor and subclassing stuff */
+    PyMethodDef *tp_methods;
+    struct PyMemberDef *tp_members;
+    struct PyGetSetDef *tp_getset;
+    struct _typeobject *tp_base;
+    PyObject *tp_dict;
+    void*  tp_descr_get;
+    void*  tp_descr_set;
+    size_t tp_dictoffset;
+    void* tp_init;
+    void* tp_alloc;
+    void* tp_new;
+    void* tp_free; /* Low-level free-memory routine */
+    void* tp_is_gc; /* For PyObject_IS_GC */
+    PyObject *tp_bases;
+    PyObject *tp_mro; /* method resolution order */
+    PyObject *tp_cache;
+    PyObject *tp_subclasses;
+    PyObject *tp_weaklist;
+    void*  tp_del;
+
+    /* Type attribute cache version tag. Added in version 2.6 */
+    unsigned int tp_version_tag;
+};
+
+// 2.4 - 3.4
+class PyTupleObject : public PyVarObject {
+public:
+    PyObject *ob_item[1];
+
+    /* ob_item contains space for 'ob_size' elements.
+     * Items must normally not be NULL, except during construction when
+     * the tuple is not yet visible outside the function that builds it.
+     */
+};
+
+// 2.4 - 3.4
+class PyCFunctionObject : public PyObject {
+public:
+    PyMethodDef *m_ml;      /* Description of the C function to call */
+    PyObject    *m_self;    /* Passed as 'self' arg to the C func, can be NULL */
+    PyObject    *m_module;  /* The __module__ attribute, can be anything */
+};
+
+typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
+
+#define PyTrace_CALL 0
+#define PyTrace_EXCEPTION 1
+#define PyTrace_LINE 2
+#define PyTrace_RETURN 3
+#define PyTrace_C_CALL 4
+#define PyTrace_C_EXCEPTION 5
+#define PyTrace_C_RETURN 6
+
+class PyInterpreterState {
+};
+
+class PyThreadState { };
+
+class PyThreadState_25_27 : public PyThreadState {
+public:
+    /* See Python/ceval.c for comments explaining most fields */
+
+    PyThreadState *next;
+    PyInterpreterState *interp;
+
+    PyFrameObject *frame;
+    int recursion_depth;
+    /* 'tracing' keeps track of the execution depth when tracing/profiling.
+       This is to prevent the actual trace/profile code from being recorded in
+       the trace/profile. */
+    int tracing;
+    int use_tracing;
+
+    Py_tracefunc c_profilefunc;
+    Py_tracefunc c_tracefunc;
+    PyObject *c_profileobj;
+    PyObject *c_traceobj;
+
+    PyObject *curexc_type;
+    PyObject *curexc_value;
+    PyObject *curexc_traceback;
+
+    PyObject *exc_type;
+    PyObject *exc_value;
+    PyObject *exc_traceback;
+
+    PyObject *dict;  /* Stores per-thread state */
+
+    /* tick_counter is incremented whenever the check_interval ticker
+     * reaches zero. The purpose is to give a useful measure of the number
+     * of interpreted bytecode instructions in a given thread.  This
+     * extremely lightweight statistic collector may be of interest to
+     * profilers (like psyco.jit()), although nothing in the core uses it.
+     */
+    int tick_counter;
+
+    int gilstate_counter;
+
+    PyObject *async_exc; /* Asynchronous exception to raise */
+    long thread_id; /* Thread id where this tstate was created */
+
+    /* XXX signal handlers should also be here */
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version >= PythonVersion_25 && version <= PythonVersion_27;
+    }
+};
+
+class PyThreadState_30_33 : public PyThreadState {
+public:
+    PyThreadState *next;
+    PyInterpreterState *interp;
+
+    PyFrameObject *frame;
+    int recursion_depth;
+    char overflowed; /* The stack has overflowed. Allow 50 more calls
+                        to handle the runtime error. */
+    char recursion_critical; /* The current calls must not cause
+                                a stack overflow. */
+    /* 'tracing' keeps track of the execution depth when tracing/profiling.
+       This is to prevent the actual trace/profile code from being recorded in
+       the trace/profile. */
+    int tracing;
+    int use_tracing;
+
+    Py_tracefunc c_profilefunc;
+    Py_tracefunc c_tracefunc;
+    PyObject *c_profileobj;
+    PyObject *c_traceobj;
+
+    PyObject *curexc_type;
+    PyObject *curexc_value;
+    PyObject *curexc_traceback;
+
+    PyObject *exc_type;
+    PyObject *exc_value;
+    PyObject *exc_traceback;
+
+    PyObject *dict;  /* Stores per-thread state */
+
+    /* tick_counter is incremented whenever the check_interval ticker
+     * reaches zero. The purpose is to give a useful measure of the number
+     * of interpreted bytecode instructions in a given thread.  This
+     * extremely lightweight statistic collector may be of interest to
+     * profilers (like psyco.jit()), although nothing in the core uses it.
+     */
+    int tick_counter;
+
+    int gilstate_counter;
+
+    PyObject *async_exc; /* Asynchronous exception to raise */
+    long thread_id; /* Thread id where this tstate was created */
+
+    /* XXX signal handlers should also be here */
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version >= PythonVersion_30 && version <= PythonVersion_33;
+    }
+};
+
+class PyThreadState_34 : public PyThreadState {
+public:
+    PyThreadState *prev;
+    PyThreadState *next;
+    PyInterpreterState *interp;
+
+    PyFrameObject *frame;
+    int recursion_depth;
+    char overflowed; /* The stack has overflowed. Allow 50 more calls
+                        to handle the runtime error. */
+    char recursion_critical; /* The current calls must not cause
+                                a stack overflow. */
+    /* 'tracing' keeps track of the execution depth when tracing/profiling.
+       This is to prevent the actual trace/profile code from being recorded in
+       the trace/profile. */
+    int tracing;
+    int use_tracing;
+
+    Py_tracefunc c_profilefunc;
+    Py_tracefunc c_tracefunc;
+    PyObject *c_profileobj;
+    PyObject *c_traceobj;
+
+    PyObject *curexc_type;
+    PyObject *curexc_value;
+    PyObject *curexc_traceback;
+
+    PyObject *exc_type;
+    PyObject *exc_value;
+    PyObject *exc_traceback;
+
+    PyObject *dict;  /* Stores per-thread state */
+
+    int gilstate_counter;
+
+    PyObject *async_exc; /* Asynchronous exception to raise */
+    long thread_id; /* Thread id where this tstate was created */
+
+    /* XXX signal handlers should also be here */
+    static bool IsFor(int majorVersion, int minorVersion) {
+        return majorVersion == 3 && minorVersion == 4;
+    }
+
+    static bool IsFor(PythonVersion version) {
+        return version == PythonVersion_34;
+    }
+};
+
+class PyIntObject : public PyObject {
+public:
+    long ob_ival;
+};
+
+//class Py3kLongObject : public PyVarObject {
+//public:
+//    DWORD ob_digit[1];
+//};
+
+class PyOldStyleClassObject : public PyObject {
+public:
+    PyObject *cl_bases; /* A tuple of class objects */
+    PyObject *cl_dict; /* A dictionary */
+    PyObject *cl_name; /* A string */
+    /* The following three are functions or NULL */
+    PyObject *cl_getattr;
+    PyObject *cl_setattr;
+    PyObject *cl_delattr;
+};
+
+class PyInstanceObject : public PyObject {
+public:
+    PyOldStyleClassObject *in_class; /* The class object */
+    PyObject *in_dict; /* A dictionary */
+    PyObject *in_weakreflist; /* List of weak references */
+};
+
+typedef const char* (*GetVersionFunc) ();
+
+static PythonVersion GetPythonVersion() {
+    GetVersionFunc versionFunc;
+    void *main_hndl = dlopen(NULL, 0x2);
+    *(void**)(&versionFunc) = dlsym(main_hndl, "Py_GetVersion");
+    if(versionFunc != NULL) {
+        const char* version = versionFunc();
+        if(version != NULL && strlen(version) >= 3 && version[1] == '.') {
+            if(version[0] == '2') {
+                switch(version[2]) {
+                case '5': return PythonVersion_25;
+                case '6': return PythonVersion_26;
+                case '7': return PythonVersion_27;
+                }
+            } else if(version[0] == '3') {
+                switch(version[2]) {
+                case '0': return PythonVersion_30;
+                case '1': return PythonVersion_31;
+                case '2': return PythonVersion_32;
+                case '3': return PythonVersion_33;
+                case '4': return PythonVersion_34;
+                }
+            }
+        }
+    }
+    return PythonVersion_Unknown;
+}
+
+#endif
diff --git a/plugins/org.python.pydev/pysrc/pydevd_comm.py b/plugins/org.python.pydev/pysrc/pydevd_comm.py
index 27fca26..476900b 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_comm.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_comm.py
@@ -136,7 +136,7 @@ CMD_IGNORE_THROWN_EXCEPTION_AT = 140
 CMD_ENABLE_DONT_TRACE = 141
 CMD_SHOW_CONSOLE = 142
 
-
+CMD_GET_ARRAY = 143
 
 CMD_VERSION = 501
 CMD_RETURN = 502
@@ -189,6 +189,8 @@ ID_TO_MEANING = {
     '501':'CMD_VERSION',
     '502':'CMD_RETURN',
     '901':'CMD_ERROR',
+
+    '143':'CMD_GET_ARRAY',
     }
 
 MAX_IO_MSG_SIZE = 1000  #if the io is too big, we'll not send all (could make the debugger too non-responsive)
@@ -245,7 +247,7 @@ def SetGlobalDebugger(dbg):
 # PyDBDaemonThread
 #=======================================================================================================================
 class PyDBDaemonThread:
-    
+
     created_pydb_daemon_threads = {}
 
     def __init__(self):
@@ -273,7 +275,7 @@ class PyDBDaemonThread:
                     ss = PyCore.PySystemState()
                     # Note: Py.setSystemState() affects only the current thread.
                     PyCore.Py.setSystemState(ss)
-        
+
                 self.OnRun()
             except:
                 if sys is not None and traceback is not None:
@@ -290,16 +292,16 @@ class PyDBDaemonThread:
 
     def stopTrace(self):
         if self.dontTraceMe:
-            
+
             disable_tracing = True
-    
+
             if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON and sys.hexversion <= 0x020201f0:
                 # don't run untraced threads if we're in jython 2.2.1 or lower
                 # jython bug: if we start a thread and another thread changes the tracing facility
                 # it affects other threads (it's not set only for the thread but globally)
                 # Bug: http://sourceforge.net/tracker/index.php?func=detail&aid=1870039&group_id=12867&atid=112867
                 disable_tracing = False
-    
+
             if disable_tracing:
                 pydevd_tracing.SetTrace(None)  # no debugging on this thread
 
@@ -452,6 +454,8 @@ class WriterThread(PyDBDaemonThread):
             if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0:
                 traceback.print_exc()
 
+    def empty(self):
+        return self.cmdQueue.empty()
 
 
 
@@ -692,6 +696,13 @@ class NetCommandFactory:
         except Exception:
             return self.makeErrorMessage(seq, GetExceptionTracebackStr())
 
+
+    def makeGetArrayMessage(self, seq, payload):
+        try:
+            return NetCommand(CMD_GET_ARRAY, seq, payload)
+        except Exception:
+            return self.makeErrorMessage(seq, GetExceptionTracebackStr())
+
     def makeGetFrameMessage(self, seq, payload):
         try:
             return NetCommand(CMD_GET_FRAME, seq, payload)
@@ -955,6 +966,44 @@ class InternalGetVariable(InternalThreadCommand):
 
 
 #=======================================================================================================================
+# InternalGetArray
+#=======================================================================================================================
+class InternalGetArray(InternalThreadCommand):
+    def __init__(self, seq, roffset, coffset, rows, cols, format, thread_id, frame_id, scope, attrs):
+        self.sequence = seq
+        self.thread_id = thread_id
+        self.frame_id = frame_id
+        self.scope = scope
+        self.name = attrs.split("\t")[-1]
+        self.attrs = attrs
+        self.roffset = int(roffset)
+        self.coffset = int(coffset)
+        self.rows = int(rows)
+        self.cols = int(cols)
+        self.format = format
+
+    def doIt(self, dbg):
+        try:
+            frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
+            var = pydevd_vars.evalInContext(self.name, frame.f_globals, frame.f_locals)
+
+            xml = "<xml>"
+
+            var, metaxml, rows, cols, format = pydevd_vars.array_to_meta_xml(var, self.name, self.format)
+            xml += metaxml
+            self.format = '%' + format
+            if self.rows == -1 and self.cols == -1:
+                self.rows = rows
+                self.cols = cols
+            xml += pydevd_vars.array_to_xml(var, self.roffset, self.coffset, self.rows, self.cols, self.format)
+            xml += "</xml>"
+            cmd = dbg.cmdFactory.makeGetArrayMessage(self.sequence, xml)
+            dbg.writer.addCommand(cmd)
+        except:
+            cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving array: " + GetExceptionTracebackStr())
+            dbg.writer.addCommand(cmd)
+
+#=======================================================================================================================
 # InternalChangeVariable
 #=======================================================================================================================
 class InternalChangeVariable(InternalThreadCommand):
@@ -1171,11 +1220,12 @@ class InternalSendCurrExceptionTraceProceeded(InternalThreadCommand):
 class InternalEvaluateConsoleExpression(InternalThreadCommand):
     """ Execute the given command in the debug console """
 
-    def __init__(self, seq, thread_id, frame_id, line):
+    def __init__(self, seq, thread_id, frame_id, line, buffer_output=True):
         self.sequence = seq
         self.thread_id = thread_id
         self.frame_id = frame_id
         self.line = line
+        self.buffer_output = buffer_output
 
     def doIt(self, dbg):
         """ Create an XML for console output, error and more (true/false)
@@ -1188,7 +1238,9 @@ class InternalEvaluateConsoleExpression(InternalThreadCommand):
         try:
             frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
             if frame is not None:
-                console_message = pydevd_console.execute_console_command(frame, self.thread_id, self.frame_id, self.line)
+                console_message = pydevd_console.execute_console_command(
+                    frame, self.thread_id, self.frame_id, self.line, self.buffer_output)
+
                 cmd = dbg.cmdFactory.makeSendConsoleMessage(self.sequence, console_message.toXML())
             else:
                 from pydevd_console import ConsoleMessage
diff --git a/plugins/org.python.pydev/pysrc/pydevd_console.py b/plugins/org.python.pydev/pysrc/pydevd_console.py
index 52b18bb..bc2ebb1 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_console.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_console.py
@@ -81,39 +81,57 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface):
 
     overrides(BaseInterpreterInterface.createStdIn)
     def createStdIn(self):
-        return DebugConsoleStdIn() #For now, raw_input is not supported in this console.
+        try:
+            if not self.__buffer_output:
+                return sys.stdin
+        except:
+            pass
+
+        return DebugConsoleStdIn() #If buffered, raw_input is not supported in this console.
 
 
     overrides(InteractiveConsole.push)
-    def push(self, line, frame):
+    def push(self, line, frame, buffer_output=True):
         """Change built-in stdout and stderr methods by the
         new custom StdMessage.
         execute the InteractiveConsole.push.
         Change the stdout and stderr back be the original built-ins
 
+        :param buffer_output: if False won't redirect the output.
+
         Return boolean (True if more input is required else False),
         output_messages and input_messages
         """
+        self.__buffer_output = buffer_output
         more = False
-        original_stdout = sys.stdout
-        original_stderr = sys.stderr
+        if buffer_output:
+            original_stdout = sys.stdout
+            original_stderr = sys.stderr
         try:
             try:
                 self.frame = frame
-                out = sys.stdout = IOBuf()
-                err = sys.stderr = IOBuf()
+                if buffer_output:
+                    out = sys.stdout = IOBuf()
+                    err = sys.stderr = IOBuf()
                 more = self.addExec(line)
             except Exception:
                 exc = GetExceptionTracebackStr()
-                err.buflist.append("Internal Error: %s" % (exc,))
+                if buffer_output:
+                    err.buflist.append("Internal Error: %s" % (exc,))
+                else:
+                    sys.stderr.write("Internal Error: %s\n" % (exc,))
         finally:
             #Remove frame references.
             self.frame = None
             frame = None
-            sys.stdout = original_stdout
-            sys.stderr = original_stderr
+            if buffer_output:
+                sys.stdout = original_stdout
+                sys.stderr = original_stderr
 
-        return more, out.buflist, err.buflist
+        if buffer_output:
+            return more, out.buflist, err.buflist
+        else:
+            return more, [], []
 
 
     overrides(BaseInterpreterInterface.doAddExec)
@@ -179,7 +197,7 @@ def clear_interactive_console():
     InteractiveConsoleCache.interactive_console_instance = None
 
 
-def execute_console_command(frame, thread_id, frame_id, line):
+def execute_console_command(frame, thread_id, frame_id, line, buffer_output=True):
     """fetch an interactive console instance from the cache and
     push the received command to the console.
 
@@ -188,7 +206,7 @@ def execute_console_command(frame, thread_id, frame_id, line):
     console_message = ConsoleMessage()
 
     interpreter = get_interactive_console(thread_id, frame_id, frame, console_message)
-    more, output_messages, error_messages = interpreter.push(line, frame)
+    more, output_messages, error_messages = interpreter.push(line, frame, buffer_output)
     console_message.update_more(more)
 
     for message in output_messages:
diff --git a/plugins/org.python.pydev/pysrc/pydevd_constants.py b/plugins/org.python.pydev/pysrc/pydevd_constants.py
index f328107..c60dbe2 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_constants.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_constants.py
@@ -1,6 +1,7 @@
 '''
 This module holds the constants used for specifying the states of the debugger.
 '''
+from __future__ import nested_scopes
 STATE_RUN = 1
 STATE_SUSPEND = 2
 
@@ -73,7 +74,11 @@ except AttributeError:
     except:
         IS_64_BITS = False
 
-SUPPORT_GEVENT = os.getenv('GEVENT_SUPPORT', 'False') == 'True'
+try:
+    SUPPORT_GEVENT = os.getenv('GEVENT_SUPPORT', 'False') == 'True'
+except:
+    # Jython 2.1 doesn't accept that construct
+    SUPPORT_GEVENT = False
 
 USE_LIB_COPY = SUPPORT_GEVENT and not IS_PY3K and sys.version_info[1] >= 6
 import _pydev_threading as threading
@@ -96,12 +101,12 @@ except:
         except NameError:
             def DictContains(d, key):
                 return d.has_key(key)
-#=======================================================================================================================
-# Jython?
-#=======================================================================================================================
 try:
     DictPop = dict.pop
 except:
+    #=======================================================================================================================
+    # Jython 2.1
+    #=======================================================================================================================
     def DictPop(d, key, default=None):
         try:
             ret = d[key]
@@ -127,16 +132,32 @@ if IS_PY3K:
         return list(d.items())
 
 else:
-    DictKeys = dict.keys
+    try:
+        DictKeys = dict.keys
+    except:
+        def DictKeys(d):
+            return d.keys()
+    
     try:
         DictIterValues = dict.itervalues
     except:
-        DictIterValues = dict.values #Older versions don't have the itervalues
+        try:
+            DictIterValues = dict.values #Older versions don't have the itervalues
+        except:
+            def DictIterValues(d):
+                return d.values()
 
-    DictValues = dict.values
+    try:
+        DictValues = dict.values
+    except:
+        def DictValues(d):
+            return d.values()
 
     def DictIterItems(d):
-        return d.iteritems()
+        try:
+            return d.iteritems()
+        except:
+            return d.items()
 
     def DictItems(d):
         return d.items()
diff --git a/plugins/org.python.pydev/pysrc/pydevd_file_utils.py b/plugins/org.python.pydev/pysrc/pydevd_file_utils.py
index 147aa66..4a4081b 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_file_utils.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_file_utils.py
@@ -119,7 +119,7 @@ def _NormFile(filename):
             if r[ind] == "!":
                 ind+=1
             inner_path = r[ind:]
-            if inner_path.startswith('/'):
+            if inner_path.startswith('/') or inner_path.startswith('\\'):
                 inner_path = inner_path[1:]
             r = zip_path + "/" + inner_path
 
@@ -152,7 +152,7 @@ def exists(file):
                 return None
 
         try:
-            if inner_path.startswith('/'):
+            if inner_path.startswith('/') or inner_path.startswith('\\'):
                 inner_path = inner_path[1:]
 
             info = zip.getinfo(inner_path)
diff --git a/plugins/org.python.pydev/pysrc/pydevd_frame.py b/plugins/org.python.pydev/pysrc/pydevd_frame.py
index 1417ee2..a1ac823 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_frame.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_frame.py
@@ -227,7 +227,7 @@ class PyDBFrame:
 
             if event == 'call' and main_debugger.signature_factory:
                 sendSignatureCallTrace(main_debugger, frame, filename)
-                
+
             plugin_manager = main_debugger.plugin
 
             is_exception_event = event == 'exception'
@@ -492,15 +492,26 @@ class PyDBFrame:
                             #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)
+                            #I.e.: when setting to note we'll set the state to STATE_RUN and clear any stepping flags.
+                            back_filename, base = GetFilenameAndBase(back)
                             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)
+                                #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
 
+                            elif pydevd_dont_trace.should_trace_hook is not None:
+                                if not pydevd_dont_trace.should_trace_hook(back, back_filename):
+                                    # In this case, we'll have to skip the previous one because it shouldn't be traced.
+                                    # Also, we have to reset the tracing, because if the parent's parent (or some
+                                    # other parent) has to be traced and it's not currently, we wouldn't stop where
+                                    # we should anymore (so, a step in/over/return may not stop anywhere if no parent is traced).
+                                    # Related test: _debugger_case17a.py
+                                    main_debugger.SetTraceForFrameAndParents(back, overwrite_prev_trace=True)
+                                    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)
diff --git a/plugins/org.python.pydev/pysrc/pydevd_io.py b/plugins/org.python.pydev/pysrc/pydevd_io.py
index 2e74154..d05eb86 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_io.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_io.py
@@ -57,6 +57,8 @@ class IOBuf:
     def flush(self):
         pass
 
+    def empty(self):
+        return len(self.buflist) == 0
 
 class _RedirectionsHolder:
     _stack_stdout = []
diff --git a/plugins/org.python.pydev/pysrc/pydevd_referrers.py b/plugins/org.python.pydev/pysrc/pydevd_referrers.py
index 66b1a0e..c7bd15c 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_referrers.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_referrers.py
@@ -198,6 +198,8 @@ def get_referrer_info(searched_obj):
                         i += 1
 
                 if found_as:
+                    if not isinstance(found_as, str):
+                        found_as = str(found_as)
                     found_as = ' found_as="%s"' % (pydevd_vars.makeValidXmlValue(found_as),)
 
                 ret.append(pydevd_vars.varToXML(
diff --git a/plugins/org.python.pydev/pysrc/pydevd_resolver.py b/plugins/org.python.pydev/pysrc/pydevd_resolver.py
index a1c7a1d..a340943 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_resolver.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_resolver.py
@@ -13,7 +13,7 @@ except:
     setattr(__builtin__, 'False', 0)
 
 import pydevd_constants
-from pydevd_constants import DictIterItems, xrange
+from pydevd_constants import DictIterItems, DictKeys, xrange
 
 
 # Note: 300 is already a lot to see in the outline (after that the user should really use the shell to get things)
@@ -235,7 +235,7 @@ class DictResolver:
 
     def keyStr(self, key):
         if isinstance(key, str):
-            return "'%s'"%key
+            return '%r'%key
         else:
             if not pydevd_constants.IS_PY3K:
                 if isinstance(key, unicode):
@@ -444,6 +444,43 @@ class NdArrayResolver:
 class NdArrayItemsContainer: pass
 
 
+
+#=======================================================================================================================
+# MultiValueDictResolver
+#=======================================================================================================================
+class MultiValueDictResolver(DictResolver):
+
+    def resolve(self, dict, key):
+        if key in ('__len__', TOO_LARGE_ATTR):
+            return None
+
+        #ok, we have to iterate over the items to find the one that matches the id, because that's the only way
+        #to actually find the reference from the string we have before.
+        expected_id = int(key.split('(')[-1][:-1])
+        for key in DictKeys(dict):
+            val = dict.getlist(key)
+            if id(key) == expected_id:
+                return val
+
+        raise UnableToResolveVariableException()
+
+    def getDictionary(self, dict):
+        ret = {}
+        i = 0
+        for key in DictKeys(dict):
+            val = dict.getlist(key)
+            i += 1
+            #we need to add the id because otherwise we cannot find the real object to get its contents later on.
+            key = '%s (%s)' % (self.keyStr(key), id(key))
+            ret[key] = val
+            if i > MAX_ITEMS_TO_HANDLE:
+                ret[TOO_LARGE_ATTR] = TOO_LARGE_MSG
+                break
+
+        ret['__len__'] = len(dict)
+        return ret
+
+
 #=======================================================================================================================
 # FrameResolver
 #=======================================================================================================================
@@ -501,4 +538,5 @@ instanceResolver = InstanceResolver()
 jyArrayResolver = JyArrayResolver()
 setResolver = SetResolver()
 ndarrayResolver = NdArrayResolver()
+multiValueDictResolver = MultiValueDictResolver()
 frameResolver = FrameResolver()
diff --git a/plugins/org.python.pydev/pysrc/pydevd_utils.py b/plugins/org.python.pydev/pysrc/pydevd_utils.py
index 054dd69..0473636 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_utils.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_utils.py
@@ -1,3 +1,4 @@
+from __future__ import nested_scopes
 import traceback
 
 try:
@@ -89,10 +90,12 @@ def cmp_to_key(mycmp):
             return mycmp(self.obj, other.obj) != 0
     return K
 
-def is_string(x):
-    if pydevd_constants.IS_PY3K:
+if pydevd_constants.IS_PY3K:
+    def is_string(x):
         return isinstance(x, str)
-    else:
+    
+else:
+    def is_string(x):
         return isinstance(x, basestring)
 
 def to_string(x):
@@ -105,10 +108,11 @@ def print_exc():
     if traceback:
         traceback.print_exc()
 
-def quote_smart(s, safe='/'):
-    if pydevd_constants.IS_PY3K:
+if pydevd_constants.IS_PY3K:
+    def quote_smart(s, safe='/'):
         return quote(s, safe)
-    else:
+else:
+    def quote_smart(s, safe='/'):
         if isinstance(s, unicode):
             s =  s.encode('utf-8')
 
diff --git a/plugins/org.python.pydev/pysrc/pydevd_vars.py b/plugins/org.python.pydev/pysrc/pydevd_vars.py
index b2df11e..178b11c 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_vars.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_vars.py
@@ -19,6 +19,7 @@ import _pydev_threading as threading
 import traceback
 import pydevd_save_locals
 from pydev_imports import Exec, quote, execfile
+from pydevd_utils import to_string
 
 try:
     import types
@@ -276,6 +277,43 @@ def customOperation(thread_id, frame_id, scope, attrs, style, code_or_file, oper
         traceback.print_exc()
 
 
+def evalInContext(expression, globals, locals):
+    result = None
+    try:
+        result = eval(expression, globals, locals)
+    except Exception:
+        s = StringIO()
+        traceback.print_exc(file=s)
+        result = s.getvalue()
+
+        try:
+            try:
+                etype, value, tb = sys.exc_info()
+                result = value
+            finally:
+                etype = value = tb = None
+        except:
+            pass
+
+        result = ExceptionOnEvaluate(result)
+
+        # Ok, we have the initial error message, but let's see if we're dealing with a name mangling error...
+        try:
+            if '__' in expression:
+                # Try to handle '__' name mangling...
+                split = expression.split('.')
+                curr = locals.get(split[0])
+                for entry in split[1:]:
+                    if entry.startswith('__') and not hasattr(curr, entry):
+                        entry = '_%s%s' % (curr.__class__.__name__, entry)
+                    curr = getattr(curr, entry)
+
+                result = curr
+        except:
+            pass
+    return result
+
+
 def evaluateExpression(thread_id, frame_id, expression, doExec):
     '''returns the result of the evaluated expression
     @param doExec: determines if we should do an exec or an eval
@@ -284,9 +322,6 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
     if frame is None:
         return
 
-    expression = str(expression.replace('@LINE@', '\n'))
-
-
     #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
     #(Names not resolved in generator expression in method)
     #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
@@ -295,6 +330,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
     updated_globals.update(frame.f_locals)  #locals later because it has precedence over the actual globals
 
     try:
+        expression = str(expression.replace('@LINE@', '\n'))
 
         if doExec:
             try:
@@ -311,42 +347,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
             return
 
         else:
-            result = None
-            try:
-                result = eval(expression, updated_globals, frame.f_locals)
-            except Exception:
-                s = StringIO()
-                traceback.print_exc(file=s)
-                result = s.getvalue()
-
-                try:
-                    try:
-                        etype, value, tb = sys.exc_info()
-                        result = value
-                    finally:
-                        etype = value = tb = None
-                except:
-                    pass
-
-                result = ExceptionOnEvaluate(result)
-
-                # Ok, we have the initial error message, but let's see if we're dealing with a name mangling error...
-                try:
-                    if '__' in expression:
-                        # Try to handle '__' name mangling...
-                        split = expression.split('.')
-                        curr = frame.f_locals.get(split[0])
-                        for entry in split[1:]:
-                            if entry.startswith('__') and not hasattr(curr, entry):
-                                entry = '_%s%s' % (curr.__class__.__name__, entry)
-                            curr = getattr(curr, entry)
-
-                        result = curr
-                except:
-                    pass
-
-
-            return result
+            return evalInContext(expression, updated_globals, frame.f_locals)
     finally:
         #Should not be kept alive if an exception happens and this frame is kept in the stack.
         del updated_globals
@@ -387,7 +388,115 @@ def changeAttrExpression(thread_id, frame_id, attr, expression, dbg):
     except Exception:
         traceback.print_exc()
 
-
+MAXIMUM_ARRAY_SIZE = 100
+MAX_SLICE_SIZE = 1000
+
+def array_to_xml(array, roffset, coffset, rows, cols, format):
+    xml = ""
+    rows = min(rows, MAXIMUM_ARRAY_SIZE)
+    cols = min(cols, MAXIMUM_ARRAY_SIZE)
+
+
+    #there is no obvious rule for slicing (at least 5 choices)
+    if len(array) == 1 and (rows > 1 or cols > 1):
+        array = array[0]
+    if array.size > len(array):
+        array = array[roffset:, coffset:]
+        rows = min(rows, len(array))
+        cols = min(cols, len(array[0]))
+        if len(array) == 1:
+            array = array[0]
+    elif array.size == len(array):
+        if roffset == 0 and rows == 1:
+            array = array[coffset:]
+            cols = min(cols, len(array))
+        elif coffset == 0 and cols == 1:
+            array = array[roffset:]
+            rows = min(rows, len(array))
+
+    xml += "<arraydata rows=\"%s\" cols=\"%s\"/>" % (rows, cols)
+    for row in range(rows):
+        xml += "<row index=\"%s\"/>" % to_string(row)
+        for col in range(cols):
+            value = array
+            if rows == 1 or cols == 1:
+                if rows == 1 and cols == 1:
+                    value = array[0]
+                else:
+                    if rows == 1:
+                        dim = col
+                    else:
+                        dim = row
+                    value = array[dim]
+                    if "ndarray" in str(type(value)):
+                        value = value[0]
+            else:
+                value = array[row][col]
+            value = format % value
+            xml += varToXML(value, '')
+    return xml
+
+
+def array_to_meta_xml(array, name, format):
+    type = array.dtype.kind
+    slice = name
+    l = len(array.shape)
+
+    # initial load, compute slice
+    if format == '%':
+        if l > 2:
+            slice += '[0]' * (l - 2)
+            for r in range(l - 2):
+                array = array[0]
+        if type == 'f':
+            format = '.5f'
+        elif type == 'i' or type == 'u':
+            format = 'd'
+        else:
+            format = 's'
+    else:
+        format = format.replace('%', '')
+
+    l = len(array.shape)
+    reslice = ""
+    if l > 2:
+        raise Exception("%s has more than 2 dimensions." % slice)
+    elif l == 1:
+        # special case with 1D arrays arr[i, :] - row, but arr[:, i] - column with equal shape and ndim
+        # http://stackoverflow.com/questions/16837946/numpy-a-2-rows-1-column-file-loadtxt-returns-1row-2-columns
+        # explanation: http://stackoverflow.com/questions/15165170/how-do-i-maintain-row-column-orientation-of-vectors-in-numpy?rq=1
+        # we use kind of a hack - get information about memory from C_CONTIGUOUS
+        is_row = array.flags['C_CONTIGUOUS']
+
+        if is_row:
+            rows = 1
+            cols = min(len(array), MAX_SLICE_SIZE)
+            if cols < len(array):
+                reslice = '[0:%s]' % (cols)
+            array = array[0:cols]
+        else:
+            cols = 1
+            rows = min(len(array), MAX_SLICE_SIZE)
+            if rows < len(array):
+                reslice = '[0:%s]' % (rows)
+            array = array[0:rows]
+    elif l == 2:
+        rows = min(array.shape[-2], MAX_SLICE_SIZE)
+        cols = min(array.shape[-1], MAX_SLICE_SIZE)
+        if cols < array.shape[-1] or  rows < array.shape[-2]:
+            reslice = '[0:%s, 0:%s]' % (rows, cols)
+        array = array[0:rows, 0:cols]
+
+    #avoid slice duplication
+    if not slice.endswith(reslice):
+        slice += reslice
+
+    bounds = (0, 0)
+    if type in "biufc":
+        bounds = (array.min(), array.max())
+    xml = '<array slice=\"%s\" rows=\"%s\" cols=\"%s\" format=\"%s\" type=\"%s\" max=\"%s\" min=\"%s\"/>' % \
+           (slice, rows, cols, format, type, bounds[1], bounds[0])
+    return array, xml, rows, cols, format
 
 
 
diff --git a/plugins/org.python.pydev/pysrc/pydevd_xml.py b/plugins/org.python.pydev/pysrc/pydevd_xml.py
index ff2b578..be94f4c 100644
--- a/plugins/org.python.pydev/pysrc/pydevd_xml.py
+++ b/plugins/org.python.pydev/pysrc/pydevd_xml.py
@@ -74,6 +74,13 @@ def _update_type_map():
         except:
             pass  #numpy may not be installed
     
+        try:
+            from django.utils.datastructures import MultiValueDict
+            _TYPE_MAP.insert(0, (MultiValueDict, pydevd_resolver.multiValueDictResolver))
+            #we should put it before dict
+        except:
+            pass  #django may not be installed
+
         if frame_type is not None:
             _TYPE_MAP.append((frame_type, pydevd_resolver.frameResolver))
     
diff --git a/plugins/org.python.pydev/pysrc/runfiles.py b/plugins/org.python.pydev/pysrc/runfiles.py
index 3e6c0d6..4819e52 100644
--- a/plugins/org.python.pydev/pysrc/runfiles.py
+++ b/plugins/org.python.pydev/pysrc/runfiles.py
@@ -3,7 +3,7 @@ import os
 def main():
     import sys
 
-    #Separate the nose params and the pydev params.
+    # Separate the nose params and the pydev params.
     pydev_params = []
     other_test_framework_params = []
     found_other_test_framework_param = None
@@ -22,7 +22,7 @@ def main():
                 other_test_framework_params.append(arg)
 
 
-    #Here we'll run either with nose or with the pydev_runfiles.
+    # Here we'll run either with nose or with the pydev_runfiles.
     import pydev_runfiles
     import pydev_runfiles_xml_rpc
     import pydevd_constants
@@ -40,13 +40,13 @@ def main():
     except:
         sys.stderr.write('Command line received: %s\n' % (sys.argv,))
         raise
-    pydev_runfiles_xml_rpc.InitializeServer(configuration.port) #Note that if the port is None, a Null server will be initialized.
+    pydev_runfiles_xml_rpc.InitializeServer(configuration.port)  # Note that if the port is None, a Null server will be initialized.
 
     NOSE_FRAMEWORK = 1
     PY_TEST_FRAMEWORK = 2
     try:
         if found_other_test_framework_param:
-            test_framework = 0 #Default (pydev)
+            test_framework = 0  # Default (pydev)
             if found_other_test_framework_param == NOSE_PARAMS:
                 import nose
                 test_framework = NOSE_FRAMEWORK
@@ -68,34 +68,34 @@ def main():
 
         test_framework = 0
 
-    #Clear any exception that may be there so that clients don't see it.
-    #See: https://sourceforge.net/tracker/?func=detail&aid=3408057&group_id=85796&atid=577329
+    # Clear any exception that may be there so that clients don't see it.
+    # See: https://sourceforge.net/tracker/?func=detail&aid=3408057&group_id=85796&atid=577329
     if hasattr(sys, 'exc_clear'):
         sys.exc_clear()
 
     if test_framework == 0:
 
-        return pydev_runfiles.main(configuration) #Note: still doesn't return a proper value.
+        return pydev_runfiles.main(configuration)  # Note: still doesn't return a proper value.
 
     else:
-        #We'll convert the parameters to what nose or py.test expects.
-        #The supported parameters are:
-        #runfiles.py  --config-file|-t|--tests <Test.test1,Test2>  dirs|files --nose-params xxx yyy zzz
-        #(all after --nose-params should be passed directly to nose)
+        # We'll convert the parameters to what nose or py.test expects.
+        # The supported parameters are:
+        # runfiles.py  --config-file|-t|--tests <Test.test1,Test2>  dirs|files --nose-params xxx yyy zzz
+        # (all after --nose-params should be passed directly to nose)
 
-        #In java:
-        #--tests = Constants.ATTR_UNITTEST_TESTS
-        #--config-file = Constants.ATTR_UNITTEST_CONFIGURATION_FILE
+        # In java:
+        # --tests = Constants.ATTR_UNITTEST_TESTS
+        # --config-file = Constants.ATTR_UNITTEST_CONFIGURATION_FILE
 
 
-        #The only thing actually handled here are the tests that we want to run, which we'll
-        #handle and pass as what the test framework expects.
+        # The only thing actually handled here are the tests that we want to run, which we'll
+        # handle and pass as what the test framework expects.
 
         py_test_accept_filter = {}
         files_to_tests = configuration.files_to_tests
 
         if files_to_tests:
-            #Handling through the file contents (file where each line is a test)
+            # Handling through the file contents (file where each line is a test)
             files_or_dirs = []
             for file, tests in files_to_tests.items():
                 if test_framework == NOSE_FRAMEWORK:
@@ -112,7 +112,7 @@ def main():
 
         else:
             if configuration.tests:
-                #Tests passed (works together with the files_or_dirs)
+                # Tests passed (works together with the files_or_dirs)
                 files_or_dirs = []
                 for file in configuration.files_or_dirs:
                     if test_framework == NOSE_FRAMEWORK:
@@ -127,16 +127,16 @@ def main():
                     else:
                         raise AssertionError('Cannot handle test framework: %s at this point.' % (test_framework,))
             else:
-                #Only files or dirs passed (let it do the test-loading based on those paths)
+                # Only files or dirs passed (let it do the test-loading based on those paths)
                 files_or_dirs = configuration.files_or_dirs
 
         argv = other_test_framework_params + files_or_dirs
 
 
         if test_framework == NOSE_FRAMEWORK:
-            #Nose usage: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html
-            #show_stdout_option = ['-s']
-            #processes_option = ['--processes=2']
+            # Nose usage: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html
+            # show_stdout_option = ['-s']
+            # processes_option = ['--processes=2']
             argv.insert(0, sys.argv[0])
             if DEBUG:
                 sys.stdout.write('Final test framework args: %s\n' % (argv[1:],))
@@ -159,15 +159,46 @@ def main():
             except:
                 xrange = range
 
+            def dotted(p):
+                # Helper to convert path to have dots instead of slashes
+                return os.path.normpath(p).replace(os.sep, "/").replace('/', '.')
+
+            curr_dir = os.path.realpath('.')
+            curr_dotted = dotted(curr_dir) + '.'
+
+            # Overcome limitation on py.test:
+            # When searching conftest if we have a structure as:
+            # /my_package
+            # /my_package/conftest.py
+            # /my_package/tests
+            # /my_package/tests/test_my_package.py
+            # The test_my_package won't have access to the conftest contents from the
+            # test_my_package.py file unless the working dir is set to /my_package.
+            #
+            # See related issue (for which we work-around below):
+            # https://bitbucket.org/hpk42/pytest/issue/639/conftest-being-loaded-twice-giving
+
+            for path in sys.path:
+                path_dotted = dotted(path)
+                if curr_dotted.startswith(path_dotted):
+                    os.chdir(path)
+                    break
+
             for i in xrange(len(argv)):
                 arg = argv[i]
-                #Workaround bug in py.test: if we pass the full path it ends up importing conftest
-                #more than once (so, always work with relative paths).
+                # Workaround bug in py.test: if we pass the full path it ends up importing conftest
+                # more than once (so, always work with relative paths).
                 if os.path.isfile(arg) or os.path.isdir(arg):
                     from pydev_imports import relpath
-                    arg = relpath(arg)
-                    argv[i] = arg
+                    try:
+                        # May fail if on different drives
+                        arg = relpath(arg)
+                    except ValueError:
+                        pass
+                    else:
+                        argv[i] = arg
 
+            # To find our runfile helpers (i.e.: plugin)...
             d = os.path.dirname(__file__)
             if d not in sys.path:
                 sys.path.insert(0, d)
@@ -180,7 +211,7 @@ def main():
             # Set what should be skipped in the plugin through an environment variable
             s = base64.b64encode(zlib.compress(pickle.dumps(py_test_accept_filter)))
             if pydevd_constants.IS_PY3K:
-                s = s.decode('ascii') # Must be str in py3.
+                s = s.decode('ascii')  # Must be str in py3.
             os.environ['PYDEV_PYTEST_SKIP'] = s
 
             # Identifies the main pid (i.e.: if it's not the main pid it has to connect back to the
@@ -203,11 +234,11 @@ if __name__ == '__main__':
         main()
     finally:
         try:
-            #The server is not a daemon thread, so, we have to ask for it to be killed!
+            # The server is not a daemon thread, so, we have to ask for it to be killed!
             import pydev_runfiles_xml_rpc
             pydev_runfiles_xml_rpc.forceServerKill()
         except:
-            pass #Ignore any errors here
+            pass  # Ignore any errors here
 
     import sys
     import threading
@@ -237,7 +268,7 @@ if __name__ == '__main__':
                     stack_trace.append('')
 
                     if 'self' in stack.f_locals:
-                        sys.stderr.write(str(stack.f_locals['self'])+'\n')
+                        sys.stderr.write(str(stack.f_locals['self']) + '\n')
 
                     for filename, lineno, name, line in traceback.extract_stack(stack):
                         stack_trace.append(' File "%s", line %d, in %s' % (filename, lineno, name))
@@ -248,5 +279,5 @@ if __name__ == '__main__':
 
 
         dump_current_frames_thread = DumpThreads()
-        dump_current_frames_thread.setDaemon(True) # Daemon so that this thread doesn't halt it!
+        dump_current_frames_thread.setDaemon(True)  # Daemon so that this thread doesn't halt it!
         dump_current_frames_thread.start()
diff --git a/plugins/org.python.pydev/pysrc/tests/test_check_pydevconsole.py b/plugins/org.python.pydev/pysrc/tests/test_check_pydevconsole.py
index 5d09968..10a6226 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_check_pydevconsole.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_check_pydevconsole.py
@@ -1,11 +1,15 @@
 import threading
 import unittest
+import os
+import sys
 
-import pydevconsole
+try:
+    import pydevconsole
+except:
+    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+    import pydevconsole
 from pydev_imports import xmlrpclib, SimpleXMLRPCServer
-import sys
 from pydev_localhost import get_localhost
-from pydev_ipython_console_011 import get_pydev_frontend
 
 try:
     raw_input
@@ -18,31 +22,31 @@ except NameError:
 #=======================================================================================================================
 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):
                         client_thread.requested_input = True
                         return 'RequestInput: OK'
-                    
+
                     def NotifyFinished(self, *args, **kwargs):
                         client_thread.notified_finished += 1
                         return 1
-                
+
                 handle_request_input = HandleRequestInput()
-                
+
                 import pydev_localhost
                 self.client_server = client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False)
                 client_server.register_function(handle_request_input.RequestInput)
                 client_server.register_function(handle_request_input.NotifyFinished)
                 client_server.serve_forever()
-                    
+
             def shutdown(self):
                 return
                 self.client_server.shutdown()
@@ -54,32 +58,37 @@ class Test(unittest.TestCase):
         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):
         # Just making sure that the singleton is created in this thread.
+        try:
+            from pydev_ipython_console_011 import get_pydev_frontend
+        except:
+            sys.stderr.write('Skipped test because IPython could not be imported.')
+            return
         get_pydev_frontend(get_localhost(), 0)
-        
+
         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)
@@ -89,11 +98,11 @@ class Test(unittest.TestCase):
         server_thread.start()
 
         client_thread = self.startClientThread(client_port) #@UnusedVariable
-        
+
         try:
             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.execLine("import sys; print('Running with: %s %s' % (sys.executable or sys.platform, sys.version))")
@@ -111,9 +120,9 @@ class Test(unittest.TestCase):
             self.assert_('RequestInput' in frame_xml, 'Did not fid RequestInput in:\n%s' % (frame_xml,))
         finally:
             client_thread.shutdown()
-        
+
 #=======================================================================================================================
-# main        
+# main
 #=======================================================================================================================
 if __name__ == '__main__':
     unittest.main()
diff --git a/plugins/org.python.pydev/pysrc/tests/test_get_referrers.py b/plugins/org.python.pydev/pysrc/tests/test_get_referrers.py
index 8284b27..fcfedbd 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_get_referrers.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_get_referrers.py
@@ -1,9 +1,13 @@
 import sys
 import threading
 import time
-
+import os
 import unittest
-import pydevd_referrers
+try:
+    import pydevd_referrers
+except:
+    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+    import pydevd_referrers
 from pydev_imports import StringIO
 
 #=======================================================================================================================
diff --git a/plugins/org.python.pydev/pysrc/tests/test_pydev_ipython_011.py b/plugins/org.python.pydev/pysrc/tests/test_pydev_ipython_011.py
index dc4684f..f8a6a03 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_pydev_ipython_011.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_pydev_ipython_011.py
@@ -17,46 +17,46 @@ except:
 
 
 class TestBase(unittest.TestCase):
-    
-    
+
+
     def setUp(self):
         # PyDevFrontEnd depends on singleton in IPython, so you
         # can't make multiple versions. So we reuse self.front_end for
         # all the tests
         self.front_end = get_pydev_frontend(get_localhost(), 0)
-        
+
         from pydev_ipython.inputhook import set_return_control_callback
         set_return_control_callback(lambda:True)
         self.front_end.clearBuffer()
 
     def tearDown(self):
         pass
-    
+
     def addExec(self, code, expected_more=False):
         more = self.front_end.addExec(code)
         eq_(expected_more, more)
-    
+
     def redirectStdout(self):
         from IPython.utils import io
-        
+
         self.original_stdout = sys.stdout
         sys.stdout = io.stdout = StringIO()
-    
+
     def restoreStdout(self):
         from IPython.utils import io
         io.stdout = sys.stdout = self.original_stdout
 
 
 class TestPyDevFrontEnd(TestBase):
-    
+
     def testAddExec_1(self):
         self.addExec('if True:', True)
-        
+
     def testAddExec_2(self):
         #Change: 'more' must now be controlled in the client side after the initial 'True' returned.
-        self.addExec('if True:\n    testAddExec_a = 10\n', False) 
+        self.addExec('if True:\n    testAddExec_a = 10\n', False)
         assert 'testAddExec_a' in self.front_end.getNamespace()
-        
+
     def testAddExec_3(self):
         assert 'testAddExec_x' not in self.front_end.getNamespace()
         self.addExec('if True:\n    testAddExec_x = 10\n\n')
@@ -158,7 +158,7 @@ class TestRunningCode(TestBase):
             _ih = self.front_end.getNamespace()['_ih']
             eq_(_ih[-1], 'b=2')
             eq_(_ih[-2], 'a=1')
-    
+
             self.addExec('history')
             hist = sys.stdout.getvalue().split('\n')
             eq_(hist[-1], '')
@@ -194,7 +194,7 @@ class TestRunningCode(TestBase):
                     client_server.register_function(handle_request_input.RequestInput)
                     client_server.register_function(handle_request_input.IPythonEditor)
                     client_server.serve_forever()
-                    
+
                 def shutdown(self):
                     return
                     self.client_server.shutdown()
@@ -219,12 +219,58 @@ class TestRunningCode(TestBase):
         try:
             filename = 'made_up_file.py'
             self.addExec('%edit ' + filename)
-            
+
             for i in xrange(10):
                 if called_IPythonEditor[0] == (os.path.abspath(filename), '0'):
                     break
                 time.sleep(.1)
-                
+
+            if not called_IPythonEditor[0]:
+                #   File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2883, in run_code
+                #     exec(code_obj, self.user_global_ns, self.user_ns)
+                #   File "<ipython-input-15-09583ca3bce1>", line 1, in <module>
+                #     get_ipython().magic('edit made_up_file.py')
+                #   File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2205, in magic
+                #     return self.run_line_magic(magic_name, magic_arg_s)
+                #   File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/interactiveshell.py", line 2126, in run_line_magic
+                #     result = fn(*args,**kwargs)
+                #   File "<string>", line 2, in edit
+                #   File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/magic.py", line 193, in <lambda>
+                #     call = lambda f, *a, **k: f(*a, **k)
+                #   File "/home/travis/miniconda/lib/python3.3/site-packages/IPython/core/magics/code.py", line 662, in edit
+                #     self.shell.hooks.editor(filename,lineno)
+                #   File "/home/travis/build/fabioz/PyDev.Debugger/pydev_ipython_console_011.py", line 70, in call_editor
+                #     server.IPythonEditor(filename, str(line))
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1090, in __call__
+                #     return self.__send(self.__name, args)
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1419, in __request
+                #     verbose=self.__verbose
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1132, in request
+                #     return self.single_request(host, handler, request_body, verbose)
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1143, in single_request
+                #     http_conn = self.send_request(host, handler, request_body, verbose)
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1255, in send_request
+                #     self.send_content(connection, request_body)
+                #   File "/home/travis/miniconda/lib/python3.3/xmlrpc/client.py", line 1285, in send_content
+                #     connection.endheaders(request_body)
+                #   File "/home/travis/miniconda/lib/python3.3/http/client.py", line 1061, in endheaders
+                #     self._send_output(message_body)
+                #   File "/home/travis/miniconda/lib/python3.3/http/client.py", line 906, in _send_output
+                #     self.send(msg)
+                #   File "/home/travis/miniconda/lib/python3.3/http/client.py", line 844, in send
+                #     self.connect()
+                #   File "/home/travis/miniconda/lib/python3.3/http/client.py", line 822, in connect
+                #     self.timeout, self.source_address)
+                #   File "/home/travis/miniconda/lib/python3.3/socket.py", line 435, in create_connection
+                #     raise err
+                #   File "/home/travis/miniconda/lib/python3.3/socket.py", line 426, in create_connection
+                #     sock.connect(sa)
+                # ConnectionRefusedError: [Errno 111] Connection refused
+
+                # I.e.: just warn that the test failing, don't actually fail.
+                sys.stderr.write('Test failed: this test is brittle in travis because sometimes the connection is refused (as above) and we do not have a callback.\n')
+                return
+
             eq_(called_IPythonEditor[0], (os.path.abspath(filename), '0'))
             assert called_RequestInput[0], "Make sure the 'wait' parameter has been respected"
         finally:
diff --git a/plugins/org.python.pydev/pysrc/tests/test_pydevconsole.py b/plugins/org.python.pydev/pysrc/tests/test_pydevconsole.py
index 1842198..6413af1 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_pydevconsole.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_pydevconsole.py
@@ -1,7 +1,13 @@
 import threading
 import unittest
 import sys
-import pydevconsole
+import os
+
+try:
+    import pydevconsole
+except:
+    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+    import pydevconsole
 from pydev_imports import xmlrpclib, SimpleXMLRPCServer, StringIO
 
 try:
@@ -18,16 +24,16 @@ class Test(unittest.TestCase):
     def testConsoleHello(self):
         self.original_stdout = sys.stdout
         sys.stdout = StringIO()
-        
+
         try:
             client_port, _server_port = self.getFreeAddresses()
             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
             interpreter = pydevconsole.InterpreterInterface(pydev_localhost.get_localhost(), client_port, threading.currentThread())
-    
+
             (result,) = interpreter.hello("Hello pydevconsole")
             self.assertEqual(result, "Hello eclipse")
         finally:
@@ -37,21 +43,19 @@ class Test(unittest.TestCase):
     def testConsoleRequests(self):
         self.original_stdout = sys.stdout
         sys.stdout = StringIO()
-        
+
         try:
             client_port, _server_port = self.getFreeAddresses()
             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
             from pydev_console_utils import CodeFragment
-            
+
             interpreter = pydevconsole.InterpreterInterface(pydev_localhost.get_localhost(), client_port, threading.currentThread())
             sys.stdout = StringIO()
-            interpreter.addExec(CodeFragment('class Foo:'))
-            interpreter.addExec(CodeFragment('   CONSTANT=1'))
-            interpreter.addExec(CodeFragment(''))
+            interpreter.addExec(CodeFragment('class Foo:\n    CONSTANT=1\n'))
             interpreter.addExec(CodeFragment('foo=Foo()'))
             interpreter.addExec(CodeFragment('foo.__doc__=None'))
             interpreter.addExec(CodeFragment('val = %s()' % (raw_input_name,)))
@@ -62,13 +66,13 @@ class Test(unittest.TestCase):
                 self.assertEqual(['50', 'input_request'], found)
             except:
                 self.assertEqual(['input_request'], found)  #IPython
-    
+
             comps = interpreter.getCompletions('foo.', 'foo.')
             self.assert_(
                 ('CONSTANT', '', '', '3') in comps or ('CONSTANT', '', '', '4') in comps, \
                 'Found: %s' % comps
             )
-    
+
             comps = interpreter.getCompletions('"".', '"".')
             self.assert_(
                 ('__add__', 'x.__add__(y) <==> x+y', '', '3') in comps or
@@ -77,27 +81,27 @@ class Test(unittest.TestCase):
                 ('__add__', 'x.\n__add__(y) <==> x+yx.\n__add__(y) <==> x+y', '()', '2'),
                 'Did not find __add__ in : %s' % (comps,)
             )
-    
-    
+
+
             completions = interpreter.getCompletions('', '')
             for c in completions:
                 if c[0] == 'AssertionError':
                     break
             else:
                 self.fail('Could not find AssertionError')
-    
+
             completions = interpreter.getCompletions('Assert', 'Assert')
             for c in completions:
                 if c[0] == 'RuntimeError':
                     self.fail('Did not expect to find RuntimeError there')
-    
+
             self.assert_(('__doc__', None, '', '3') not in interpreter.getCompletions('foo.CO', 'foo.'))
-    
+
             comps = interpreter.getCompletions('va', 'va')
             self.assert_(('val', '', '', '3') in comps or ('val', '', '', '4') in comps)
-    
+
             interpreter.addExec(CodeFragment('s = "mystring"'))
-    
+
             desc = interpreter.getDescription('val')
             self.assert_(desc.find('str(object) -> string') >= 0 or
                          desc == "'input_request'" or
@@ -108,7 +112,7 @@ class Test(unittest.TestCase):
                          desc.find('str(object=\'\') -> str') >= 0
                          ,
                          'Could not find what was needed in %s' % desc)
-    
+
             desc = interpreter.getDescription('val.join')
             self.assert_(desc.find('S.join(sequence) -> string') >= 0 or
                          desc.find('S.join(sequence) -> str') >= 0 or
@@ -128,25 +132,25 @@ class Test(unittest.TestCase):
             def __init__(self, client_port):
                 threading.Thread.__init__(self)
                 self.client_port = client_port
-                
+
             def run(self):
                 class HandleRequestInput:
                     def RequestInput(self):
                         client_thread.requested_input = True
                         return 'input_request'
-                    
+
                     def NotifyFinished(self, *args, **kwargs):
                         client_thread.notified_finished += 1
                         return 1
-                
+
                 handle_request_input = HandleRequestInput()
-                
+
                 import pydev_localhost
                 client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False)
                 client_server.register_function(handle_request_input.RequestInput)
                 client_server.register_function(handle_request_input.NotifyFinished)
                 client_server.serve_forever()
-                
+
         client_thread = ClientThread(client_port)
         client_thread.requested_input = False
         client_thread.notified_finished = 0
@@ -216,20 +220,20 @@ class Test(unittest.TestCase):
                     threading.Thread.__init__(self)
                     self.client_port = client_port
                     self.server_port = server_port
-    
+
                 def run(self):
                     import pydev_localhost
                     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
             sys.stdout = StringIO()
-    
+
             import pydev_localhost
             server = xmlrpclib.Server('http://%s:%s' % (pydev_localhost.get_localhost(), server_port))
             server.execLine('class Foo:')
@@ -243,7 +247,7 @@ class Test(unittest.TestCase):
                 if time.time() - initial > 2:
                     raise AssertionError('Did not get the return asked before the timeout.')
                 time.sleep(.1)
-                
+
             while ['input_request'] != sys.stdout.getvalue().split():
                 if time.time() - initial > 2:
                     break
diff --git a/plugins/org.python.pydev/pysrc/tests/test_pyserver.py b/plugins/org.python.pydev/pysrc/tests/test_pyserver.py
index ea9daff..38256e4 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_pyserver.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_pyserver.py
@@ -3,7 +3,12 @@
 '''
 import sys
 import os
-from _pydev_imps._pydev_thread import start_new_thread
+try:
+    from _pydev_imps._pydev_thread import start_new_thread
+except:
+    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+    from _pydev_imps._pydev_thread import start_new_thread
+
 
 #make it as if we were executing from the directory above this one (so that we can use pycompletionserver
 #without the need for it being in the pythonpath)
diff --git a/plugins/org.python.pydev/pysrc/tests/test_simpleTipper.py b/plugins/org.python.pydev/pysrc/tests/test_simpleTipper.py
index 255a521..830cb49 100644
--- a/plugins/org.python.pydev/pysrc/tests/test_simpleTipper.py
+++ b/plugins/org.python.pydev/pysrc/tests/test_simpleTipper.py
@@ -1,7 +1,8 @@
 '''
- at author Fabio Zadrozny 
+ at author Fabio Zadrozny
 '''
 import sys
+import os
 
 try:
     import __builtin__ #@UnusedImport
@@ -11,24 +12,28 @@ except ImportError:
 
 
 if sys.platform.find('java') == -1:
-    
+
     HAS_WX = False
-    
+
     import unittest
-    import _pydev_imports_tipper
+    try:
+        import _pydev_imports_tipper
+    except:
+        sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+        import _pydev_imports_tipper
     import inspect
-    
+
     class Test(unittest.TestCase):
-    
+
         def p(self, t):
             for a in t:
                 sys.stdout.write('%s\n' % (a,))
-     
+
         def testImports3(self):
             tip = _pydev_imports_tipper.GenerateTip('os')
             ret = self.assertIn('path', tip)
             self.assertEquals('', ret[2])
-    
+
         def testImports2(self):
             try:
                 tip = _pydev_imports_tipper.GenerateTip('OpenGL.GLUT')
@@ -36,29 +41,29 @@ if sys.platform.find('java') == -1:
                 self.assertIn('glutInitDisplayMode', tip)
             except ImportError:
                 pass
-    
+
         def testImports4(self):
             try:
                 tip = _pydev_imports_tipper.GenerateTip('mx.DateTime.mxDateTime.mxDateTime')
                 self.assertIn('now', tip)
             except ImportError:
                 pass
-    
+
         def testImports5(self):
             tip = _pydev_imports_tipper.GenerateTip('%s.list' % BUILTIN_MOD)
             s = self.assertIn('sort', tip)
             self.CheckArgs(
-                s, 
-                '(cmp=None, key=None, reverse=False)', 
+                s,
+                '(cmp=None, key=None, reverse=False)',
                 '(self, object cmp, object key, bool reverse)',
                 '(self, cmp: object, key: object, reverse: bool)',
                 '(key=None, reverse=False)',
             )
-            
+
         def testImports2a(self):
             tips = _pydev_imports_tipper.GenerateTip('%s.RuntimeError' % BUILTIN_MOD)
             self.assertIn('__doc__', tips)
-            
+
         def testImports2b(self):
             try:
                 file
@@ -68,7 +73,7 @@ if sys.platform.find('java') == -1:
                 tips = _pydev_imports_tipper.GenerateTip('%s' % BUILTIN_MOD)
                 t = self.assertIn('file' , tips)
                 self.assert_('->' in t[1].strip() or 'file' in t[1])
-            
+
         def testImports2c(self):
             try:
                 file # file is not available on py 3
@@ -78,7 +83,7 @@ if sys.platform.find('java') == -1:
                 tips = _pydev_imports_tipper.GenerateTip('%s.file' % BUILTIN_MOD)
                 t = self.assertIn('readlines' , tips)
                 self.assert_('->' in t[1] or 'sizehint' in t[1])
-            
+
         def testImports(self):
             '''
             You can print_ the results to check...
@@ -86,27 +91,27 @@ if sys.platform.find('java') == -1:
             if HAS_WX:
                 tip = _pydev_imports_tipper.GenerateTip('wxPython.wx')
                 self.assertIn('wxApp'        , tip)
-                
+
                 tip = _pydev_imports_tipper.GenerateTip('wxPython.wx.wxApp')
-                
+
                 try:
                     tip = _pydev_imports_tipper.GenerateTip('qt')
                     self.assertIn('QWidget'        , tip)
                     self.assertIn('QDialog'        , tip)
-                    
+
                     tip = _pydev_imports_tipper.GenerateTip('qt.QWidget')
                     self.assertIn('rect'           , tip)
                     self.assertIn('rect'           , tip)
                     self.assertIn('AltButton'      , tip)
-            
+
                     tip = _pydev_imports_tipper.GenerateTip('qt.QWidget.AltButton')
                     self.assertIn('__xor__'      , tip)
-            
+
                     tip = _pydev_imports_tipper.GenerateTip('qt.QWidget.AltButton.__xor__')
                     self.assertIn('__class__'      , tip)
                 except ImportError:
                     pass
-                
+
             tip = _pydev_imports_tipper.GenerateTip(BUILTIN_MOD)
     #        for t in tip[1]:
     #            print_ t
@@ -115,20 +120,20 @@ if sys.platform.find('java') == -1:
             self.assertIn('list'          , tip)
             self.assertIn('RuntimeError'   , tip)
             self.assertIn('RuntimeWarning' , tip)
-            
+
             # Remove cmp as it's not available on py 3
             #t = self.assertIn('cmp' , tip)
             #self.CheckArgs(t, '(x, y)', '(object x, object y)', '(x: object, y: object)') #args
-            
+
             t = self.assertIn('isinstance' , tip)
             self.CheckArgs(t, '(object, class_or_type_or_tuple)', '(object o, type typeinfo)', '(o: object, typeinfo: type)') #args
-            
+
             t = self.assertIn('compile' , tip)
             self.CheckArgs(t, '(source, filename, mode)', '()', '(o: object, name: str, val: object)') #args
-            
+
             t = self.assertIn('setattr' , tip)
             self.CheckArgs(t, '(object, name, value)', '(object o, str name, object val)', '(o: object, name: str, val: object)') #args
-            
+
             try:
                 import compiler
                 compiler_module = 'compiler'
@@ -138,9 +143,9 @@ if sys.platform.find('java') == -1:
                     compiler_module = 'ast'
                 except ImportError:
                     compiler_module = None
-                
+
             if compiler_module is not None: #Not available in iron python
-                tip = _pydev_imports_tipper.GenerateTip(compiler_module) 
+                tip = _pydev_imports_tipper.GenerateTip(compiler_module)
                 if compiler_module == 'compiler':
                     self.assertArgs('parse', '(buf, mode)', tip)
                     self.assertArgs('walk', '(tree, visitor, walker, verbose)', tip)
@@ -149,57 +154,57 @@ if sys.platform.find('java') == -1:
                     self.assertArgs('parse', '(source, filename, mode)', tip)
                     self.assertArgs('walk', '(node)', tip)
                 self.assertIn('parse'          , tip)
-            
-            
+
+
         def CheckArgs(self, t, *expected):
             for x in expected:
                 if x == t[2]:
                     return
             self.fail('Found: %s. Expected: %s' % (t[2], expected))
-            
-            
+
+
         def assertArgs(self, tok, args, tips):
             for a in tips[1]:
                 if tok == a[0]:
                     self.assertEquals(args, a[2])
                     return
             raise AssertionError('%s not in %s', tok, tips)
-    
+
         def assertIn(self, tok, tips):
             for a in tips[1]:
                 if tok == a[0]:
                     return a
             raise AssertionError('%s not in %s' % (tok, tips))
-        
-        
+
+
         def testSearch(self):
             s = _pydev_imports_tipper.Search('inspect.ismodule')
             (f, line, col), foundAs = s
             self.assert_(line > 0)
-            
-            
+
+
         def testDotNetLibraries(self):
             if sys.platform == 'cli':
                 tip = _pydev_imports_tipper.GenerateTip('System.Drawing')
                 self.assertIn('Brushes' , tip)
-                
+
                 tip = _pydev_imports_tipper.GenerateTip('System.Drawing.Brushes')
                 self.assertIn('Aqua' , tip)
-            
-    
+
+
         def testInspect(self):
-            
+
             class C(object):
                 def metA(self, a, b):
                     pass
-            
+
             obj = C.metA
             if inspect.ismethod (obj):
                 pass
     #            print_ obj.im_func
     #            print_ inspect.getargspec(obj.im_func)
-                
-            
+
+
     def suite():
         s = unittest.TestSuite()
         s.addTest(Test("testImports5"))
@@ -212,4 +217,4 @@ if __name__ == '__main__':
         unittest.main()
     else:
         sys.stdout.write('Not running python tests in platform: %s\n' % (sys.platform,))
-    
+
diff --git a/plugins/org.python.pydev/pysrc/tests_python/_debugger_case17a.py b/plugins/org.python.pydev/pysrc/tests_python/_debugger_case17a.py
new file mode 100644
index 0000000..10ca7c8
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/tests_python/_debugger_case17a.py
@@ -0,0 +1,15 @@
+def m1():
+    print('m1')
+
+def m2(): # @DontTrace
+    m1()
+    print('m2')
+
+def m3():
+    m2()
+    print('m3')
+
+if __name__ == '__main__':
+    m3()
+
+    print('TEST SUCEEDED')
diff --git a/plugins/org.python.pydev/pysrc/tests_python/test_debugger.py b/plugins/org.python.pydev/pysrc/tests_python/test_debugger.py
index 96fbd9c..20be11a 100644
--- a/plugins/org.python.pydev/pysrc/tests_python/test_debugger.py
+++ b/plugins/org.python.pydev/pysrc/tests_python/test_debugger.py
@@ -47,7 +47,7 @@ def _get_debugger_test_file(filename):
         # jython does not support os.path.realpath
         # realpath is a no-op on systems without islink support
         rPath = os.path.abspath
-        
+
     return os.path.normcase(rPath(os.path.join(os.path.dirname(__file__), filename)))
 
 import pydevd
@@ -117,7 +117,7 @@ class AbstractWriterThread(threading.Thread):
         self.sock.close()
 
     def Write(self, s):
-        
+
         last = self.readerThread.lastReceived
         if SHOW_WRITES_AND_READS:
             print('Test Writer Thread Written %s' % (s,))
@@ -215,7 +215,7 @@ class AbstractWriterThread(threading.Thread):
             i += 1
             time.sleep(1)
             if i >= 10:
-                raise AssertionError('After %s seconds, the custom operation not received. Last found:\n%s\nExpected (encoded)\n%s' % 
+                raise AssertionError('After %s seconds, the custom operation not received. Last found:\n%s\nExpected (encoded)\n%s' %
                     (i, self.readerThread.lastReceived, expectedEncoded))
 
         return True
@@ -231,14 +231,14 @@ class AbstractWriterThread(threading.Thread):
             i += 1
             time.sleep(1)
             if i >= 10:
-                raise AssertionError('After %s seconds, the vars were not found. Last found:\n%s' % 
+                raise AssertionError('After %s seconds, the vars were not found. Last found:\n%s' %
                     (i, self.readerThread.lastReceived))
 
         return True
 
     def WaitForVar(self, expected):
         self._WaitFor(expected, 'the var was not found')
-        
+
     def _WaitFor(self, expected, error_msg):
         '''
         :param expected:
@@ -246,7 +246,7 @@ class AbstractWriterThread(threading.Thread):
         '''
         if not isinstance(expected, (list, tuple)):
             expected = [expected]
-            
+
         i = 0
         found = False
         while not found:
@@ -255,7 +255,7 @@ class AbstractWriterThread(threading.Thread):
                 if e in last:
                     found = True
                     break
-                
+
             last = unquote_plus(last)
             for e in expected:
                 if e in last:
@@ -264,11 +264,11 @@ class AbstractWriterThread(threading.Thread):
 
             if found:
                 break
-                        
+
             i += 1
             time.sleep(1)
             if i >= 10:
-                raise AssertionError('After %s seconds, %s. Last found:\n%s' % 
+                raise AssertionError('After %s seconds, %s. Last found:\n%s' %
                     (i, error_msg, last))
 
         return True
@@ -286,7 +286,7 @@ class AbstractWriterThread(threading.Thread):
             i += 1
             time.sleep(1)
             if i >= 10:
-                raise AssertionError('After %s seconds, the vars were not found. Last found:\n%s' % 
+                raise AssertionError('After %s seconds, the vars were not found. Last found:\n%s' %
                     (i, self.readerThread.lastReceived))
 
         return True
@@ -344,7 +344,7 @@ class AbstractWriterThread(threading.Thread):
 
     def WriteCustomOperation(self, locator, style, codeOrFile, operation_fn_name):
         self.Write("%s\t%s\t%s||%s\t%s\t%s" % (CMD_RUN_CUSTOM_OPERATION, self.NextSeq(), locator, style, codeOrFile, operation_fn_name))
-        
+
     def WriteEvaluateExpression(self, locator, expression):
         self.Write("113\t%s\t%s\t%s\t1" % (self.NextSeq(), locator, expression))
 
@@ -371,12 +371,12 @@ class WriterThreadCase19(AbstractWriterThread):
         threadId, frameId, line = self.WaitForBreakpointHit('111', True)
 
         assert line == 8, 'Expected return to be in line 8, was: %s' % line
-        
+
         self.WriteEvaluateExpression('%s\t%s\t%s' % (threadId, frameId, 'LOCAL'), 'a.__var')
         self.WaitForEvaluation('<var name="a.__var" type="int" value="int')
         self.WriteRunThread(threadId)
 
-        
+
         self.finishedOk = True
 
 
@@ -397,7 +397,7 @@ class WriterThreadCase18(AbstractWriterThread):
 
         self.WriteChangeVariable(thread_id, frame_id, 'a', '40')
         self.WriteRunThread(thread_id)
-        
+
         self.finishedOk = True
 
 #=======================================================================================================================
@@ -418,14 +418,38 @@ class WriterThreadCase17(AbstractWriterThread):
 
         for i in range(4):
             threadId, frameId, line = self.WaitForBreakpointHit('111', True)
-    
+
             self.WriteStepIn(threadId)
             threadId, frameId, line = self.WaitForBreakpointHit('107', True)
             # Should Skip step into properties setter
             assert line == 2, 'Expected return to be in line 2, was: %s' % line
             self.WriteRunThread(threadId)
 
-        
+
+        self.finishedOk = True
+
+#=======================================================================================================================
+# WriterThreadCase17a - [Test Case]: dont trace return
+#======================================================================================================================
+class WriterThreadCase17a(AbstractWriterThread):
+
+    TEST_FILE = _get_debugger_test_file('_debugger_case17a.py')
+
+    def run(self):
+        self.StartSocket()
+        self.WriteEnableDontTrace(True)
+        self.WriteAddBreakpoint(2, 'm1')
+        self.WriteMakeInitialRun()
+
+        threadId, frameId, line = self.WaitForBreakpointHit('111', True)
+
+        self.WriteStepIn(threadId)
+        threadId, frameId, line = self.WaitForBreakpointHit('107', True)
+        # Should Skip step into properties setter
+        assert line == 10, 'Expected return to be in line 10, was: %s' % line
+        self.WriteRunThread(threadId)
+
+
         self.finishedOk = True
 
 #=======================================================================================================================
@@ -464,12 +488,12 @@ class WriterThreadCase16(AbstractWriterThread):
 
         self.WriteGetVariable(threadId, frameId, 'bigarray')
         self.WaitForVar([
-            '<var name="min" type="int64" value="int64%253A 0" />', 
-            '<var name="min" type="int64" value="int64%3A 0" />', 
+            '<var name="min" type="int64" value="int64%253A 0" />',
+            '<var name="min" type="int64" value="int64%3A 0" />',
             '<var name="size" type="int" value="int%3A 100000" />',
         ])
         self.WaitForVar([
-            '<var name="max" type="int64" value="int64%253A 99999" />', 
+            '<var name="max" type="int64" value="int64%253A 99999" />',
             '<var name="max" type="int32" value="int32%253A 99999" />',
             '<var name="max" type="int64" value="int64%3A 99999"'
         ])
@@ -1066,10 +1090,10 @@ class WriterThreadCase1(AbstractWriterThread):
 
     def run(self):
         self.StartSocket()
-        
+
         self.log.append('writing add breakpoint')
         self.WriteAddBreakpoint(6, 'SetUp')
-        
+
         self.log.append('making initial run')
         self.WriteMakeInitialRun()
 
@@ -1141,10 +1165,10 @@ class DebuggerBase(object):
                 if SHOW_STDOUT:
                     print(line)
                 buffer.append(line)
-            
+
         start_new_thread(read, (process.stdout, stdout))
-        
-        
+
+
         if SHOW_OTHER_DEBUG_INFO:
             print('Both processes started')
 
@@ -1161,12 +1185,12 @@ class DebuggerBase(object):
                         print('Warning: writer thread exited and process still did not.')
                     if check == 100:
                         self.fail_with_message(
-                            "The other process should've exited but still didn't (timeout for process to exit).", 
+                            "The other process should've exited but still didn't (timeout for process to exit).",
                             stdout, stderr, writerThread
                         )
             time.sleep(.2)
-            
-            
+
+
         poll = process.poll()
         if poll < 0:
             self.fail_with_message(
@@ -1183,17 +1207,17 @@ class DebuggerBase(object):
         for i in xrange(100):
             if not writerThread.finishedOk:
                 time.sleep(.1)
-            
+
         if not writerThread.finishedOk:
             self.fail_with_message(
                 "The thread that was doing the tests didn't finish successfully.", stdout, stderr, writerThread)
-            
+
     def fail_with_message(self, msg, stdout, stderr, writerThread):
         self.fail(msg+
             "\nStdout: \n"+'\n'.join(stdout)+
             "\nStderr:"+'\n'.join(stderr)+
             "\nLog:\n"+'\n'.join(getattr(writerThread, 'log', [])))
-        
+
 
     def testCase1(self):
         self.CheckCase(WriterThreadCase1)
@@ -1245,13 +1269,16 @@ class DebuggerBase(object):
 
     def testCase17(self):
         self.CheckCase(WriterThreadCase17)
-        
+
+    def testCase17a(self):
+        self.CheckCase(WriterThreadCase17a)
+
     def testCase18(self):
         self.CheckCase(WriterThreadCase18)
-        
+
     def testCase19(self):
         self.CheckCase(WriterThreadCase19)
-        
+
     def _has_qt(self):
         try:
             from PySide import QtCore
@@ -1312,19 +1339,19 @@ class TestIronPython(unittest.TestCase, DebuggerBase):
             ]
 
     def testCase3(self):
-        self.skipTest("Timing issues") # This test fails once in a while due to timing issues on IronPython, so, skipping it. 
-        
+        self.skipTest("Timing issues") # This test fails once in a while due to timing issues on IronPython, so, skipping it.
+
     def testCase7(self):
         # This test checks that we start without variables and at each step a new var is created, but on ironpython,
         # the variables exist all at once (with None values), so, we can't test it properly.
-        self.skipTest("Different behavior on IronPython") 
-        
+        self.skipTest("Different behavior on IronPython")
+
     def testCase13(self):
         self.skipTest("Unsupported Decorators") # Not sure why it doesn't work on IronPython, but it's not so common, so, leave it be.
-        
+
     def testCase16(self):
         self.skipTest("Unsupported numpy")
-        
+
     def testCase18(self):
         self.skipTest("Unsupported assign to local")
 
@@ -1360,13 +1387,13 @@ if os.path.exists(test_dependent):
             var, loc = SplitLine(line)
             if 'PYTHON_EXE' == var:
                 PYTHON_EXE = loc
-    
+
             if 'IRONPYTHON_EXE' == var:
                 IRONPYTHON_EXE = loc
-    
+
             if 'JYTHON_JAR_LOCATION' == var:
                 JYTHON_JAR_LOCATION = loc
-    
+
             if 'JAVA_LOCATION' == var:
                 JAVA_LOCATION = loc
     finally:
@@ -1378,16 +1405,16 @@ if IRONPYTHON_EXE is None:
     sys.stderr.write('Warning: not running IronPython tests.\n')
     class TestIronPython(unittest.TestCase):
         pass
-    
+
 if JAVA_LOCATION is None:
     sys.stderr.write('Warning: not running Jython tests.\n')
     class TestJython(unittest.TestCase):
         pass
-    
+
 # if PYTHON_EXE is None:
 PYTHON_EXE = sys.executable
-    
-    
+
+
 if __name__ == '__main__':
     if False:
         assert PYTHON_EXE, 'PYTHON_EXE not found in %s' % (test_dependent,)
@@ -1398,18 +1425,18 @@ if __name__ == '__main__':
         assert os.path.exists(IRONPYTHON_EXE), 'The location: %s is not valid' % (IRONPYTHON_EXE,)
         assert os.path.exists(JYTHON_JAR_LOCATION), 'The location: %s is not valid' % (JYTHON_JAR_LOCATION,)
         assert os.path.exists(JAVA_LOCATION), 'The location: %s is not valid' % (JAVA_LOCATION,)
-    
+
     if True:
         #try:
         #    os.remove(r'X:\pydev\plugins\org.python.pydev\pysrc\pydevd.pyc')
         #except:
         #    pass
         suite = unittest.TestSuite()
-        
+
 #         suite.addTests(unittest.makeSuite(TestJython)) # Note: Jython should be 2.2.1
-#           
+#
 #         suite.addTests(unittest.makeSuite(TestIronPython))
-#         
+#
         suite.addTests(unittest.makeSuite(TestPython))
 
 
@@ -1419,12 +1446,12 @@ if __name__ == '__main__':
 #         suite.addTest(TestIronPython('testCase17'))
 #         suite.addTest(TestIronPython('testCase3'))
 #         suite.addTest(TestIronPython('testCase7'))
-#         
+#
 #         suite.addTest(TestPython('testCaseQthread1'))
 #         suite.addTest(TestPython('testCaseQthread2'))
 #         suite.addTest(TestPython('testCaseQthread3'))
-        
-#         suite.addTest(TestPython('testCase4'))
+
+#         suite.addTest(TestPython('testCase17a'))
 
 
 #         suite.addTest(TestJython('testCase1'))
@@ -1433,5 +1460,5 @@ if __name__ == '__main__':
     #     suite.addTest(TestPython('testCase17'))
     #     suite.addTest(TestPython('testCase18'))
     #     suite.addTest(TestPython('testCase19'))
-        
+
         unittest.TextTestRunner(verbosity=3).run(suite)
diff --git a/plugins/org.python.pydev/pysrc/tests_python/test_pydev_monkey.py b/plugins/org.python.pydev/pysrc/tests_python/test_pydev_monkey.py
index be1312a..943e875 100644
--- a/plugins/org.python.pydev/pysrc/tests_python/test_pydev_monkey.py
+++ b/plugins/org.python.pydev/pysrc/tests_python/test_pydev_monkey.py
@@ -1,6 +1,11 @@
-import unittest
-import pydev_monkey
 import sys
+import os
+import unittest
+try:
+    import pydev_monkey
+except:
+    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
+    import pydev_monkey
 from pydevd import SetupHolder
 from pydev_monkey import pydev_src_dir
 
@@ -10,7 +15,7 @@ class TestCase(unittest.TestCase):
 
     def test_monkey(self):
         original = SetupHolder.setup
-        
+
         try:
             SetupHolder.setup = {'client':'127.0.0.1', 'port': '0'}
             check='''C:\\bin\\python.exe -u -c "
@@ -22,15 +27,98 @@ connect(\\"127.0.0.1\\")
                 'sys.path.append(r\'%s\'); '
                 'import pydevd; pydevd.settrace(host=\'127.0.0.1\', port=0, suspend=False, '
                     'trace_only_current_thread=False, patch_multiprocessing=True); '
-                    '\nconnect(\\"127.0.0.1\\")\n"' % pydev_src_dir, 
+                    '\nconnect(\\"127.0.0.1\\")\n"' % pydev_src_dir,
                 pydev_monkey.patch_arg_str_win(check)
             )
         finally:
             SetupHolder.setup = original
 
     def test_str_to_args_windows(self):
-        
         self.assertEqual(['a', 'b'], pydev_monkey.str_to_args_windows('a "b"'))
-        
+
+    def test_monkey_patch_args_indc(self):
+        original = SetupHolder.setup
+
+        try:
+            SetupHolder.setup = {'client':'127.0.0.1', 'port': '0'}
+            check=['C:\\bin\\python.exe', '-u', '-c', 'connect(\\"127.0.0.1\\")']
+            sys.original_argv = []
+            self.assertEqual(pydev_monkey.patch_args(check), [
+                'C:\\bin\\python.exe',
+                '-u',
+                '-c',
+                (
+                    'import sys; sys.path.append(r\'%s\'); import pydevd; '
+                    'pydevd.settrace(host=\'127.0.0.1\', port=0, suspend=False, trace_only_current_thread=False, patch_multiprocessing=True); '
+                    'connect(\\"127.0.0.1\\")'
+                ) % pydev_src_dir
+            ])
+        finally:
+            SetupHolder.setup = original
+
+    def test_monkey_patch_args_no_indc(self):
+        original = SetupHolder.setup
+
+        try:
+            SetupHolder.setup = {'client':'127.0.0.1', 'port': '0'}
+            check=['C:\\bin\\python.exe', 'connect(\\"127.0.0.1\\")']
+            sys.original_argv = ['my', 'original', 'argv']
+            if sys.platform == 'win32':
+                self.assertEqual(pydev_monkey.patch_args(check), [
+                    'C:\\bin\\python.exe', '"my"', '"original"', '"argv"', 'connect(\\"127.0.0.1\\")'])
+            else:
+                self.assertEqual(pydev_monkey.patch_args(check), [
+                    'C:\\bin\\python.exe', 'my', 'original', 'argv', 'connect(\\"127.0.0.1\\")'])
+        finally:
+            SetupHolder.setup = original
+
+    def test_monkey_patch_args_no_indc_with_pydevd(self):
+        original = SetupHolder.setup
+
+        try:
+            SetupHolder.setup = {'client':'127.0.0.1', 'port': '0'}
+            check=['C:\\bin\\python.exe', 'pydevd.py', 'connect(\\"127.0.0.1\\")', 'bar']
+            sys.original_argv = ['my', 'original', 'argv']
+
+            self.assertEqual(pydev_monkey.patch_args(check), [
+                'C:\\bin\\python.exe', 'pydevd.py', 'connect(\\"127.0.0.1\\")', 'bar'])
+        finally:
+            SetupHolder.setup = original
+
+    def test_monkey_patch_args_no_indc_without_pydevd(self):
+        original = SetupHolder.setup
+
+        try:
+            SetupHolder.setup = {'client':'127.0.0.1', 'port': '0'}
+            check=['C:\\bin\\python.exe', 'target.py', 'connect(\\"127.0.0.1\\")', 'bar']
+            sys.original_argv = ['pydevd.py', '--a=1', 'b', '--c=2', '--file', 'ignore_this.py']
+
+            if sys.platform == 'win32':
+                self.assertEqual(pydev_monkey.patch_args(check), [
+                    'C:\\bin\\python.exe',
+                    '"pydevd.py"',
+                    '"--a=1"',
+                    '"b"',
+                    '"--c=2"',
+                    '"--file"',
+                    'target.py',
+                    'connect(\\"127.0.0.1\\")',
+                    'bar',
+                ])
+            else:
+                self.assertEqual(pydev_monkey.patch_args(check), [
+                    'C:\\bin\\python.exe',
+                    'pydevd.py',
+                    '--a=1',
+                    'b',
+                    '--c=2',
+                    '--file',
+                    'target.py',
+                    'connect(\\"127.0.0.1\\")',
+                    'bar',
+                ])
+        finally:
+            SetupHolder.setup = original
+
 if __name__ == '__main__':
     unittest.main()
\ No newline at end of file
diff --git a/plugins/org.python.pydev/pysrc/third_party/pep8/autopep8.py b/plugins/org.python.pydev/pysrc/third_party/pep8/autopep8.py
new file mode 100644
index 0000000..224b5c6
--- /dev/null
+++ b/plugins/org.python.pydev/pysrc/third_party/pep8/autopep8.py
@@ -0,0 +1,3687 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2010-2011 Hideo Hattori
+# Copyright (C) 2011-2013 Hideo Hattori, Steven Myint
+# Copyright (C) 2013-2014 Hideo Hattori, Steven Myint, Bill Wendling
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""Automatically formats Python code to conform to the PEP 8 style guide.
+
+Fixes that only need be done once can be added by adding a function of the form
+"fix_<code>(source)" to this module. They should return the fixed source code.
+These fixes are picked up by apply_global_fixes().
+
+Fixes that depend on pep8 should be added as methods to FixPEP8. See the class
+documentation for more information.
+
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import bisect
+import codecs
+import collections
+import copy
+import difflib
+import fnmatch
+import inspect
+import io
+import itertools
+import keyword
+import locale
+import os
+import re
+import signal
+import sys
+import token
+import tokenize
+
+import pep8
+
+
+try:
+    unicode
+except NameError:
+    unicode = str
+
+
+__version__ = '1.0.3'
+
+
+CR = '\r'
+LF = '\n'
+CRLF = '\r\n'
+
+
+PYTHON_SHEBANG_REGEX = re.compile(r'^#!.*\bpython[23]?\b\s*$')
+
+
+# For generating line shortening candidates.
+SHORTEN_OPERATOR_GROUPS = frozenset([
+    frozenset([',']),
+    frozenset(['%']),
+    frozenset([',', '(', '[', '{']),
+    frozenset(['%', '(', '[', '{']),
+    frozenset([',', '(', '[', '{', '%', '+', '-', '*', '/', '//']),
+    frozenset(['%', '+', '-', '*', '/', '//']),
+])
+
+
+DEFAULT_IGNORE = 'E24'
+DEFAULT_INDENT_SIZE = 4
+
+
+# W602 is handled separately due to the need to avoid "with_traceback".
+CODE_TO_2TO3 = {
+    'E721': ['idioms'],
+    'W601': ['has_key'],
+    'W603': ['ne'],
+    'W604': ['repr'],
+    'W690': ['apply',
+             'except',
+             'exitfunc',
+             'import',
+             'numliterals',
+             'operator',
+             'paren',
+             'reduce',
+             'renames',
+             'standarderror',
+             'sys_exc',
+             'throw',
+             'tuple_params',
+             'xreadlines']}
+
+
+def check_lib2to3():
+    try:
+        import lib2to3
+    except ImportError:
+        sys.path.append(os.path.join(os.path.dirname(__file__), 'lib2to3'))
+        import lib2to3
+
+
+def open_with_encoding(filename, encoding=None, mode='r'):
+    """Return opened file with a specific encoding."""
+    if not encoding:
+        encoding = detect_encoding(filename)
+
+    return io.open(filename, mode=mode, encoding=encoding,
+                   newline='')  # Preserve line endings
+
+
+def detect_encoding(filename):
+    """Return file encoding."""
+    try:
+        with open(filename, 'rb') as input_file:
+            check_lib2to3()
+            from lib2to3.pgen2 import tokenize as lib2to3_tokenize
+            encoding = lib2to3_tokenize.detect_encoding(input_file.readline)[0]
+
+        # Check for correctness of encoding
+        with open_with_encoding(filename, encoding) as test_file:
+            test_file.read()
+
+        return encoding
+    except (LookupError, SyntaxError, UnicodeDecodeError):
+        return 'latin-1'
+
+
+def readlines_from_file(filename):
+    """Return contents of file."""
+    with open_with_encoding(filename) as input_file:
+        return input_file.readlines()
+
+
+def extended_blank_lines(logical_line,
+                         blank_lines,
+                         indent_level,
+                         previous_logical):
+    """Check for missing blank lines after class declaration."""
+    if previous_logical.startswith('class '):
+        if (
+            logical_line.startswith(('def ', 'class ', '@')) or
+            pep8.DOCSTRING_REGEX.match(logical_line)
+        ):
+            if indent_level and not blank_lines:
+                yield (0, 'E309 expected 1 blank line after class declaration')
+    elif previous_logical.startswith('def '):
+        if blank_lines and pep8.DOCSTRING_REGEX.match(logical_line):
+            yield (0, 'E303 too many blank lines ({0})'.format(blank_lines))
+    elif pep8.DOCSTRING_REGEX.match(previous_logical):
+        # Missing blank line between class docstring and method declaration.
+        if (
+            indent_level and
+            not blank_lines and
+            logical_line.startswith(('def ')) and
+            '(self' in logical_line
+        ):
+            yield (0, 'E301 expected 1 blank line, found 0')
+pep8.register_check(extended_blank_lines)
+
+
+def continued_indentation(logical_line, tokens, indent_level, indent_char,
+                          noqa):
+    """Override pep8's function to provide indentation information."""
+    first_row = tokens[0][2][0]
+    nrows = 1 + tokens[-1][2][0] - first_row
+    if noqa or nrows == 1:
+        return
+
+    # indent_next tells us whether the next block is indented. Assuming
+    # that it is indented by 4 spaces, then we should not allow 4-space
+    # indents on the final continuation line. In turn, some other
+    # indents are allowed to have an extra 4 spaces.
+    indent_next = logical_line.endswith(':')
+
+    row = depth = 0
+    valid_hangs = (
+        (DEFAULT_INDENT_SIZE,)
+        if indent_char != '\t' else (DEFAULT_INDENT_SIZE,
+                                     2 * DEFAULT_INDENT_SIZE)
+    )
+
+    # Remember how many brackets were opened on each line.
+    parens = [0] * nrows
+
+    # Relative indents of physical lines.
+    rel_indent = [0] * nrows
+
+    # For each depth, collect a list of opening rows.
+    open_rows = [[0]]
+    # For each depth, memorize the hanging indentation.
+    hangs = [None]
+
+    # Visual indents.
+    indent_chances = {}
+    last_indent = tokens[0][2]
+    indent = [last_indent[1]]
+
+    last_token_multiline = None
+    line = None
+    last_line = ''
+    last_line_begins_with_multiline = False
+    for token_type, text, start, end, line in tokens:
+
+        newline = row < start[0] - first_row
+        if newline:
+            row = start[0] - first_row
+            newline = (not last_token_multiline and
+                       token_type not in (tokenize.NL, tokenize.NEWLINE))
+            last_line_begins_with_multiline = last_token_multiline
+
+        if newline:
+            # This is the beginning of a continuation line.
+            last_indent = start
+
+            # Record the initial indent.
+            rel_indent[row] = pep8.expand_indent(line) - indent_level
+
+            # Identify closing bracket.
+            close_bracket = (token_type == tokenize.OP and text in ']})')
+
+            # Is the indent relative to an opening bracket line?
+            for open_row in reversed(open_rows[depth]):
+                hang = rel_indent[row] - rel_indent[open_row]
+                hanging_indent = hang in valid_hangs
+                if hanging_indent:
+                    break
+            if hangs[depth]:
+                hanging_indent = (hang == hangs[depth])
+
+            visual_indent = (not close_bracket and hang > 0 and
+                             indent_chances.get(start[1]))
+
+            if close_bracket and indent[depth]:
+                # Closing bracket for visual indent.
+                if start[1] != indent[depth]:
+                    yield (start, 'E124 {0}'.format(indent[depth]))
+            elif close_bracket and not hang:
+                pass
+            elif indent[depth] and start[1] < indent[depth]:
+                # Visual indent is broken.
+                yield (start, 'E128 {0}'.format(indent[depth]))
+            elif (hanging_indent or
+                  (indent_next and
+                   rel_indent[row] == 2 * DEFAULT_INDENT_SIZE)):
+                # Hanging indent is verified.
+                if close_bracket:
+                    yield (start, 'E123 {0}'.format(indent_level +
+                                                    rel_indent[open_row]))
+                hangs[depth] = hang
+            elif visual_indent is True:
+                # Visual indent is verified.
+                indent[depth] = start[1]
+            elif visual_indent in (text, unicode):
+                # Ignore token lined up with matching one from a previous line.
+                pass
+            else:
+                one_indented = (indent_level + rel_indent[open_row] +
+                                DEFAULT_INDENT_SIZE)
+                # Indent is broken.
+                if hang <= 0:
+                    error = ('E122', one_indented)
+                elif indent[depth]:
+                    error = ('E127', indent[depth])
+                elif hang > DEFAULT_INDENT_SIZE:
+                    error = ('E126', one_indented)
+                else:
+                    hangs[depth] = hang
+                    error = ('E121', one_indented)
+
+                yield (start, '{0} {1}'.format(*error))
+
+        # Look for visual indenting.
+        if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
+                and not indent[depth]):
+            indent[depth] = start[1]
+            indent_chances[start[1]] = True
+        # Deal with implicit string concatenation.
+        elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
+              text in ('u', 'ur', 'b', 'br')):
+            indent_chances[start[1]] = unicode
+        # Special case for the "if" statement because len("if (") is equal to
+        # 4.
+        elif not indent_chances and not row and not depth and text == 'if':
+            indent_chances[end[1] + 1] = True
+        elif text == ':' and line[end[1]:].isspace():
+            open_rows[depth].append(row)
+
+        # Keep track of bracket depth.
+        if token_type == tokenize.OP:
+            if text in '([{':
+                depth += 1
+                indent.append(0)
+                hangs.append(None)
+                if len(open_rows) == depth:
+                    open_rows.append([])
+                open_rows[depth].append(row)
+                parens[row] += 1
+            elif text in ')]}' and depth > 0:
+                # Parent indents should not be more than this one.
+                prev_indent = indent.pop() or last_indent[1]
+                hangs.pop()
+                for d in range(depth):
+                    if indent[d] > prev_indent:
+                        indent[d] = 0
+                for ind in list(indent_chances):
+                    if ind >= prev_indent:
+                        del indent_chances[ind]
+                del open_rows[depth + 1:]
+                depth -= 1
+                if depth:
+                    indent_chances[indent[depth]] = True
+                for idx in range(row, -1, -1):
+                    if parens[idx]:
+                        parens[idx] -= 1
+                        break
+            assert len(indent) == depth + 1
+            if (
+                start[1] not in indent_chances and
+                # This is for purposes of speeding up E121 (GitHub #90).
+                not last_line.rstrip().endswith(',')
+            ):
+                # Allow to line up tokens.
+                indent_chances[start[1]] = text
+
+        last_token_multiline = (start[0] != end[0])
+        if last_token_multiline:
+            rel_indent[end[0] - first_row] = rel_indent[row]
+
+        last_line = line
+
+    if (
+        indent_next and
+        not last_line_begins_with_multiline and
+        pep8.expand_indent(line) == indent_level + DEFAULT_INDENT_SIZE
+    ):
+        pos = (start[0], indent[0] + 4)
+        yield (pos, 'E125 {0}'.format(indent_level +
+                                      2 * DEFAULT_INDENT_SIZE))
+del pep8._checks['logical_line'][pep8.continued_indentation]
+pep8.register_check(continued_indentation)
+
+
+class FixPEP8(object):
+
+    """Fix invalid code.
+
+    Fixer methods are prefixed "fix_". The _fix_source() method looks for these
+    automatically.
+
+    The fixer method can take either one or two arguments (in addition to
+    self). The first argument is "result", which is the error information from
+    pep8. The second argument, "logical", is required only for logical-line
+    fixes.
+
+    The fixer method can return the list of modified lines or None. An empty
+    list would mean that no changes were made. None would mean that only the
+    line reported in the pep8 error was modified. Note that the modified line
+    numbers that are returned are indexed at 1. This typically would correspond
+    with the line number reported in the pep8 error information.
+
+    [fixed method list]
+        - e121,e122,e123,e124,e125,e126,e127,e128,e129
+        - e201,e202,e203
+        - e211
+        - e221,e222,e223,e224,e225
+        - e231
+        - e251
+        - e261,e262
+        - e271,e272,e273,e274
+        - e301,e302,e303
+        - e401
+        - e502
+        - e701,e702
+        - e711
+        - w291
+
+    """
+
+    def __init__(self, filename,
+                 options,
+                 contents=None,
+                 long_line_ignore_cache=None):
+        self.filename = filename
+        if contents is None:
+            self.source = readlines_from_file(filename)
+        else:
+            sio = io.StringIO(contents)
+            self.source = sio.readlines()
+        self.options = options
+        self.indent_word = _get_indentword(''.join(self.source))
+
+        self.long_line_ignore_cache = (
+            set() if long_line_ignore_cache is None
+            else long_line_ignore_cache)
+
+        # Many fixers are the same even though pep8 categorizes them
+        # differently.
+        self.fix_e115 = self.fix_e112
+        self.fix_e116 = self.fix_e113
+        self.fix_e121 = self._fix_reindent
+        self.fix_e122 = self._fix_reindent
+        self.fix_e123 = self._fix_reindent
+        self.fix_e124 = self._fix_reindent
+        self.fix_e126 = self._fix_reindent
+        self.fix_e127 = self._fix_reindent
+        self.fix_e128 = self._fix_reindent
+        self.fix_e129 = self._fix_reindent
+        self.fix_e202 = self.fix_e201
+        self.fix_e203 = self.fix_e201
+        self.fix_e211 = self.fix_e201
+        self.fix_e221 = self.fix_e271
+        self.fix_e222 = self.fix_e271
+        self.fix_e223 = self.fix_e271
+        self.fix_e226 = self.fix_e225
+        self.fix_e227 = self.fix_e225
+        self.fix_e228 = self.fix_e225
+        self.fix_e241 = self.fix_e271
+        self.fix_e242 = self.fix_e224
+        self.fix_e261 = self.fix_e262
+        self.fix_e272 = self.fix_e271
+        self.fix_e273 = self.fix_e271
+        self.fix_e274 = self.fix_e271
+        self.fix_e309 = self.fix_e301
+        self.fix_e501 = (
+            self.fix_long_line_logically if
+            options and (options.aggressive >= 2 or options.experimental) else
+            self.fix_long_line_physically)
+        self.fix_e703 = self.fix_e702
+
+        self._ws_comma_done = False
+
+    def _fix_source(self, results):
+        try:
+            (logical_start, logical_end) = _find_logical(self.source)
+            logical_support = True
+        except (SyntaxError, tokenize.TokenError):  # pragma: no cover
+            logical_support = False
+
+        completed_lines = set()
+        for result in sorted(results, key=_priority_key):
+            if result['line'] in completed_lines:
+                continue
+
+            fixed_methodname = 'fix_' + result['id'].lower()
+            if hasattr(self, fixed_methodname):
+                fix = getattr(self, fixed_methodname)
+
+                line_index = result['line'] - 1
+                original_line = self.source[line_index]
+
+                is_logical_fix = len(inspect.getargspec(fix).args) > 2
+                if is_logical_fix:
+                    logical = None
+                    if logical_support:
+                        logical = _get_logical(self.source,
+                                               result,
+                                               logical_start,
+                                               logical_end)
+                        if logical and set(range(
+                            logical[0][0] + 1,
+                            logical[1][0] + 1)).intersection(
+                                completed_lines):
+                            continue
+
+                    modified_lines = fix(result, logical)
+                else:
+                    modified_lines = fix(result)
+
+                if modified_lines is None:
+                    # Force logical fixes to report what they modified.
+                    assert not is_logical_fix
+
+                    if self.source[line_index] == original_line:
+                        modified_lines = []
+
+                if modified_lines:
+                    completed_lines.update(modified_lines)
+                elif modified_lines == []:  # Empty list means no fix
+                    if self.options.verbose >= 2:
+                        print(
+                            '--->  Not fixing {f} on line {l}'.format(
+                                f=result['id'], l=result['line']),
+                            file=sys.stderr)
+                else:  # We assume one-line fix when None.
+                    completed_lines.add(result['line'])
+            else:
+                if self.options.verbose >= 3:
+                    print(
+                        "--->  '{0}' is not defined.".format(fixed_methodname),
+                        file=sys.stderr)
+
+                    info = result['info'].strip()
+                    print('--->  {0}:{1}:{2}:{3}'.format(self.filename,
+                                                         result['line'],
+                                                         result['column'],
+                                                         info),
+                          file=sys.stderr)
+
+    def fix(self):
+        """Return a version of the source code with PEP 8 violations fixed."""
+        pep8_options = {
+            'ignore': self.options.ignore,
+            'select': self.options.select,
+            'max_line_length': self.options.max_line_length,
+        }
+        results = _execute_pep8(pep8_options, self.source)
+
+        if self.options.verbose:
+            progress = {}
+            for r in results:
+                if r['id'] not in progress:
+                    progress[r['id']] = set()
+                progress[r['id']].add(r['line'])
+            print('--->  {n} issue(s) to fix {progress}'.format(
+                n=len(results), progress=progress), file=sys.stderr)
+
+        if self.options.line_range:
+            start, end = self.options.line_range
+            results = [r for r in results
+                       if start <= r['line'] <= end]
+
+        self._fix_source(filter_results(source=''.join(self.source),
+                                        results=results,
+                                        aggressive=self.options.aggressive))
+
+        if self.options.line_range:
+            # If number of lines has changed then change line_range.
+            count = sum(sline.count('\n')
+                        for sline in self.source[start - 1:end])
+            self.options.line_range[1] = start + count - 1
+
+        return ''.join(self.source)
+
+    def _fix_reindent(self, result):
+        """Fix a badly indented line.
+
+        This is done by adding or removing from its initial indent only.
+
+        """
+        num_indent_spaces = int(result['info'].split()[1])
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        self.source[line_index] = ' ' * num_indent_spaces + target.lstrip()
+
+    def fix_e112(self, result):
+        """Fix under-indented comments."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        if not target.lstrip().startswith('#'):
+            # Don't screw with invalid syntax.
+            return []
+
+        self.source[line_index] = self.indent_word + target
+
+    def fix_e113(self, result):
+        """Fix over-indented comments."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        indent = _get_indentation(target)
+        stripped = target.lstrip()
+
+        if not stripped.startswith('#'):
+            # Don't screw with invalid syntax.
+            return []
+
+        self.source[line_index] = indent[1:] + stripped
+
+    def fix_e125(self, result):
+        """Fix indentation undistinguish from the next logical line."""
+        num_indent_spaces = int(result['info'].split()[1])
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        spaces_to_add = num_indent_spaces - len(_get_indentation(target))
+        indent = len(_get_indentation(target))
+        modified_lines = []
+
+        while len(_get_indentation(self.source[line_index])) >= indent:
+            self.source[line_index] = (' ' * spaces_to_add +
+                                       self.source[line_index])
+            modified_lines.append(1 + line_index)  # Line indexed at 1.
+            line_index -= 1
+
+        return modified_lines
+
+    def fix_e201(self, result):
+        """Remove extraneous whitespace."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column'] - 1
+
+        if is_probably_part_of_multiline(target):
+            return []
+
+        fixed = fix_whitespace(target,
+                               offset=offset,
+                               replacement='')
+
+        self.source[line_index] = fixed
+
+    def fix_e224(self, result):
+        """Remove extraneous whitespace around operator."""
+        target = self.source[result['line'] - 1]
+        offset = result['column'] - 1
+        fixed = target[:offset] + target[offset:].replace('\t', ' ')
+        self.source[result['line'] - 1] = fixed
+
+    def fix_e225(self, result):
+        """Fix missing whitespace around operator."""
+        target = self.source[result['line'] - 1]
+        offset = result['column'] - 1
+        fixed = target[:offset] + ' ' + target[offset:]
+
+        # Only proceed if non-whitespace characters match.
+        # And make sure we don't break the indentation.
+        if (
+            fixed.replace(' ', '') == target.replace(' ', '') and
+            _get_indentation(fixed) == _get_indentation(target)
+        ):
+            self.source[result['line'] - 1] = fixed
+        else:
+            return []
+
+    def fix_e231(self, result):
+        """Add missing whitespace."""
+        # Optimize for comma case. This will fix all commas in the full source
+        # code in one pass. Don't do this more than once. If it fails the first
+        # time, there is no point in trying again.
+        if ',' in result['info'] and not self._ws_comma_done:
+            self._ws_comma_done = True
+            original = ''.join(self.source)
+            new = refactor(original, ['ws_comma'])
+            if original.strip() != new.strip():
+                self.source = [new]
+                return range(1, 1 + len(original))
+
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column']
+        fixed = target[:offset] + ' ' + target[offset:]
+        self.source[line_index] = fixed
+
+    def fix_e251(self, result):
+        """Remove whitespace around parameter '=' sign."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        # This is necessary since pep8 sometimes reports columns that goes
+        # past the end of the physical line. This happens in cases like,
+        # foo(bar\n=None)
+        c = min(result['column'] - 1,
+                len(target) - 1)
+
+        if target[c].strip():
+            fixed = target
+        else:
+            fixed = target[:c].rstrip() + target[c:].lstrip()
+
+        # There could be an escaped newline
+        #
+        #     def foo(a=\
+        #             1)
+        if fixed.endswith(('=\\\n', '=\\\r\n', '=\\\r')):
+            self.source[line_index] = fixed.rstrip('\n\r \t\\')
+            self.source[line_index + 1] = self.source[line_index + 1].lstrip()
+            return [line_index + 1, line_index + 2]  # Line indexed at 1
+
+        self.source[result['line'] - 1] = fixed
+
+    def fix_e262(self, result):
+        """Fix spacing after comment hash."""
+        target = self.source[result['line'] - 1]
+        offset = result['column']
+
+        code = target[:offset].rstrip(' \t#')
+        comment = target[offset:].lstrip(' \t#')
+
+        fixed = code + ('  # ' + comment if comment.strip() else '\n')
+
+        self.source[result['line'] - 1] = fixed
+
+    def fix_e271(self, result):
+        """Fix extraneous whitespace around keywords."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column'] - 1
+
+        if is_probably_part_of_multiline(target):
+            return []
+
+        fixed = fix_whitespace(target,
+                               offset=offset,
+                               replacement=' ')
+
+        if fixed == target:
+            return []
+        else:
+            self.source[line_index] = fixed
+
+    def fix_e301(self, result):
+        """Add missing blank line."""
+        cr = '\n'
+        self.source[result['line'] - 1] = cr + self.source[result['line'] - 1]
+
+    def fix_e302(self, result):
+        """Add missing 2 blank lines."""
+        add_linenum = 2 - int(result['info'].split()[-1])
+        cr = '\n' * add_linenum
+        self.source[result['line'] - 1] = cr + self.source[result['line'] - 1]
+
+    def fix_e303(self, result):
+        """Remove extra blank lines."""
+        delete_linenum = int(result['info'].split('(')[1].split(')')[0]) - 2
+        delete_linenum = max(1, delete_linenum)
+
+        # We need to count because pep8 reports an offset line number if there
+        # are comments.
+        cnt = 0
+        line = result['line'] - 2
+        modified_lines = []
+        while cnt < delete_linenum and line >= 0:
+            if not self.source[line].strip():
+                self.source[line] = ''
+                modified_lines.append(1 + line)  # Line indexed at 1
+                cnt += 1
+            line -= 1
+
+        return modified_lines
+
+    def fix_e304(self, result):
+        """Remove blank line following function decorator."""
+        line = result['line'] - 2
+        if not self.source[line].strip():
+            self.source[line] = ''
+
+    def fix_e401(self, result):
+        """Put imports on separate lines."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column'] - 1
+
+        if not target.lstrip().startswith('import'):
+            return []
+
+        indentation = re.split(pattern=r'\bimport\b',
+                               string=target, maxsplit=1)[0]
+        fixed = (target[:offset].rstrip('\t ,') + '\n' +
+                 indentation + 'import ' + target[offset:].lstrip('\t ,'))
+        self.source[line_index] = fixed
+
+    def fix_long_line_logically(self, result, logical):
+        """Try to make lines fit within --max-line-length characters."""
+        if (
+            not logical or
+            len(logical[2]) == 1 or
+            self.source[result['line'] - 1].lstrip().startswith('#')
+        ):
+            return self.fix_long_line_physically(result)
+
+        start_line_index = logical[0][0]
+        end_line_index = logical[1][0]
+        logical_lines = logical[2]
+
+        previous_line = get_item(self.source, start_line_index - 1, default='')
+        next_line = get_item(self.source, end_line_index + 1, default='')
+
+        single_line = join_logical_line(''.join(logical_lines))
+
+        try:
+            fixed = self.fix_long_line(
+                target=single_line,
+                previous_line=previous_line,
+                next_line=next_line,
+                original=''.join(logical_lines))
+        except (SyntaxError, tokenize.TokenError):
+            return self.fix_long_line_physically(result)
+
+        if fixed:
+            for line_index in range(start_line_index, end_line_index + 1):
+                self.source[line_index] = ''
+            self.source[start_line_index] = fixed
+            return range(start_line_index + 1, end_line_index + 1)
+        else:
+            return []
+
+    def fix_long_line_physically(self, result):
+        """Try to make lines fit within --max-line-length characters."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        previous_line = get_item(self.source, line_index - 1, default='')
+        next_line = get_item(self.source, line_index + 1, default='')
+
+        try:
+            fixed = self.fix_long_line(
+                target=target,
+                previous_line=previous_line,
+                next_line=next_line,
+                original=target)
+        except (SyntaxError, tokenize.TokenError):
+            return []
+
+        if fixed:
+            self.source[line_index] = fixed
+            return [line_index + 1]
+        else:
+            return []
+
+    def fix_long_line(self, target, previous_line,
+                      next_line, original):
+        cache_entry = (target, previous_line, next_line)
+        if cache_entry in self.long_line_ignore_cache:
+            return []
+
+        if target.lstrip().startswith('#'):
+            # Wrap commented lines.
+            return shorten_comment(
+                line=target,
+                max_line_length=self.options.max_line_length,
+                last_comment=not next_line.lstrip().startswith('#'))
+
+        fixed = get_fixed_long_line(
+            target=target,
+            previous_line=previous_line,
+            original=original,
+            indent_word=self.indent_word,
+            max_line_length=self.options.max_line_length,
+            aggressive=self.options.aggressive,
+            experimental=self.options.experimental,
+            verbose=self.options.verbose)
+        if fixed and not code_almost_equal(original, fixed):
+            return fixed
+        else:
+            self.long_line_ignore_cache.add(cache_entry)
+            return None
+
+    def fix_e502(self, result):
+        """Remove extraneous escape of newline."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        self.source[line_index] = target.rstrip('\n\r \t\\') + '\n'
+
+    def fix_e701(self, result):
+        """Put colon-separated compound statement on separate lines."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        c = result['column']
+
+        fixed_source = (target[:c] + '\n' +
+                        _get_indentation(target) + self.indent_word +
+                        target[c:].lstrip('\n\r \t\\'))
+        self.source[result['line'] - 1] = fixed_source
+        return [result['line'], result['line'] + 1]
+
+    def fix_e702(self, result, logical):
+        """Put semicolon-separated compound statement on separate lines."""
+        if not logical:
+            return []  # pragma: no cover
+        logical_lines = logical[2]
+
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        if target.rstrip().endswith('\\'):
+            # Normalize '1; \\\n2' into '1; 2'.
+            self.source[line_index] = target.rstrip('\n \r\t\\')
+            self.source[line_index + 1] = self.source[line_index + 1].lstrip()
+            return [line_index + 1, line_index + 2]
+
+        if target.rstrip().endswith(';'):
+            self.source[line_index] = target.rstrip('\n \r\t;') + '\n'
+            return [line_index + 1]
+
+        offset = result['column'] - 1
+        first = target[:offset].rstrip(';').rstrip()
+        second = (_get_indentation(logical_lines[0]) +
+                  target[offset:].lstrip(';').lstrip())
+
+        self.source[line_index] = first + '\n' + second
+        return [line_index + 1]
+
+    def fix_e711(self, result):
+        """Fix comparison with None."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column'] - 1
+
+        right_offset = offset + 2
+        if right_offset >= len(target):
+            return []
+
+        left = target[:offset].rstrip()
+        center = target[offset:right_offset]
+        right = target[right_offset:].lstrip()
+
+        if not right.startswith('None'):
+            return []
+
+        if center.strip() == '==':
+            new_center = 'is'
+        elif center.strip() == '!=':
+            new_center = 'is not'
+        else:
+            return []
+
+        self.source[line_index] = ' '.join([left, new_center, right])
+
+    def fix_e712(self, result):
+        """Fix comparison with boolean."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+        offset = result['column'] - 1
+
+        # Handle very easy "not" special cases.
+        if re.match(r'^\s*if \w+ == False:$', target):
+            self.source[line_index] = re.sub(r'if (\w+) == False:',
+                                             r'if not \1:', target, count=1)
+        elif re.match(r'^\s*if \w+ != True:$', target):
+            self.source[line_index] = re.sub(r'if (\w+) != True:',
+                                             r'if not \1:', target, count=1)
+        else:
+            right_offset = offset + 2
+            if right_offset >= len(target):
+                return []
+
+            left = target[:offset].rstrip()
+            center = target[offset:right_offset]
+            right = target[right_offset:].lstrip()
+
+            # Handle simple cases only.
+            new_right = None
+            if center.strip() == '==':
+                if re.match(r'\bTrue\b', right):
+                    new_right = re.sub(r'\bTrue\b *', '', right, count=1)
+            elif center.strip() == '!=':
+                if re.match(r'\bFalse\b', right):
+                    new_right = re.sub(r'\bFalse\b *', '', right, count=1)
+
+            if new_right is None:
+                return []
+
+            if new_right[0].isalnum():
+                new_right = ' ' + new_right
+
+            self.source[line_index] = left + new_right
+
+    def fix_e713(self, result):
+        """Fix non-membership check."""
+        line_index = result['line'] - 1
+        target = self.source[line_index]
+
+        # Handle very easy case only.
+        if re.match(r'^\s*if not \w+ in \w+:$', target):
+            self.source[line_index] = re.sub(r'if not (\w+) in (\w+):',
+                                             r'if \1 not in \2:',
+                                             target,
+                                             count=1)
+
+    def fix_w291(self, result):
+        """Remove trailing whitespace."""
+        fixed_line = self.source[result['line'] - 1].rstrip()
+        self.source[result['line'] - 1] = fixed_line + '\n'
+
+
+def get_fixed_long_line(target, previous_line, original,
+                        indent_word='    ', max_line_length=79,
+                        aggressive=False, experimental=False, verbose=False):
+    """Break up long line and return result.
+
+    Do this by generating multiple reformatted candidates and then
+    ranking the candidates to heuristically select the best option.
+
+    """
+    indent = _get_indentation(target)
+    source = target[len(indent):]
+    assert source.lstrip() == source
+
+    # Check for partial multiline.
+    tokens = list(generate_tokens(source))
+
+    candidates = shorten_line(
+        tokens, source, indent,
+        indent_word,
+        max_line_length,
+        aggressive=aggressive,
+        experimental=experimental,
+        previous_line=previous_line)
+
+    # Also sort alphabetically as a tie breaker (for determinism).
+    candidates = sorted(
+        sorted(set(candidates).union([target, original])),
+        key=lambda x: line_shortening_rank(x,
+                                           indent_word,
+                                           max_line_length,
+                                           experimental))
+
+    if verbose >= 4:
+        print(('-' * 79 + '\n').join([''] + candidates + ['']),
+              file=codecs.getwriter('utf-8')(sys.stderr.buffer
+                                             if hasattr(sys.stderr,
+                                                        'buffer')
+                                             else sys.stderr))
+
+    if candidates:
+        return candidates[0]
+
+
+def join_logical_line(logical_line):
+    """Return single line based on logical line input."""
+    indentation = _get_indentation(logical_line)
+
+    return indentation + untokenize_without_newlines(
+        generate_tokens(logical_line.lstrip())) + '\n'
+
+
+def untokenize_without_newlines(tokens):
+    """Return source code based on tokens."""
+    text = ''
+    last_row = 0
+    last_column = -1
+
+    for t in tokens:
+        token_string = t[1]
+        (start_row, start_column) = t[2]
+        (end_row, end_column) = t[3]
+
+        if start_row > last_row:
+            last_column = 0
+        if (
+            (start_column > last_column or token_string == '\n') and
+            not text.endswith(' ')
+        ):
+            text += ' '
+
+        if token_string != '\n':
+            text += token_string
+
+        last_row = end_row
+        last_column = end_column
+
+    return text
+
+
+def _find_logical(source_lines):
+    # Make a variable which is the index of all the starts of lines.
+    logical_start = []
+    logical_end = []
+    last_newline = True
+    parens = 0
+    for t in generate_tokens(''.join(source_lines)):
+        if t[0] in [tokenize.COMMENT, tokenize.DEDENT,
+                    tokenize.INDENT, tokenize.NL,
+                    tokenize.ENDMARKER]:
+            continue
+        if not parens and t[0] in [tokenize.NEWLINE, tokenize.SEMI]:
+            last_newline = True
+            logical_end.append((t[3][0] - 1, t[2][1]))
+            continue
+        if last_newline and not parens:
+            logical_start.append((t[2][0] - 1, t[2][1]))
+            last_newline = False
+        if t[0] == tokenize.OP:
+            if t[1] in '([{':
+                parens += 1
+            elif t[1] in '}])':
+                parens -= 1
+    return (logical_start, logical_end)
+
+
+def _get_logical(source_lines, result, logical_start, logical_end):
+    """Return the logical line corresponding to the result.
+
+    Assumes input is already E702-clean.
+
+    """
+    row = result['line'] - 1
+    col = result['column'] - 1
+    ls = None
+    le = None
+    for i in range(0, len(logical_start), 1):
+        assert logical_end
+        x = logical_end[i]
+        if x[0] > row or (x[0] == row and x[1] > col):
+            le = x
+            ls = logical_start[i]
+            break
+    if ls is None:
+        return None
+    original = source_lines[ls[0]:le[0] + 1]
+    return ls, le, original
+
+
+def get_item(items, index, default=None):
+    if 0 <= index < len(items):
+        return items[index]
+    else:
+        return default
+
+
+def reindent(source, indent_size):
+    """Reindent all lines."""
+    reindenter = Reindenter(source)
+    return reindenter.run(indent_size)
+
+
+def code_almost_equal(a, b):
+    """Return True if code is similar.
+
+    Ignore whitespace when comparing specific line.
+
+    """
+    split_a = split_and_strip_non_empty_lines(a)
+    split_b = split_and_strip_non_empty_lines(b)
+
+    if len(split_a) != len(split_b):
+        return False
+
+    for index in range(len(split_a)):
+        if ''.join(split_a[index].split()) != ''.join(split_b[index].split()):
+            return False
+
+    return True
+
+
+def split_and_strip_non_empty_lines(text):
+    """Return lines split by newline.
+
+    Ignore empty lines.
+
+    """
+    return [line.strip() for line in text.splitlines() if line.strip()]
+
+
+def fix_e265(source, aggressive=False):  # pylint: disable=unused-argument
+    """Format block comments."""
+    if '#' not in source:
+        # Optimization.
+        return source
+
+    ignored_line_numbers = multiline_string_lines(
+        source,
+        include_docstrings=True) | set(commented_out_code_lines(source))
+
+    fixed_lines = []
+    sio = io.StringIO(source)
+    line_number = 0
+    for line in sio.readlines():
+        line_number += 1
+        if (
+            line.lstrip().startswith('#') and
+            line_number not in ignored_line_numbers
+        ):
+            indentation = _get_indentation(line)
+            line = line.lstrip()
+
+            # Normalize beginning if not a shebang.
+            if len(line) > 1:
+                if (
+                    # Leave multiple spaces like '#    ' alone.
+                    (line.count('#') > 1 or line[1].isalnum())
+                    # Leave stylistic outlined blocks alone.
+                    and not line.rstrip().endswith('#')
+                ):
+                    line = '# ' + line.lstrip('# \t')
+
+            fixed_lines.append(indentation + line)
+        else:
+            fixed_lines.append(line)
+
+    return ''.join(fixed_lines)
+
+
+def refactor(source, fixer_names, ignore=None):
+    """Return refactored code using lib2to3.
+
+    Skip if ignore string is produced in the refactored code.
+
+    """
+    check_lib2to3()
+    from lib2to3 import pgen2
+    try:
+        new_text = refactor_with_2to3(source,
+                                      fixer_names=fixer_names)
+    except (pgen2.parse.ParseError,
+            SyntaxError,
+            UnicodeDecodeError,
+            UnicodeEncodeError):
+        return source
+
+    if ignore:
+        if ignore in new_text and ignore not in source:
+            return source
+
+    return new_text
+
+
+def code_to_2to3(select, ignore):
+    fixes = set()
+    for code, fix in CODE_TO_2TO3.items():
+        if code_match(code, select=select, ignore=ignore):
+            fixes |= set(fix)
+    return fixes
+
+
+def fix_2to3(source, aggressive=True, select=None, ignore=None):
+    """Fix various deprecated code (via lib2to3)."""
+    if not aggressive:
+        return source
+
+    select = select or []
+    ignore = ignore or []
+
+    return refactor(source,
+                    code_to_2to3(select=select,
+                                 ignore=ignore))
+
+
+def fix_w602(source, aggressive=True):
+    """Fix deprecated form of raising exception."""
+    if not aggressive:
+        return source
+
+    return refactor(source, ['raise'],
+                    ignore='with_traceback')
+
+
+def find_newline(source):
+    """Return type of newline used in source.
+
+    Input is a list of lines.
+
+    """
+    assert not isinstance(source, unicode)
+
+    counter = collections.defaultdict(int)
+    for line in source:
+        if line.endswith(CRLF):
+            counter[CRLF] += 1
+        elif line.endswith(CR):
+            counter[CR] += 1
+        elif line.endswith(LF):
+            counter[LF] += 1
+
+    return (sorted(counter, key=counter.get, reverse=True) or [LF])[0]
+
+
+def _get_indentword(source):
+    """Return indentation type."""
+    indent_word = '    '  # Default in case source has no indentation
+    try:
+        for t in generate_tokens(source):
+            if t[0] == token.INDENT:
+                indent_word = t[1]
+                break
+    except (SyntaxError, tokenize.TokenError):
+        pass
+    return indent_word
+
+
+def _get_indentation(line):
+    """Return leading whitespace."""
+    if line.strip():
+        non_whitespace_index = len(line) - len(line.lstrip())
+        return line[:non_whitespace_index]
+    else:
+        return ''
+
+
+def get_diff_text(old, new, filename):
+    """Return text of unified diff between old and new."""
+    newline = '\n'
+    diff = difflib.unified_diff(
+        old, new,
+        'original/' + filename,
+        'fixed/' + filename,
+        lineterm=newline)
+
+    text = ''
+    for line in diff:
+        text += line
+
+        # Work around missing newline (http://bugs.python.org/issue2142).
+        if text and not line.endswith(newline):
+            text += newline + r'\ No newline at end of file' + newline
+
+    return text
+
+
+def _priority_key(pep8_result):
+    """Key for sorting PEP8 results.
+
+    Global fixes should be done first. This is important for things like
+    indentation.
+
+    """
+    priority = [
+        # Fix multiline colon-based before semicolon based.
+        'e701',
+        # Break multiline statements early.
+        'e702',
+        # Things that make lines longer.
+        'e225', 'e231',
+        # Remove extraneous whitespace before breaking lines.
+        'e201',
+        # Shorten whitespace in comment before resorting to wrapping.
+        'e262'
+    ]
+    middle_index = 10000
+    lowest_priority = [
+        # We need to shorten lines last since the logical fixer can get in a
+        # loop, which causes us to exit early.
+        'e501'
+    ]
+    key = pep8_result['id'].lower()
+    try:
+        return priority.index(key)
+    except ValueError:
+        try:
+            return middle_index + lowest_priority.index(key) + 1
+        except ValueError:
+            return middle_index
+
+
+def shorten_line(tokens, source, indentation, indent_word, max_line_length,
+                 aggressive=False, experimental=False, previous_line=''):
+    """Separate line at OPERATOR.
+
+    Multiple candidates will be yielded.
+
+    """
+    for candidate in _shorten_line(tokens=tokens,
+                                   source=source,
+                                   indentation=indentation,
+                                   indent_word=indent_word,
+                                   aggressive=aggressive,
+                                   previous_line=previous_line):
+        yield candidate
+
+    if aggressive:
+        for key_token_strings in SHORTEN_OPERATOR_GROUPS:
+            shortened = _shorten_line_at_tokens(
+                tokens=tokens,
+                source=source,
+                indentation=indentation,
+                indent_word=indent_word,
+                key_token_strings=key_token_strings,
+                aggressive=aggressive)
+
+            if shortened is not None and shortened != source:
+                yield shortened
+
+    if experimental:
+        for shortened in _shorten_line_at_tokens_new(
+                tokens=tokens,
+                source=source,
+                indentation=indentation,
+                max_line_length=max_line_length):
+
+            yield shortened
+
+
+def _shorten_line(tokens, source, indentation, indent_word,
+                  aggressive=False, previous_line=''):
+    """Separate line at OPERATOR.
+
+    The input is expected to be free of newlines except for inside multiline
+    strings and at the end.
+
+    Multiple candidates will be yielded.
+
+    """
+    for (token_type,
+         token_string,
+         start_offset,
+         end_offset) in token_offsets(tokens):
+
+        if (
+            token_type == tokenize.COMMENT and
+            not is_probably_part_of_multiline(previous_line) and
+            not is_probably_part_of_multiline(source) and
+            not source[start_offset + 1:].strip().lower().startswith(
+                ('noqa', 'pragma:', 'pylint:'))
+        ):
+            # Move inline comments to previous line.
+            first = source[:start_offset]
+            second = source[start_offset:]
+            yield (indentation + second.strip() + '\n' +
+                   indentation + first.strip() + '\n')
+        elif token_type == token.OP and token_string != '=':
+            # Don't break on '=' after keyword as this violates PEP 8.
+
+            assert token_type != token.INDENT
+
+            first = source[:end_offset]
+
+            second_indent = indentation
+            if first.rstrip().endswith('('):
+                second_indent += indent_word
+            elif '(' in first:
+                second_indent += ' ' * (1 + first.find('('))
+            else:
+                second_indent += indent_word
+
+            second = (second_indent + source[end_offset:].lstrip())
+            if (
+                not second.strip() or
+                second.lstrip().startswith('#')
+            ):
+                continue
+
+            # Do not begin a line with a comma
+            if second.lstrip().startswith(','):
+                continue
+            # Do end a line with a dot
+            if first.rstrip().endswith('.'):
+                continue
+            if token_string in '+-*/':
+                fixed = first + ' \\' + '\n' + second
+            else:
+                fixed = first + '\n' + second
+
+            # Only fix if syntax is okay.
+            if check_syntax(normalize_multiline(fixed)
+                            if aggressive else fixed):
+                yield indentation + fixed
+
+
+# A convenient way to handle tokens.
+Token = collections.namedtuple('Token', ['token_type', 'token_string',
+                                         'spos', 'epos', 'line'])
+
+
+class ReformattedLines(object):
+
+    """The reflowed lines of atoms.
+
+    Each part of the line is represented as an "atom." They can be moved
+    around when need be to get the optimal formatting.
+
+    """
+
+    ###########################################################################
+    # Private Classes
+
+    class _Indent(object):
+
+        """Represent an indentation in the atom stream."""
+
+        def __init__(self, indent_amt):
+            self._indent_amt = indent_amt
+
+        def emit(self):
+            return ' ' * self._indent_amt
+
+        @property
+        def size(self):
+            return self._indent_amt
+
+    class _Space(object):
+
+        """Represent a space in the atom stream."""
+
+        def emit(self):
+            return ' '
+
+        @property
+        def size(self):
+            return 1
+
+    class _LineBreak(object):
+
+        """Represent a line break in the atom stream."""
+
+        def emit(self):
+            return '\n'
+
+        @property
+        def size(self):
+            return 0
+
+    def __init__(self, max_line_length):
+        self._max_line_length = max_line_length
+        self._lines = []
+        self._bracket_depth = 0
+        self._prev_item = None
+        self._prev_prev_item = None
+
+    def __repr__(self):
+        return self.emit()
+
+    ###########################################################################
+    # Public Methods
+
+    def add(self, obj, indent_amt, break_after_open_bracket):
+        if isinstance(obj, Atom):
+            self._add_item(obj, indent_amt)
+            return
+
+        self._add_container(obj, indent_amt, break_after_open_bracket)
+
+    def add_comment(self, item):
+        num_spaces = 2
+        if len(self._lines) > 1:
+            if isinstance(self._lines[-1], self._Space):
+                num_spaces -= 1
+            if len(self._lines) > 2:
+                if isinstance(self._lines[-2], self._Space):
+                    num_spaces -= 1
+
+        while num_spaces > 0:
+            self._lines.append(self._Space())
+            num_spaces -= 1
+        self._lines.append(item)
+
+    def add_indent(self, indent_amt):
+        self._lines.append(self._Indent(indent_amt))
+
+    def add_line_break(self, indent):
+        self._lines.append(self._LineBreak())
+        self.add_indent(len(indent))
+
+    def add_line_break_at(self, index, indent_amt):
+        self._lines.insert(index, self._LineBreak())
+        self._lines.insert(index + 1, self._Indent(indent_amt))
+
+    def add_space_if_needed(self, curr_text, equal=False):
+        if (
+            not self._lines or isinstance(
+                self._lines[-1], (self._LineBreak, self._Indent, self._Space))
+        ):
+            return
+
+        prev_text = unicode(self._prev_item)
+        prev_prev_text = (
+            unicode(self._prev_prev_item) if self._prev_prev_item else '')
+
+        if (
+            # The previous item was a keyword or identifier and the current
+            # item isn't an operator that doesn't require a space.
+            ((self._prev_item.is_keyword or self._prev_item.is_string or
+              self._prev_item.is_name or self._prev_item.is_number) and
+             (curr_text[0] not in '([{.,:}])' or
+              (curr_text[0] == '=' and equal))) or
+
+            # Don't place spaces around a '.', unless it's in an 'import'
+            # statement.
+            ((prev_prev_text != 'from' and prev_text[-1] != '.' and
+              curr_text != 'import') and
+
+             # Don't place a space before a colon.
+             curr_text[0] != ':' and
+
+             # Don't split up ending brackets by spaces.
+             ((prev_text[-1] in '}])' and curr_text[0] not in '.,}])') or
+
+              # Put a space after a colon or comma.
+              prev_text[-1] in ':,' or
+
+              # Put space around '=' if asked to.
+              (equal and prev_text == '=') or
+
+              # Put spaces around non-unary arithmetic operators.
+              ((self._prev_prev_item and
+                (prev_text not in '+-' and
+                 (self._prev_prev_item.is_name or
+                  self._prev_prev_item.is_number or
+                  self._prev_prev_item.is_string)) and
+                prev_text in ('+', '-', '%', '*', '/', '//', '**')))))
+        ):
+            self._lines.append(self._Space())
+
+    def previous_item(self):
+        """Return the previous non-whitespace item."""
+        return self._prev_item
+
+    def fits_on_current_line(self, item_extent):
+        return self.current_size() + item_extent <= self._max_line_length
+
+    def current_size(self):
+        """The size of the current line minus the indentation."""
+        size = 0
+        for item in reversed(self._lines):
+            size += item.size
+            if isinstance(item, self._LineBreak):
+                break
+
+        return size
+
+    def line_empty(self):
+        return (self._lines and
+                isinstance(self._lines[-1],
+                           (self._LineBreak, self._Indent)))
+
+    def emit(self):
+        string = ''
+        for item in self._lines:
+            if isinstance(item, self._LineBreak):
+                string = string.rstrip()
+            string += item.emit()
+
+        return string.rstrip() + '\n'
+
+    ###########################################################################
+    # Private Methods
+
+    def _add_item(self, item, indent_amt):
+        """Add an item to the line.
+
+        Reflow the line to get the best formatting after the item is
+        inserted. The bracket depth indicates if the item is being
+        inserted inside of a container or not.
+
+        """
+        if self._prev_item and self._prev_item.is_string and item.is_string:
+            # Place consecutive string literals on separate lines.
+            self._lines.append(self._LineBreak())
+            self._lines.append(self._Indent(indent_amt))
+
+        item_text = unicode(item)
+        if self._lines and self._bracket_depth:
+            # Adding the item into a container.
+            self._prevent_default_initializer_splitting(item, indent_amt)
+
+            if item_text in '.,)]}':
+                self._split_after_delimiter(item, indent_amt)
+
+        elif self._lines and not self.line_empty():
+            # Adding the item outside of a container.
+            if self.fits_on_current_line(len(item_text)):
+                self._enforce_space(item)
+
+            else:
+                # Line break for the new item.
+                self._lines.append(self._LineBreak())
+                self._lines.append(self._Indent(indent_amt))
+
+        self._lines.append(item)
+        self._prev_item, self._prev_prev_item = item, self._prev_item
+
+        if item_text in '([{':
+            self._bracket_depth += 1
+
+        elif item_text in '}])':
+            self._bracket_depth -= 1
+            assert self._bracket_depth >= 0
+
+    def _add_container(self, container, indent_amt, break_after_open_bracket):
+        actual_indent = indent_amt + 1
+
+        if (
+            unicode(self._prev_item) != '=' and
+            not self.line_empty() and
+            not self.fits_on_current_line(
+                container.size + self._bracket_depth + 2)
+        ):
+
+            if unicode(container)[0] == '(' and self._prev_item.is_name:
+                # Don't split before the opening bracket of a call.
+                break_after_open_bracket = True
+                actual_indent = indent_amt + 4
+            elif (
+                break_after_open_bracket or
+                unicode(self._prev_item) not in '([{'
+            ):
+                # If the container doesn't fit on the current line and the
+                # current line isn't empty, place the container on the next
+                # line.
+                self._lines.append(self._LineBreak())
+                self._lines.append(self._Indent(indent_amt))
+                break_after_open_bracket = False
+        else:
+            actual_indent = self.current_size() + 1
+            break_after_open_bracket = False
+
+        if isinstance(container, (ListComprehension, IfExpression)):
+            actual_indent = indent_amt
+
+        # Increase the continued indentation only if recursing on a
+        # container.
+        container.reflow(self, ' ' * actual_indent,
+                         break_after_open_bracket=break_after_open_bracket)
+
+    def _prevent_default_initializer_splitting(self, item, indent_amt):
+        """Prevent splitting between a default initializer.
+
+        When there is a default initializer, it's best to keep it all on
+        the same line. It's nicer and more readable, even if it goes
+        over the maximum allowable line length. This goes back along the
+        current line to determine if we have a default initializer, and,
+        if so, to remove extraneous whitespaces and add a line
+        break/indent before it if needed.
+
+        """
+        if unicode(item) == '=':
+            # This is the assignment in the initializer. Just remove spaces for
+            # now.
+            self._delete_whitespace()
+            return
+
+        if (not self._prev_item or not self._prev_prev_item or
+                unicode(self._prev_item) != '='):
+            return
+
+        self._delete_whitespace()
+        prev_prev_index = self._lines.index(self._prev_prev_item)
+
+        if (
+            isinstance(self._lines[prev_prev_index - 1], self._Indent) or
+            self.fits_on_current_line(item.size + 1)
+        ):
+            # The default initializer is already the only item on this line.
+            # Don't insert a newline here.
+            return
+
+        # Replace the space with a newline/indent combo.
+        if isinstance(self._lines[prev_prev_index - 1], self._Space):
+            del self._lines[prev_prev_index - 1]
+
+        self.add_line_break_at(self._lines.index(self._prev_prev_item),
+                               indent_amt)
+
+    def _split_after_delimiter(self, item, indent_amt):
+        """Split the line only after a delimiter."""
+        self._delete_whitespace()
+
+        if self.fits_on_current_line(item.size):
+            return
+
+        last_space = None
+        for item in reversed(self._lines):
+            if (
+                last_space and
+                (not isinstance(item, Atom) or not item.is_colon)
+            ):
+                break
+            else:
+                last_space = None
+            if isinstance(item, self._Space):
+                last_space = item
+            if isinstance(item, (self._LineBreak, self._Indent)):
+                return
+
+        if not last_space:
+            return
+
+        self.add_line_break_at(self._lines.index(last_space), indent_amt)
+
+    def _enforce_space(self, item):
+        """Enforce a space in certain situations.
+
+        There are cases where we will want a space where normally we
+        wouldn't put one. This just enforces the addition of a space.
+
+        """
+        if isinstance(self._lines[-1],
+                      (self._Space, self._LineBreak, self._Indent)):
+            return
+
+        if not self._prev_item:
+            return
+
+        item_text = unicode(item)
+        prev_text = unicode(self._prev_item)
+
+        # Prefer a space around a '.' in an import statement, and between the
+        # 'import' and '('.
+        if (
+            (item_text == '.' and prev_text == 'from') or
+            (item_text == 'import' and prev_text == '.') or
+            (item_text == '(' and prev_text == 'import')
+        ):
+            self._lines.append(self._Space())
+
+    def _delete_whitespace(self):
+        """Delete all whitespace from the end of the line."""
+        while isinstance(self._lines[-1], (self._Space, self._LineBreak,
+                                           self._Indent)):
+            del self._lines[-1]
+
+
+class Atom(object):
+
+    """The smallest unbreakable unit that can be reflowed."""
+
+    def __init__(self, atom):
+        self._atom = atom
+
+    def __repr__(self):
+        return self._atom.token_string
+
+    def __len__(self):
+        return self.size
+
+    def reflow(
+        self, reflowed_lines, continued_indent, extent,
+        break_after_open_bracket=False,
+        is_list_comp_or_if_expr=False,
+        next_is_dot=False
+    ):
+        if self._atom.token_type == tokenize.COMMENT:
+            reflowed_lines.add_comment(self)
+            return
+
+        total_size = extent if extent else self.size
+
+        if self._atom.token_string not in ',:([{}])':
+            # Some atoms will need an extra 1-sized space token after them.
+            total_size += 1
+
+        prev_item = reflowed_lines.previous_item()
+        if (
+            not is_list_comp_or_if_expr and
+            not reflowed_lines.fits_on_current_line(total_size) and
+            not (next_is_dot and
+                 reflowed_lines.fits_on_current_line(self.size + 1)) and
+            not reflowed_lines.line_empty() and
+            not self.is_colon and
+            not (prev_item and prev_item.is_name and
+                 unicode(self) == '(')
+        ):
+            # Start a new line if there is already something on the line and
+            # adding this atom would make it go over the max line length.
+            reflowed_lines.add_line_break(continued_indent)
+        else:
+            reflowed_lines.add_space_if_needed(unicode(self))
+
+        reflowed_lines.add(self, len(continued_indent),
+                           break_after_open_bracket)
+
+    def emit(self):
+        return self.__repr__()
+
+    @property
+    def is_keyword(self):
+        return keyword.iskeyword(self._atom.token_string)
+
+    @property
+    def is_string(self):
+        return self._atom.token_type == tokenize.STRING
+
+    @property
+    def is_name(self):
+        return self._atom.token_type == tokenize.NAME
+
+    @property
+    def is_number(self):
+        return self._atom.token_type == tokenize.NUMBER
+
+    @property
+    def is_comma(self):
+        return self._atom.token_string == ','
+
+    @property
+    def is_colon(self):
+        return self._atom.token_string == ':'
+
+    @property
+    def size(self):
+        return len(self._atom.token_string)
+
+
+class Container(object):
+
+    """Base class for all container types."""
+
+    def __init__(self, items):
+        self._items = items
+
+    def __repr__(self):
+        string = ''
+        last_was_keyword = False
+
+        for item in self._items:
+            if item.is_comma:
+                string += ', '
+            elif item.is_colon:
+                string += ': '
+            else:
+                item_string = unicode(item)
+                if (
+                    string and
+                    (last_was_keyword or
+                     (not string.endswith(tuple('([{,.:}]) ')) and
+                      not item_string.startswith(tuple('([{,.:}])'))))
+                ):
+                    string += ' '
+                string += item_string
+
+            last_was_keyword = item.is_keyword
+        return string
+
+    def __iter__(self):
+        for element in self._items:
+            yield element
+
+    def __getitem__(self, idx):
+        return self._items[idx]
+
+    def reflow(self, reflowed_lines, continued_indent,
+               break_after_open_bracket=False):
+        last_was_container = False
+        for (index, item) in enumerate(self._items):
+            next_item = get_item(self._items, index + 1)
+
+            if isinstance(item, Atom):
+                is_list_comp_or_if_expr = (
+                    isinstance(self, (ListComprehension, IfExpression)))
+                item.reflow(reflowed_lines, continued_indent,
+                            self._get_extent(index),
+                            is_list_comp_or_if_expr=is_list_comp_or_if_expr,
+                            next_is_dot=(next_item and
+                                         unicode(next_item) == '.'))
+                if last_was_container and item.is_comma:
+                    reflowed_lines.add_line_break(continued_indent)
+                last_was_container = False
+            else:  # isinstance(item, Container)
+                reflowed_lines.add(item, len(continued_indent),
+                                   break_after_open_bracket)
+                last_was_container = not isinstance(item, (ListComprehension,
+                                                           IfExpression))
+
+            if (
+                break_after_open_bracket and index == 0 and
+                # Prefer to keep empty containers together instead of
+                # separating them.
+                unicode(item) == self.open_bracket and
+                (not next_item or unicode(next_item) != self.close_bracket) and
+                (len(self._items) != 3 or not isinstance(next_item, Atom))
+            ):
+                reflowed_lines.add_line_break(continued_indent)
+                break_after_open_bracket = False
+            else:
+                next_next_item = get_item(self._items, index + 2)
+                if (
+                    unicode(item) not in ['.', '%', 'in'] and
+                    next_item and not isinstance(next_item, Container) and
+                    unicode(next_item) != ':' and
+                    next_next_item and (not isinstance(next_next_item, Atom) or
+                                        unicode(next_item) == 'not') and
+                    not reflowed_lines.line_empty() and
+                    not reflowed_lines.fits_on_current_line(
+                        self._get_extent(index + 1) + 2)
+                ):
+                    reflowed_lines.add_line_break(continued_indent)
+
+    def _get_extent(self, index):
+        """The extent of the full element.
+
+        E.g., the length of a function call or keyword.
+
+        """
+        extent = 0
+        prev_item = get_item(self._items, index - 1)
+        seen_dot = prev_item and unicode(prev_item) == '.'
+        while index < len(self._items):
+            item = get_item(self._items, index)
+            index += 1
+
+            if isinstance(item, (ListComprehension, IfExpression)):
+                break
+
+            if isinstance(item, Container):
+                if prev_item and prev_item.is_name:
+                    if seen_dot:
+                        extent += 1
+                    else:
+                        extent += item.size
+
+                    prev_item = item
+                    continue
+            elif (unicode(item) not in ['.', '=', ':', 'not'] and
+                  not item.is_name and not item.is_string):
+                break
+
+            if unicode(item) == '.':
+                seen_dot = True
+
+            extent += item.size
+            prev_item = item
+
+        return extent
+
+    @property
+    def is_string(self):
+        return False
+
+    @property
+    def size(self):
+        return len(self.__repr__())
+
+    @property
+    def is_keyword(self):
+        return False
+
+    @property
+    def is_name(self):
+        return False
+
+    @property
+    def is_comma(self):
+        return False
+
+    @property
+    def is_colon(self):
+        return False
+
+    @property
+    def open_bracket(self):
+        return None
+
+    @property
+    def close_bracket(self):
+        return None
+
+
+class Tuple(Container):
+
+    """A high-level representation of a tuple."""
+
+    @property
+    def open_bracket(self):
+        return '('
+
+    @property
+    def close_bracket(self):
+        return ')'
+
+
+class List(Container):
+
+    """A high-level representation of a list."""
+
+    @property
+    def open_bracket(self):
+        return '['
+
+    @property
+    def close_bracket(self):
+        return ']'
+
+
+class DictOrSet(Container):
+
+    """A high-level representation of a dictionary or set."""
+
+    @property
+    def open_bracket(self):
+        return '{'
+
+    @property
+    def close_bracket(self):
+        return '}'
+
+
+class ListComprehension(Container):
+
+    """A high-level representation of a list comprehension."""
+
+    @property
+    def size(self):
+        length = 0
+        for item in self._items:
+            if isinstance(item, IfExpression):
+                break
+            length += item.size
+        return length
+
+
+class IfExpression(Container):
+
+    """A high-level representation of an if-expression."""
+
+
+def _parse_container(tokens, index, for_or_if=None):
+    """Parse a high-level container, such as a list, tuple, etc."""
+
+    # Store the opening bracket.
+    items = [Atom(Token(*tokens[index]))]
+    index += 1
+
+    num_tokens = len(tokens)
+    while index < num_tokens:
+        tok = Token(*tokens[index])
+
+        if tok.token_string in ',)]}':
+            # First check if we're at the end of a list comprehension or
+            # if-expression. Don't add the ending token as part of the list
+            # comprehension or if-expression, because they aren't part of those
+            # constructs.
+            if for_or_if == 'for':
+                return (ListComprehension(items), index - 1)
+
+            elif for_or_if == 'if':
+                return (IfExpression(items), index - 1)
+
+            # We've reached the end of a container.
+            items.append(Atom(tok))
+
+            # If not, then we are at the end of a container.
+            if tok.token_string == ')':
+                # The end of a tuple.
+                return (Tuple(items), index)
+
+            elif tok.token_string == ']':
+                # The end of a list.
+                return (List(items), index)
+
+            elif tok.token_string == '}':
+                # The end of a dictionary or set.
+                return (DictOrSet(items), index)
+
+        elif tok.token_string in '([{':
+            # A sub-container is being defined.
+            (container, index) = _parse_container(tokens, index)
+            items.append(container)
+
+        elif tok.token_string == 'for':
+            (container, index) = _parse_container(tokens, index, 'for')
+            items.append(container)
+
+        elif tok.token_string == 'if':
+            (container, index) = _parse_container(tokens, index, 'if')
+            items.append(container)
+
+        else:
+            items.append(Atom(tok))
+
+        index += 1
+
+    return (None, None)
+
+
+def _parse_tokens(tokens):
+    """Parse the tokens.
+
+    This converts the tokens into a form where we can manipulate them
+    more easily.
+
+    """
+
+    index = 0
+    parsed_tokens = []
+
+    num_tokens = len(tokens)
+    while index < num_tokens:
+        tok = Token(*tokens[index])
+
+        assert tok.token_type != token.INDENT
+        if tok.token_type == tokenize.NEWLINE:
+            # There's only one newline and it's at the end.
+            break
+
+        if tok.token_string in '([{':
+            (container, index) = _parse_container(tokens, index)
+            if not container:
+                return None
+            parsed_tokens.append(container)
+        else:
+            parsed_tokens.append(Atom(tok))
+
+        index += 1
+
+    return parsed_tokens
+
+
+def _reflow_lines(parsed_tokens, indentation, max_line_length,
+                  start_on_prefix_line):
+    """Reflow the lines so that it looks nice."""
+
+    if unicode(parsed_tokens[0]) == 'def':
+        # A function definition gets indented a bit more.
+        continued_indent = indentation + ' ' * 2 * DEFAULT_INDENT_SIZE
+    else:
+        continued_indent = indentation + ' ' * DEFAULT_INDENT_SIZE
+
+    break_after_open_bracket = not start_on_prefix_line
+
+    lines = ReformattedLines(max_line_length)
+    lines.add_indent(len(indentation.lstrip('\r\n')))
+
+    if not start_on_prefix_line:
+        # If splitting after the opening bracket will cause the first element
+        # to be aligned weirdly, don't try it.
+        first_token = get_item(parsed_tokens, 0)
+        second_token = get_item(parsed_tokens, 1)
+
+        if (
+            first_token and second_token and
+            unicode(second_token)[0] == '(' and
+            len(indentation) + len(first_token) + 1 == len(continued_indent)
+        ):
+            return None
+
+    for item in parsed_tokens:
+        lines.add_space_if_needed(unicode(item), equal=True)
+
+        save_continued_indent = continued_indent
+        if start_on_prefix_line and isinstance(item, Container):
+            start_on_prefix_line = False
+            continued_indent = ' ' * (lines.current_size() + 1)
+
+        item.reflow(lines, continued_indent, break_after_open_bracket)
+        continued_indent = save_continued_indent
+
+    return lines.emit()
+
+
+def _shorten_line_at_tokens_new(tokens, source, indentation,
+                                max_line_length):
+    """Shorten the line taking its length into account.
+
+    The input is expected to be free of newlines except for inside
+    multiline strings and at the end.
+
+    """
+    # Yield the original source so to see if it's a better choice than the
+    # shortened candidate lines we generate here.
+    yield indentation + source
+
+    parsed_tokens = _parse_tokens(tokens)
+
+    if parsed_tokens:
+        # Perform two reflows. The first one starts on the same line as the
+        # prefix. The second starts on the line after the prefix.
+        fixed = _reflow_lines(parsed_tokens, indentation, max_line_length,
+                              start_on_prefix_line=True)
+        if fixed and check_syntax(normalize_multiline(fixed.lstrip())):
+            yield fixed
+
+        fixed = _reflow_lines(parsed_tokens, indentation, max_line_length,
+                              start_on_prefix_line=False)
+        if fixed and check_syntax(normalize_multiline(fixed.lstrip())):
+            yield fixed
+
+
+def _shorten_line_at_tokens(tokens, source, indentation, indent_word,
+                            key_token_strings, aggressive):
+    """Separate line by breaking at tokens in key_token_strings.
+
+    The input is expected to be free of newlines except for inside
+    multiline strings and at the end.
+
+    """
+    offsets = []
+    for (index, _t) in enumerate(token_offsets(tokens)):
+        (token_type,
+         token_string,
+         start_offset,
+         end_offset) = _t
+
+        assert token_type != token.INDENT
+
+        if token_string in key_token_strings:
+            # Do not break in containers with zero or one items.
+            unwanted_next_token = {
+                '(': ')',
+                '[': ']',
+                '{': '}'}.get(token_string)
+            if unwanted_next_token:
+                if (
+                    get_item(tokens,
+                             index + 1,
+                             default=[None, None])[1] == unwanted_next_token or
+                    get_item(tokens,
+                             index + 2,
+                             default=[None, None])[1] == unwanted_next_token
+                ):
+                    continue
+
+            if (
+                index > 2 and token_string == '(' and
+                tokens[index - 1][1] in ',(%['
+            ):
+                # Don't split after a tuple start, or before a tuple start if
+                # the tuple is in a list.
+                continue
+
+            if end_offset < len(source) - 1:
+                # Don't split right before newline.
+                offsets.append(end_offset)
+        else:
+            # Break at adjacent strings. These were probably meant to be on
+            # separate lines in the first place.
+            previous_token = get_item(tokens, index - 1)
+            if (
+                token_type == tokenize.STRING and
+                previous_token and previous_token[0] == tokenize.STRING
+            ):
+                offsets.append(start_offset)
+
+    current_indent = None
+    fixed = None
+    for line in split_at_offsets(source, offsets):
+        if fixed:
+            fixed += '\n' + current_indent + line
+
+            for symbol in '([{':
+                if line.endswith(symbol):
+                    current_indent += indent_word
+        else:
+            # First line.
+            fixed = line
+            assert not current_indent
+            current_indent = indent_word
+
+    assert fixed is not None
+
+    if check_syntax(normalize_multiline(fixed)
+                    if aggressive > 1 else fixed):
+        return indentation + fixed
+    else:
+        return None
+
+
+def token_offsets(tokens):
+    """Yield tokens and offsets."""
+    end_offset = 0
+    previous_end_row = 0
+    previous_end_column = 0
+    for t in tokens:
+        token_type = t[0]
+        token_string = t[1]
+        (start_row, start_column) = t[2]
+        (end_row, end_column) = t[3]
+
+        # Account for the whitespace between tokens.
+        end_offset += start_column
+        if previous_end_row == start_row:
+            end_offset -= previous_end_column
+
+        # Record the start offset of the token.
+        start_offset = end_offset
+
+        # Account for the length of the token itself.
+        end_offset += len(token_string)
+
+        yield (token_type,
+               token_string,
+               start_offset,
+               end_offset)
+
+        previous_end_row = end_row
+        previous_end_column = end_column
+
+
+def normalize_multiline(line):
+    """Normalize multiline-related code that will cause syntax error.
+
+    This is for purposes of checking syntax.
+
+    """
+    if line.startswith('def ') and line.rstrip().endswith(':'):
+        return line + ' pass'
+    elif line.startswith('return '):
+        return 'def _(): ' + line
+    elif line.startswith('@'):
+        return line + 'def _(): pass'
+    elif line.startswith('class '):
+        return line + ' pass'
+    elif line.startswith('if '):
+        return line + ' pass'
+    else:
+        return line
+
+
+def fix_whitespace(line, offset, replacement):
+    """Replace whitespace at offset and return fixed line."""
+    # Replace escaped newlines too
+    left = line[:offset].rstrip('\n\r \t\\')
+    right = line[offset:].lstrip('\n\r \t\\')
+    if right.startswith('#'):
+        return line
+    else:
+        return left + replacement + right
+
+
+def _execute_pep8(pep8_options, source):
+    """Execute pep8 via python method calls."""
+    class QuietReport(pep8.BaseReport):
+
+        """Version of checker that does not print."""
+
+        def __init__(self, options):
+            super(QuietReport, self).__init__(options)
+            self.__full_error_results = []
+
+        def error(self, line_number, offset, text, _):
+            """Collect errors."""
+            code = super(QuietReport, self).error(line_number, offset, text, _)
+            if code:
+                self.__full_error_results.append(
+                    {'id': code,
+                     'line': line_number,
+                     'column': offset + 1,
+                     'info': text})
+
+        def full_error_results(self):
+            """Return error results in detail.
+
+            Results are in the form of a list of dictionaries. Each
+            dictionary contains 'id', 'line', 'column', and 'info'.
+
+            """
+            return self.__full_error_results
+
+    checker = pep8.Checker('', lines=source,
+                           reporter=QuietReport, **pep8_options)
+    checker.check_all()
+    return checker.report.full_error_results()
+
+
+def _remove_leading_and_normalize(line):
+    return line.lstrip().rstrip(CR + LF) + '\n'
+
+
+class Reindenter(object):
+
+    """Reindents badly-indented code to uniformly use four-space indentation.
+
+    Released to the public domain, by Tim Peters, 03 October 2000.
+
+    """
+
+    def __init__(self, input_text):
+        sio = io.StringIO(input_text)
+        source_lines = sio.readlines()
+
+        self.string_content_line_numbers = multiline_string_lines(input_text)
+
+        # File lines, rstripped & tab-expanded. Dummy at start is so
+        # that we can use tokenize's 1-based line numbering easily.
+        # Note that a line is all-blank iff it is a newline.
+        self.lines = []
+        line_number = 0
+        for line in source_lines:
+            line_number += 1
+            # Do not modify if inside a multiline string.
+            if line_number in self.string_content_line_numbers:
+                self.lines.append(line)
+            else:
+                # Only expand leading tabs.
+                self.lines.append(_get_indentation(line).expandtabs() +
+                                  _remove_leading_and_normalize(line))
+
+        self.lines.insert(0, None)
+        self.index = 1  # index into self.lines of next line
+        self.input_text = input_text
+
+    def run(self, indent_size=DEFAULT_INDENT_SIZE):
+        """Fix indentation and return modified line numbers.
+
+        Line numbers are indexed at 1.
+
+        """
+        if indent_size < 1:
+            return self.input_text
+
+        try:
+            stats = _reindent_stats(tokenize.generate_tokens(self.getline))
+        except (SyntaxError, tokenize.TokenError):
+            return self.input_text
+        # Remove trailing empty lines.
+        lines = self.lines
+        while lines and lines[-1] == '\n':
+            lines.pop()
+        # Sentinel.
+        stats.append((len(lines), 0))
+        # Map count of leading spaces to # we want.
+        have2want = {}
+        # Program after transformation.
+        after = []
+        # Copy over initial empty lines -- there's nothing to do until
+        # we see a line with *something* on it.
+        i = stats[0][0]
+        after.extend(lines[1:i])
+        for i in range(len(stats) - 1):
+            thisstmt, thislevel = stats[i]
+            nextstmt = stats[i + 1][0]
+            have = _leading_space_count(lines[thisstmt])
+            want = thislevel * indent_size
+            if want < 0:
+                # A comment line.
+                if have:
+                    # An indented comment line. If we saw the same
+                    # indentation before, reuse what it most recently
+                    # mapped to.
+                    want = have2want.get(have, -1)
+                    if want < 0:
+                        # Then it probably belongs to the next real stmt.
+                        for j in range(i + 1, len(stats) - 1):
+                            jline, jlevel = stats[j]
+                            if jlevel >= 0:
+                                if have == _leading_space_count(lines[jline]):
+                                    want = jlevel * indent_size
+                                break
+                    if want < 0:            # Maybe it's a hanging
+                                            # comment like this one,
+                        # in which case we should shift it like its base
+                        # line got shifted.
+                        for j in range(i - 1, -1, -1):
+                            jline, jlevel = stats[j]
+                            if jlevel >= 0:
+                                want = (have + _leading_space_count(
+                                        after[jline - 1]) -
+                                        _leading_space_count(lines[jline]))
+                                break
+                    if want < 0:
+                        # Still no luck -- leave it alone.
+                        want = have
+                else:
+                    want = 0
+            assert want >= 0
+            have2want[have] = want
+            diff = want - have
+            if diff == 0 or have == 0:
+                after.extend(lines[thisstmt:nextstmt])
+            else:
+                line_number = thisstmt - 1
+                for line in lines[thisstmt:nextstmt]:
+                    line_number += 1
+                    if line_number in self.string_content_line_numbers:
+                        after.append(line)
+                    elif diff > 0:
+                        if line == '\n':
+                            after.append(line)
+                        else:
+                            after.append(' ' * diff + line)
+                    else:
+                        remove = min(_leading_space_count(line), -diff)
+                        after.append(line[remove:])
+
+        return ''.join(after)
+
+    def getline(self):
+        """Line-getter for tokenize."""
+        if self.index >= len(self.lines):
+            line = ''
+        else:
+            line = self.lines[self.index]
+            self.index += 1
+        return line
+
+
+def _reindent_stats(tokens):
+    """Return list of (lineno, indentlevel) pairs.
+
+    One for each stmt and comment line. indentlevel is -1 for comment lines, as
+    a signal that tokenize doesn't know what to do about them; indeed, they're
+    our headache!
+
+    """
+    find_stmt = 1  # Next token begins a fresh stmt?
+    level = 0  # Current indent level.
+    stats = []
+
+    for t in tokens:
+        token_type = t[0]
+        sline = t[2][0]
+        line = t[4]
+
+        if token_type == tokenize.NEWLINE:
+            # A program statement, or ENDMARKER, will eventually follow,
+            # after some (possibly empty) run of tokens of the form
+            #     (NL | COMMENT)* (INDENT | DEDENT+)?
+            find_stmt = 1
+
+        elif token_type == tokenize.INDENT:
+            find_stmt = 1
+            level += 1
+
+        elif token_type == tokenize.DEDENT:
+            find_stmt = 1
+            level -= 1
+
+        elif token_type == tokenize.COMMENT:
+            if find_stmt:
+                stats.append((sline, -1))
+                # But we're still looking for a new stmt, so leave
+                # find_stmt alone.
+
+        elif token_type == tokenize.NL:
+            pass
+
+        elif find_stmt:
+            # This is the first "real token" following a NEWLINE, so it
+            # must be the first token of the next program statement, or an
+            # ENDMARKER.
+            find_stmt = 0
+            if line:   # Not endmarker.
+                stats.append((sline, level))
+
+    return stats
+
+
+def _leading_space_count(line):
+    """Return number of leading spaces in line."""
+    i = 0
+    while i < len(line) and line[i] == ' ':
+        i += 1
+    return i
+
+
+def refactor_with_2to3(source_text, fixer_names):
+    """Use lib2to3 to refactor the source.
+
+    Return the refactored source code.
+
+    """
+    check_lib2to3()
+    from lib2to3.refactor import RefactoringTool
+    fixers = ['lib2to3.fixes.fix_' + name for name in fixer_names]
+    tool = RefactoringTool(fixer_names=fixers, explicit=fixers)
+
+    from lib2to3.pgen2 import tokenize as lib2to3_tokenize
+    try:
+        return unicode(tool.refactor_string(source_text, name=''))
+    except lib2to3_tokenize.TokenError:
+        return source_text
+
+
+def check_syntax(code):
+    """Return True if syntax is okay."""
+    try:
+        return compile(code, '<string>', 'exec')
+    except (SyntaxError, TypeError, UnicodeDecodeError):
+        return False
+
+
+def filter_results(source, results, aggressive):
+    """Filter out spurious reports from pep8.
+
+    If aggressive is True, we allow possibly unsafe fixes (E711, E712).
+
+    """
+    non_docstring_string_line_numbers = multiline_string_lines(
+        source, include_docstrings=False)
+    all_string_line_numbers = multiline_string_lines(
+        source, include_docstrings=True)
+
+    commented_out_code_line_numbers = commented_out_code_lines(source)
+
+    for r in results:
+        issue_id = r['id'].lower()
+
+        if r['line'] in non_docstring_string_line_numbers:
+            if issue_id.startswith(('e1', 'e501', 'w191')):
+                continue
+
+        if r['line'] in all_string_line_numbers:
+            if issue_id in ['e501']:
+                continue
+
+        # We must offset by 1 for lines that contain the trailing contents of
+        # multiline strings.
+        if not aggressive and (r['line'] + 1) in all_string_line_numbers:
+            # Do not modify multiline strings in non-aggressive mode. Remove
+            # trailing whitespace could break doctests.
+            if issue_id.startswith(('w29', 'w39')):
+                continue
+
+        if aggressive <= 0:
+            if issue_id.startswith(('e711', 'w6')):
+                continue
+
+        if aggressive <= 1:
+            if issue_id.startswith(('e712', 'e713')):
+                continue
+
+        if r['line'] in commented_out_code_line_numbers:
+            if issue_id.startswith(('e26', 'e501')):
+                continue
+
+        yield r
+
+
+def multiline_string_lines(source, include_docstrings=False):
+    """Return line numbers that are within multiline strings.
+
+    The line numbers are indexed at 1.
+
+    Docstrings are ignored.
+
+    """
+    line_numbers = set()
+    previous_token_type = ''
+    try:
+        for t in generate_tokens(source):
+            token_type = t[0]
+            start_row = t[2][0]
+            end_row = t[3][0]
+
+            if token_type == tokenize.STRING and start_row != end_row:
+                if (
+                    include_docstrings or
+                    previous_token_type != tokenize.INDENT
+                ):
+                    # We increment by one since we want the contents of the
+                    # string.
+                    line_numbers |= set(range(1 + start_row, 1 + end_row))
+
+            previous_token_type = token_type
+    except (SyntaxError, tokenize.TokenError):
+        pass
+
+    return line_numbers
+
+
+def commented_out_code_lines(source):
+    """Return line numbers of comments that are likely code.
+
+    Commented-out code is bad practice, but modifying it just adds even more
+    clutter.
+
+    """
+    line_numbers = []
+    try:
+        for t in generate_tokens(source):
+            token_type = t[0]
+            token_string = t[1]
+            start_row = t[2][0]
+            line = t[4]
+
+            # Ignore inline comments.
+            if not line.lstrip().startswith('#'):
+                continue
+
+            if token_type == tokenize.COMMENT:
+                stripped_line = token_string.lstrip('#').strip()
+                if (
+                    ' ' in stripped_line and
+                    '#' not in stripped_line and
+                    check_syntax(stripped_line)
+                ):
+                    line_numbers.append(start_row)
+    except (SyntaxError, tokenize.TokenError):
+        pass
+
+    return line_numbers
+
+
+def shorten_comment(line, max_line_length, last_comment=False):
+    """Return trimmed or split long comment line.
+
+    If there are no comments immediately following it, do a text wrap.
+    Doing this wrapping on all comments in general would lead to jagged
+    comment text.
+
+    """
+    assert len(line) > max_line_length
+    line = line.rstrip()
+
+    # PEP 8 recommends 72 characters for comment text.
+    indentation = _get_indentation(line) + '# '
+    max_line_length = min(max_line_length,
+                          len(indentation) + 72)
+
+    MIN_CHARACTER_REPEAT = 5
+    if (
+        len(line) - len(line.rstrip(line[-1])) >= MIN_CHARACTER_REPEAT and
+        not line[-1].isalnum()
+    ):
+        # Trim comments that end with things like ---------
+        return line[:max_line_length] + '\n'
+    elif last_comment and re.match(r'\s*#+\s*\w+', line):
+        import textwrap
+        split_lines = textwrap.wrap(line.lstrip(' \t#'),
+                                    initial_indent=indentation,
+                                    subsequent_indent=indentation,
+                                    width=max_line_length,
+                                    break_long_words=False,
+                                    break_on_hyphens=False)
+        return '\n'.join(split_lines) + '\n'
+    else:
+        return line + '\n'
+
+
+def normalize_line_endings(lines, newline):
+    """Return fixed line endings.
+
+    All lines will be modified to use the most common line ending.
+
+    """
+    return [line.rstrip('\n\r') + newline for line in lines]
+
+
+def mutual_startswith(a, b):
+    return b.startswith(a) or a.startswith(b)
+
+
+def code_match(code, select, ignore):
+    if ignore:
+        assert not isinstance(ignore, unicode)
+        for ignored_code in [c.strip() for c in ignore]:
+            if mutual_startswith(code.lower(), ignored_code.lower()):
+                return False
+
+    if select:
+        assert not isinstance(select, unicode)
+        for selected_code in [c.strip() for c in select]:
+            if mutual_startswith(code.lower(), selected_code.lower()):
+                return True
+        return False
+
+    return True
+
+
+def fix_code(source, options=None, encoding=None):
+    """Return fixed source code."""
+    if not options:
+        options = parse_args([''])
+
+    if not isinstance(source, unicode):
+        source = source.decode(encoding or locale.getpreferredencoding())
+
+    sio = io.StringIO(source)
+    return fix_lines(sio.readlines(), options=options)
+
+
+def fix_lines(source_lines, options, filename=''):
+    """Return fixed source code."""
+    # Transform everything to line feed. Then change them back to original
+    # before returning fixed source code.
+    original_newline = find_newline(source_lines)
+    tmp_source = ''.join(normalize_line_endings(source_lines, '\n'))
+
+    # Keep a history to break out of cycles.
+    previous_hashes = set()
+
+    if options.line_range:
+        fixed_source = apply_local_fixes(tmp_source, options)
+    else:
+        # Apply global fixes only once (for efficiency).
+        fixed_source = apply_global_fixes(tmp_source, options)
+
+    passes = 0
+    long_line_ignore_cache = set()
+    while hash(fixed_source) not in previous_hashes:
+        if options.pep8_passes >= 0 and passes > options.pep8_passes:
+            break
+        passes += 1
+
+        previous_hashes.add(hash(fixed_source))
+
+        tmp_source = copy.copy(fixed_source)
+
+        fix = FixPEP8(
+            filename,
+            options,
+            contents=tmp_source,
+            long_line_ignore_cache=long_line_ignore_cache)
+
+        fixed_source = fix.fix()
+
+    sio = io.StringIO(fixed_source)
+    return ''.join(normalize_line_endings(sio.readlines(), original_newline))
+
+
+def fix_file(filename, options=None, output=None):
+    if not options:
+        options = parse_args([filename])
+
+    original_source = readlines_from_file(filename)
+
+    fixed_source = original_source
+
+    if options.in_place or output:
+        encoding = detect_encoding(filename)
+
+    if output:
+        output = codecs.getwriter(encoding)(output.buffer
+                                            if hasattr(output, 'buffer')
+                                            else output)
+
+        output = LineEndingWrapper(output)
+
+    fixed_source = fix_lines(fixed_source, options, filename=filename)
+
+    if options.diff:
+        new = io.StringIO(fixed_source)
+        new = new.readlines()
+        diff = get_diff_text(original_source, new, filename)
+        if output:
+            output.write(diff)
+            output.flush()
+        else:
+            return diff
+    elif options.in_place:
+        fp = open_with_encoding(filename, encoding=encoding,
+                                mode='w')
+        fp.write(fixed_source)
+        fp.close()
+    else:
+        if output:
+            output.write(fixed_source)
+            output.flush()
+        else:
+            return fixed_source
+
+
+def global_fixes():
+    """Yield multiple (code, function) tuples."""
+    for function in globals().values():
+        if inspect.isfunction(function):
+            arguments = inspect.getargspec(function)[0]
+            if arguments[:1] != ['source']:
+                continue
+
+            code = extract_code_from_function(function)
+            if code:
+                yield (code, function)
+
+
+def apply_global_fixes(source, options, where='global'):
+    """Run global fixes on source code.
+
+    These are fixes that only need be done once (unlike those in
+    FixPEP8, which are dependent on pep8).
+
+    """
+    if code_match('E101', select=options.select, ignore=options.ignore):
+        source = reindent(source,
+                          indent_size=options.indent_size)
+
+    for (code, function) in global_fixes():
+        if code_match(code, select=options.select, ignore=options.ignore):
+            if options.verbose:
+                print('--->  Applying {0} fix for {1}'.format(where,
+                                                              code.upper()),
+                      file=sys.stderr)
+            source = function(source,
+                              aggressive=options.aggressive)
+
+    source = fix_2to3(source,
+                      aggressive=options.aggressive,
+                      select=options.select,
+                      ignore=options.ignore)
+
+    return source
+
+
+def apply_local_fixes(source, options):
+    """Ananologus to apply_global_fixes, but runs only those which makes sense
+    for the given line_range.
+
+    Do as much as we can without breaking code.
+
+    """
+    def find_ge(a, x):
+        """Find leftmost item greater than or equal to x."""
+        i = bisect.bisect_left(a, x)
+        if i != len(a):
+            return i, a[i]
+        return len(a) - 1, a[-1]
+
+    def find_le(a, x):
+        """Find rightmost value less than or equal to x."""
+        i = bisect.bisect_right(a, x)
+        if i:
+            return i - 1, a[i - 1]
+        return 0, a[0]
+
+    def local_fix(source, start_log, end_log,
+                  start_lines, end_lines, indents, last_line):
+        """apply_global_fixes to the source between start_log and end_log.
+
+        The subsource must be the correct syntax of a complete python program
+        (but all lines may share an indentation). The subsource's shared indent
+        is removed, fixes are applied and the indent prepended back. Taking
+        care to not reindent strings.
+
+        last_line is the strict cut off (options.line_range[1]), so that
+        lines after last_line are not modified.
+
+        """
+        if end_log < start_log:
+            return source
+
+        ind = indents[start_log]
+        indent = _get_indentation(source[start_lines[start_log]])
+
+        sl = slice(start_lines[start_log], end_lines[end_log] + 1)
+
+        subsource = source[sl]
+        # Remove indent from subsource.
+        if ind:
+            for line_no in start_lines[start_log:end_log + 1]:
+                pos = line_no - start_lines[start_log]
+                subsource[pos] = subsource[pos][ind:]
+
+        # Fix indentation of subsource.
+        fixed_subsource = apply_global_fixes(''.join(subsource),
+                                             options,
+                                             where='local')
+        fixed_subsource = fixed_subsource.splitlines(True)
+
+        # Add back indent for non multi-line strings lines.
+        msl = multiline_string_lines(''.join(fixed_subsource),
+                                     include_docstrings=False)
+        for i, line in enumerate(fixed_subsource):
+            if not i + 1 in msl:
+                fixed_subsource[i] = indent + line if line != '\n' else line
+
+        # We make a special case to look at the final line, if it's a multiline
+        # *and* the cut off is somewhere inside it, we take the fixed
+        # subset up until last_line, this assumes that the number of lines
+        # does not change in this multiline line.
+        changed_lines = len(fixed_subsource)
+        if (start_lines[end_log] != end_lines[end_log]
+                and end_lines[end_log] > last_line):
+            after_end = end_lines[end_log] - last_line
+            fixed_subsource = (fixed_subsource[:-after_end] +
+                               source[sl][-after_end:])
+            changed_lines -= after_end
+
+            options.line_range[1] = (options.line_range[0] +
+                                     changed_lines - 1)
+
+        return (source[:start_lines[start_log]] +
+                fixed_subsource +
+                source[end_lines[end_log] + 1:])
+
+    def is_continued_stmt(line,
+                          continued_stmts=frozenset(['else', 'elif',
+                                                     'finally', 'except'])):
+        return re.split('[ :]', line.strip(), 1)[0] in continued_stmts
+
+    assert options.line_range
+    start, end = options.line_range
+    start -= 1
+    end -= 1
+    last_line = end  # We shouldn't modify lines after this cut-off.
+
+    try:
+        logical = _find_logical(source)
+    except (SyntaxError, tokenize.TokenError):
+        return ''.join(source)
+
+    if not logical[0]:
+        # Just blank lines, this should imply that it will become '\n' ?
+        return apply_global_fixes(source, options)
+
+    start_lines, indents = zip(*logical[0])
+    end_lines, _ = zip(*logical[1])
+
+    source = source.splitlines(True)
+
+    start_log, start = find_ge(start_lines, start)
+    end_log, end = find_le(start_lines, end)
+
+    # Look behind one line, if it's indented less than current indent
+    # then we can move to this previous line knowing that its
+    # indentation level will not be changed.
+    if (start_log > 0
+            and indents[start_log - 1] < indents[start_log]
+            and not is_continued_stmt(source[start_log - 1])):
+        start_log -= 1
+        start = start_lines[start_log]
+
+    while start < end:
+
+        if is_continued_stmt(source[start]):
+            start_log += 1
+            start = start_lines[start_log]
+            continue
+
+        ind = indents[start_log]
+        for t in itertools.takewhile(lambda t: t[1][1] >= ind,
+                                     enumerate(logical[0][start_log:])):
+            n_log, n = start_log + t[0], t[1][0]
+        # start shares indent up to n.
+
+        if n <= end:
+            source = local_fix(source, start_log, n_log,
+                               start_lines, end_lines,
+                               indents, last_line)
+            start_log = n_log if n == end else n_log + 1
+            start = start_lines[start_log]
+            continue
+
+        else:
+            # Look at the line after end and see if allows us to reindent.
+            after_end_log, after_end = find_ge(start_lines, end + 1)
+
+            if indents[after_end_log] > indents[start_log]:
+                start_log, start = find_ge(start_lines, start + 1)
+                continue
+
+            if (indents[after_end_log] == indents[start_log]
+                    and is_continued_stmt(source[after_end])):
+                # find n, the beginning of the last continued statement
+                # Apply fix to previous block if there is one.
+                only_block = True
+                for n, n_ind in logical[0][start_log:end_log + 1][::-1]:
+                    if n_ind == ind and not is_continued_stmt(source[n]):
+                        n_log = start_lines.index(n)
+                        source = local_fix(source, start_log, n_log - 1,
+                                           start_lines, end_lines,
+                                           indents, last_line)
+                        start_log = n_log + 1
+                        start = start_lines[start_log]
+                        only_block = False
+                        break
+                if only_block:
+                    end_log, end = find_le(start_lines, end - 1)
+                continue
+
+            source = local_fix(source, start_log, end_log,
+                               start_lines, end_lines,
+                               indents, last_line)
+            break
+
+    return ''.join(source)
+
+
+def extract_code_from_function(function):
+    """Return code handled by function."""
+    if not function.__name__.startswith('fix_'):
+        return None
+
+    code = re.sub('^fix_', '', function.__name__)
+    if not code:
+        return None
+
+    try:
+        int(code[1:])
+    except ValueError:
+        return None
+
+    return code
+
+
+def create_parser():
+    """Return command-line parser."""
+    # Do import locally to be friendly to those who use autopep8 as a library
+    # and are supporting Python 2.6.
+    import argparse
+
+    parser = argparse.ArgumentParser(description=docstring_summary(__doc__),
+                                     prog='autopep8')
+    parser.add_argument('--version', action='version',
+                        version='%(prog)s ' + __version__)
+    parser.add_argument('-v', '--verbose', action='count', dest='verbose',
+                        default=0,
+                        help='print verbose messages; '
+                        'multiple -v result in more verbose messages')
+    parser.add_argument('-d', '--diff', action='store_true', dest='diff',
+                        help='print the diff for the fixed source')
+    parser.add_argument('-i', '--in-place', action='store_true',
+                        help='make changes to files in place')
+    parser.add_argument('-r', '--recursive', action='store_true',
+                        help='run recursively over directories; '
+                        'must be used with --in-place or --diff')
+    parser.add_argument('-j', '--jobs', type=int, metavar='n', default=1,
+                        help='number of parallel jobs; '
+                        'match CPU count if value is less than 1')
+    parser.add_argument('-p', '--pep8-passes', metavar='n',
+                        default=-1, type=int,
+                        help='maximum number of additional pep8 passes '
+                        '(default: infinite)')
+    parser.add_argument('-a', '--aggressive', action='count', default=0,
+                        help='enable non-whitespace changes; '
+                        'multiple -a result in more aggressive changes')
+    parser.add_argument('--experimental', action='store_true',
+                        help='enable experimental fixes')
+    parser.add_argument('--exclude', metavar='globs',
+                        help='exclude file/directory names that match these '
+                        'comma-separated globs')
+    parser.add_argument('--list-fixes', action='store_true',
+                        help='list codes for fixes; '
+                        'used by --ignore and --select')
+    parser.add_argument('--ignore', metavar='errors', default='',
+                        help='do not fix these errors/warnings '
+                        '(default: {0})'.format(DEFAULT_IGNORE))
+    parser.add_argument('--select', metavar='errors', default='',
+                        help='fix only these errors/warnings (e.g. E4,W)')
+    parser.add_argument('--max-line-length', metavar='n', default=79, type=int,
+                        help='set maximum allowed line length '
+                        '(default: %(default)s)')
+    parser.add_argument('--range', metavar='line', dest='line_range',
+                        default=None, type=int, nargs=2,
+                        help='only fix errors found within this inclusive '
+                        'range of line numbers (e.g. 1 99); '
+                        'line numbers are indexed at 1')
+    parser.add_argument('--indent-size', default=DEFAULT_INDENT_SIZE,
+                        type=int, metavar='n',
+                        help='number of spaces per indent level '
+                             '(default %(default)s)')
+    parser.add_argument('files', nargs='*',
+                        help="files to format or '-' for standard in")
+
+    return parser
+
+
+def parse_args(arguments):
+    """Parse command-line options."""
+    parser = create_parser()
+    args = parser.parse_args(arguments)
+
+    if not args.files and not args.list_fixes:
+        parser.error('incorrect number of arguments')
+
+    args.files = [decode_filename(name) for name in args.files]
+
+    if '-' in args.files:
+        if len(args.files) > 1:
+            parser.error('cannot mix stdin and regular files')
+
+        if args.diff:
+            parser.error('--diff cannot be used with standard input')
+
+        if args.in_place:
+            parser.error('--in-place cannot be used with standard input')
+
+        if args.recursive:
+            parser.error('--recursive cannot be used with standard input')
+
+    if len(args.files) > 1 and not (args.in_place or args.diff):
+        parser.error('autopep8 only takes one filename as argument '
+                     'unless the "--in-place" or "--diff" args are '
+                     'used')
+
+    if args.recursive and not (args.in_place or args.diff):
+        parser.error('--recursive must be used with --in-place or --diff')
+
+    if args.exclude and not args.recursive:
+        parser.error('--exclude is only relevant when used with --recursive')
+
+    if args.in_place and args.diff:
+        parser.error('--in-place and --diff are mutually exclusive')
+
+    if args.max_line_length <= 0:
+        parser.error('--max-line-length must be greater than 0')
+
+    if args.select:
+        args.select = args.select.split(',')
+
+    if args.ignore:
+        args.ignore = args.ignore.split(',')
+    elif not args.select:
+        if args.aggressive:
+            # Enable everything by default if aggressive.
+            args.select = ['E', 'W']
+        else:
+            args.ignore = DEFAULT_IGNORE.split(',')
+
+    if args.exclude:
+        args.exclude = args.exclude.split(',')
+    else:
+        args.exclude = []
+
+    if args.jobs < 1:
+        # Do not import multiprocessing globally in case it is not supported
+        # on the platform.
+        import multiprocessing
+        args.jobs = multiprocessing.cpu_count()
+
+    if args.jobs > 1 and not args.in_place:
+        parser.error('parallel jobs requires --in-place')
+
+    if args.line_range:
+        if args.line_range[0] <= 0:
+            parser.error('--range must be positive numbers')
+        if args.line_range[0] > args.line_range[1]:
+            parser.error('First value of --range should be less than or equal '
+                         'to the second')
+
+    return args
+
+
+def decode_filename(filename):
+    """Return Unicode filename."""
+    if isinstance(filename, unicode):
+        return filename
+    else:
+        return filename.decode(sys.getfilesystemencoding())
+
+
+def supported_fixes():
+    """Yield pep8 error codes that autopep8 fixes.
+
+    Each item we yield is a tuple of the code followed by its
+    description.
+
+    """
+    yield ('E101', docstring_summary(reindent.__doc__))
+
+    instance = FixPEP8(filename=None, options=None, contents='')
+    for attribute in dir(instance):
+        code = re.match('fix_([ew][0-9][0-9][0-9])', attribute)
+        if code:
+            yield (
+                code.group(1).upper(),
+                re.sub(r'\s+', ' ',
+                       docstring_summary(getattr(instance, attribute).__doc__))
+            )
+
+    for (code, function) in sorted(global_fixes()):
+        yield (code.upper() + (4 - len(code)) * ' ',
+               re.sub(r'\s+', ' ', docstring_summary(function.__doc__)))
+
+    for code in sorted(CODE_TO_2TO3):
+        yield (code.upper() + (4 - len(code)) * ' ',
+               re.sub(r'\s+', ' ', docstring_summary(fix_2to3.__doc__)))
+
+
+def docstring_summary(docstring):
+    """Return summary of docstring."""
+    return docstring.split('\n')[0]
+
+
+def line_shortening_rank(candidate, indent_word, max_line_length,
+                         experimental=False):
+    """Return rank of candidate.
+
+    This is for sorting candidates.
+
+    """
+    if not candidate.strip():
+        return 0
+
+    rank = 0
+    lines = candidate.split('\n')
+
+    offset = 0
+    if (
+        not lines[0].lstrip().startswith('#') and
+        lines[0].rstrip()[-1] not in '([{'
+    ):
+        for (opening, closing) in ('()', '[]', '{}'):
+            # Don't penalize empty containers that aren't split up. Things like
+            # this "foo(\n    )" aren't particularly good.
+            opening_loc = lines[0].find(opening)
+            closing_loc = lines[0].find(closing)
+            if opening_loc >= 0:
+                if closing_loc < 0 or closing_loc != opening_loc + 1:
+                    offset = max(offset, 1 + opening_loc)
+
+    current_longest = max(offset + len(x.strip()) for x in lines)
+
+    rank += 4 * max(0, current_longest - max_line_length)
+
+    rank += len(lines)
+
+    # Too much variation in line length is ugly.
+    rank += 2 * standard_deviation(len(line) for line in lines)
+
+    bad_staring_symbol = {
+        '(': ')',
+        '[': ']',
+        '{': '}'}.get(lines[0][-1])
+
+    if len(lines) > 1:
+        if (
+            bad_staring_symbol and
+            lines[1].lstrip().startswith(bad_staring_symbol)
+        ):
+            rank += 20
+
+    for lineno, current_line in enumerate(lines):
+        current_line = current_line.strip()
+
+        if current_line.startswith('#'):
+            continue
+
+        for bad_start in ['.', '%', '+', '-', '/']:
+            if current_line.startswith(bad_start):
+                rank += 100
+
+            # Do not tolerate operators on their own line.
+            if current_line == bad_start:
+                rank += 1000
+
+        if current_line.endswith(('(', '[', '{', '.')):
+            # Avoid lonely opening. They result in longer lines.
+            if len(current_line) <= len(indent_word):
+                rank += 100
+
+            # Avoid the ugliness of ", (\n".
+            if (
+                current_line.endswith('(') and
+                current_line[:-1].rstrip().endswith(',')
+            ):
+                rank += 100
+
+            # Also avoid the ugliness of "foo.\nbar"
+            if current_line.endswith('.'):
+                rank += 100
+
+            if has_arithmetic_operator(current_line):
+                rank += 100
+
+        if current_line.endswith(('%', '(', '[', '{')):
+            rank -= 20
+
+        # Try to break list comprehensions at the "for".
+        if current_line.startswith('for '):
+            rank -= 50
+
+        if current_line.endswith('\\'):
+            # If a line ends in \-newline, it may be part of a
+            # multiline string. In that case, we would like to know
+            # how long that line is without the \-newline. If it's
+            # longer than the maximum, or has comments, then we assume
+            # that the \-newline is an okay candidate and only
+            # penalize it a bit.
+            total_len = len(current_line)
+            lineno += 1
+            while lineno < len(lines):
+                total_len += len(lines[lineno])
+
+                if lines[lineno].lstrip().startswith('#'):
+                    total_len = max_line_length
+                    break
+
+                if not lines[lineno].endswith('\\'):
+                    break
+
+                lineno += 1
+
+            if total_len < max_line_length:
+                rank += 10
+            else:
+                rank += 100 if experimental else 1
+
+        # Prefer breaking at commas rather than colon.
+        if ',' in current_line and current_line.endswith(':'):
+            rank += 10
+
+        rank += 10 * count_unbalanced_brackets(current_line)
+
+    return max(0, rank)
+
+
+def standard_deviation(numbers):
+    """Return standard devation."""
+    numbers = list(numbers)
+    if not numbers:
+        return 0
+    mean = sum(numbers) / len(numbers)
+    return (sum((n - mean) ** 2 for n in numbers) /
+            len(numbers)) ** .5
+
+
+def has_arithmetic_operator(line):
+    """Return True if line contains any arithmetic operators."""
+    for operator in pep8.ARITHMETIC_OP:
+        if operator in line:
+            return True
+
+    return False
+
+
+def count_unbalanced_brackets(line):
+    """Return number of unmatched open/close brackets."""
+    count = 0
+    for opening, closing in ['()', '[]', '{}']:
+        count += abs(line.count(opening) - line.count(closing))
+
+    return count
+
+
+def split_at_offsets(line, offsets):
+    """Split line at offsets.
+
+    Return list of strings.
+
+    """
+    result = []
+
+    previous_offset = 0
+    current_offset = 0
+    for current_offset in sorted(offsets):
+        if current_offset < len(line) and previous_offset != current_offset:
+            result.append(line[previous_offset:current_offset].strip())
+        previous_offset = current_offset
+
+    result.append(line[current_offset:])
+
+    return result
+
+
+class LineEndingWrapper(object):
+
+    r"""Replace line endings to work with sys.stdout.
+
+    It seems that sys.stdout expects only '\n' as the line ending, no matter
+    the platform. Otherwise, we get repeated line endings.
+
+    """
+
+    def __init__(self, output):
+        self.__output = output
+
+    def write(self, s):
+        self.__output.write(s.replace('\r\n', '\n').replace('\r', '\n'))
+
+    def flush(self):
+        self.__output.flush()
+
+
+def match_file(filename, exclude):
+    """Return True if file is okay for modifying/recursing."""
+    base_name = os.path.basename(filename)
+
+    if base_name.startswith('.'):
+        return False
+
+    for pattern in exclude:
+        if fnmatch.fnmatch(base_name, pattern):
+            return False
+
+    if not os.path.isdir(filename) and not is_python_file(filename):
+        return False
+
+    return True
+
+
+def find_files(filenames, recursive, exclude):
+    """Yield filenames."""
+    while filenames:
+        name = filenames.pop(0)
+        if recursive and os.path.isdir(name):
+            for root, directories, children in os.walk(name):
+                filenames += [os.path.join(root, f) for f in children
+                              if match_file(os.path.join(root, f),
+                                            exclude)]
+                directories[:] = [d for d in directories
+                                  if match_file(os.path.join(root, d),
+                                                exclude)]
+        else:
+            yield name
+
+
+def _fix_file(parameters):
+    """Helper function for optionally running fix_file() in parallel."""
+    if parameters[1].verbose:
+        print('[file:{0}]'.format(parameters[0]), file=sys.stderr)
+    try:
+        fix_file(*parameters)
+    except IOError as error:
+        print(unicode(error), file=sys.stderr)
+
+
+def fix_multiple_files(filenames, options, output=None):
+    """Fix list of files.
+
+    Optionally fix files recursively.
+
+    """
+    filenames = find_files(filenames, options.recursive, options.exclude)
+    if options.jobs > 1:
+        import multiprocessing
+        pool = multiprocessing.Pool(options.jobs)
+        pool.map(_fix_file,
+                 [(name, options) for name in filenames])
+    else:
+        for name in filenames:
+            _fix_file((name, options, output))
+
+
+def is_python_file(filename):
+    """Return True if filename is Python file."""
+    if filename.endswith('.py'):
+        return True
+
+    try:
+        with open_with_encoding(filename) as f:
+            first_line = f.readlines(1)[0]
+    except (IOError, IndexError):
+        return False
+
+    if not PYTHON_SHEBANG_REGEX.match(first_line):
+        return False
+
+    return True
+
+
+def is_probably_part_of_multiline(line):
+    """Return True if line is likely part of a multiline string.
+
+    When multiline strings are involved, pep8 reports the error as being
+    at the start of the multiline string, which doesn't work for us.
+
+    """
+    return (
+        '"""' in line or
+        "'''" in line or
+        line.rstrip().endswith('\\')
+    )
+
+
+def main():
+    """Tool main."""
+    try:
+        # Exit on broken pipe.
+        signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+    except AttributeError:  # pragma: no cover
+        # SIGPIPE is not available on Windows.
+        pass
+
+    try:
+        args = parse_args(sys.argv[1:])
+
+        if args.list_fixes:
+            for code, description in sorted(supported_fixes()):
+                print('{code} - {description}'.format(
+                    code=code, description=description))
+            return 0
+
+        if args.files == ['-']:
+            assert not args.in_place
+
+            # LineEndingWrapper is unnecessary here due to the symmetry between
+            # standard in and standard out.
+
+            sys.stdout.write(
+                fix_code(
+                    sys.stdin.read(),
+                    args,
+                    encoding=sys.stdin.encoding))
+        else:
+            if args.in_place or args.diff:
+                args.files = list(set(args.files))
+            else:
+                assert len(args.files) == 1
+                assert not args.recursive
+
+            fix_multiple_files(args.files, args, sys.stdout)
+    except KeyboardInterrupt:
+        return 1  # pragma: no cover
+
+
+class CachedTokenizer(object):
+
+    """A one-element cache around tokenize.generate_tokens().
+
+    Original code written by Ned Batchelder, in coverage.py.
+
+    """
+
+    def __init__(self):
+        self.last_text = None
+        self.last_tokens = None
+
+    def generate_tokens(self, text):
+        """A stand-in for tokenize.generate_tokens()."""
+        if text != self.last_text:
+            string_io = io.StringIO(text)
+            self.last_tokens = list(
+                tokenize.generate_tokens(string_io.readline)
+            )
+            self.last_text = text
+        return self.last_tokens
+
+_cached_tokenizer = CachedTokenizer()
+generate_tokens = _cached_tokenizer.generate_tokens
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilder.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilder.java
index 3f9c1c1..0bdd98b 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilder.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilder.java
@@ -45,7 +45,7 @@ import org.python.pydev.utils.PyFileListing;
 
 /**
  * This builder only passes through python files
- * 
+ *
  * @author Fabio Zadrozny
  */
 public class PyDevBuilder extends IncrementalProjectBuilder {
@@ -53,7 +53,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
     private static final boolean DEBUG = false;
 
     /**
-     * 
+     *
      * @return a list of visitors for building the application.
      */
     public List<PyDevBuilderVisitor> getVisitors() {
@@ -82,7 +82,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
 
     /**
      * Builds the project.
-     * 
+     *
      * @see org.eclipse.core.internal.events InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
      */
     @Override
@@ -131,6 +131,11 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
                     } catch (Exception e) {
                         Log.log(e);
                     }
+                    try {
+                        grouperVisitor.finishDelayedVisits();
+                    } catch (Exception e) {
+                        Log.log(e);
+                    }
                 } catch (Exception e1) {
                     Log.log(e1);
                 }
@@ -141,7 +146,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
 
     /**
      * Processes all python files.
-     * 
+     *
      * @param monitor
      */
     private void performFullBuild(IProgressMonitor monitor) throws CoreException {
@@ -245,7 +250,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
      * @param nature the nature associated to the resource
      */
     private void addToResourcesToParse(List<IFile> resourcesToParse, IFile member, IPythonNature nature) {
-        //analyze it only if it is a valid source file 
+        //analyze it only if it is a valid source file
         String fileExtension = member.getFileExtension();
         if (DEBUG) {
             System.out.println("Checking name:'" + member.getName() + "' projPath:'" + member.getProjectRelativePath()
@@ -263,7 +268,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
 
     /**
      * Default implementation. Visits each resource once at a time. May be overridden if a better implementation is needed.
-     * 
+     *
      * @param resourcesToParse list of resources from project that are python files.
      * @param monitor
      * @param visitors
@@ -357,7 +362,7 @@ public class PyDevBuilder extends IncrementalProjectBuilder {
 
     /**
      * Used so that we can communicate the progress to the user
-     * 
+     *
      * @param bufferToCreateString: this is a buffer that's emptied and used to create the string to be shown to the
      * user with the progress.
      */
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderPrefPage.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderPrefPage.java
index 68a4a1c..cf645b4 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderPrefPage.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderPrefPage.java
@@ -23,8 +23,8 @@ import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.python.pydev.parser.PyParserManager;
 import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.plugin.preferences.PydevPrefs;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
-import org.python.pydev.utils.ComboFieldEditor;
 
 /**
  * @author Fabio Zadrozny
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderVisitor.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderVisitor.java
index 167fabf..2653930 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderVisitor.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevBuilderVisitor.java
@@ -36,9 +36,9 @@ import org.python.pydev.shared_core.callbacks.ICallback0;
 
 /**
  * Visitors within pydev should be subclasses of this class.
- * 
+ *
  * They should be prepared for being reused to, as they are instantiated and reused for visiting many resources.
- * 
+ *
  * @author Fabio Zadrozny
  */
 public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisitor> {
@@ -58,8 +58,8 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     /*default*/static final String MODULE_IN_PROJECT_PYTHONPATH = "MODULE_IN_PROJECT_PYTHONPATH"; //$NON-NLS-1$
 
     /**
-     * The default priority is 5. 
-     * 
+     * The default priority is 5.
+     *
      * Higher priorities are minor numbers (and vice-versa).
      */
     public static final int PRIORITY_DEFAULT = 5;
@@ -91,7 +91,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     }
 
     /**
-     * @return the priority of this visitor (visitors with higher priority -- 
+     * @return the priority of this visitor (visitors with higher priority --
      * lower numbers -- are visited before)
      */
     protected int getPriority() {
@@ -99,13 +99,13 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     }
 
     /**
-     * This field acts like a memory. 
-     * 
-     * It is set before a given resource is visited, and is maintained 
-     * for each visitor while the same resource is being visited. 
-     * 
+     * This field acts like a memory.
+     *
+     * It is set before a given resource is visited, and is maintained
+     * for each visitor while the same resource is being visited.
+     *
      * In this way, we can keep from having to recreate some info (such as the ast) each time over and over
-     * for each visitor. 
+     * for each visitor.
      */
     public VisitorMemo memo;
 
@@ -116,7 +116,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
 
     /**
      * Constant indicating value in memory to represent the creation time of the document in memory that the visitor
-     * is getting. 
+     * is getting.
      */
     public static final String DOCUMENT_TIME = "DOCUMENT_TIME"; //$NON-NLS-1$
 
@@ -145,13 +145,13 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
 
     /**
      * This method returns the module that is created from the given resource.
-     * 
+     *
      * It also uses the cache, to see if the module is already available for that.
-     * 
+     *
      * @param resource the resource we are analyzing
      * @param document the document with the resource contents
      * @return the module that is created by the given resource
-     * @throws MisconfigurationException 
+     * @throws MisconfigurationException
      */
     protected SourceModule getSourceModule(IResource resource, IDocument document, IPythonNature nature)
             throws MisconfigurationException {
@@ -174,7 +174,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
      * @param resource
      * @param document
      * @return
-     * @throws MisconfigurationException 
+     * @throws MisconfigurationException
      */
     protected SourceModule createSoureModule(IResource resource, IDocument document, String moduleName)
             throws MisconfigurationException {
@@ -198,7 +198,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     /**
      * @param resource must be the resource we are analyzing because it will go to the cache without the resource (only as MODULE_NAME_CACHE)
      * @return the name of the module we are analyzing (given tho resource)
-     * @throws MisconfigurationException 
+     * @throws MisconfigurationException
      */
     public String getModuleName(IResource resource, IPythonNature nature) throws MisconfigurationException {
         String moduleName = (String) memo.get(getModuleNameCacheKey(resource));
@@ -281,7 +281,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     }
 
     /**
-     * 
+     *
      * @return the maximun number of resources that it is allowed to visit (if this
      * number is higher than the number of resources changed, this visitor is not called).
      */
@@ -291,7 +291,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
 
     /**
      * Called when a resource is changed
-     * 
+     *
      * @param resource to be visited.
      */
     public abstract void visitChangedResource(IResource resource, ICallback0<IDocument> document,
@@ -300,7 +300,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
     /**
      * Called when a resource is added. Default implementation calls the same method
      * used for change.
-     * 
+     *
      * @param resource to be visited.
      */
     public void visitAddedResource(IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) {
@@ -309,7 +309,7 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
 
     /**
      * Called when a resource is removed
-     * 
+     *
      * @param resource to be visited.
      */
     public abstract void visitRemovedResource(IResource resource, ICallback0<IDocument> document,
@@ -319,17 +319,17 @@ public abstract class PyDevBuilderVisitor implements Comparable<PyDevBuilderVisi
      * This function is called right before a visiting session starts for a delta (end will
      * only be called when the whole delta is processed).
      * @param monitor this is the monitor that will be used in the visit
-     * @param nature 
+     * @param nature
      */
     public void visitingWillStart(IProgressMonitor monitor, boolean isFullBuild, IPythonNature nature) {
 
     }
 
     /**
-     * This function is called when we finish visiting some delta (which may be the whole project or 
+     * This function is called when we finish visiting some delta (which may be the whole project or
      * just some files).
-     * 
-     * A use-case is: It may be overriden if we need to store info in a persisting location
+     *
+     * A use-case is: It may be overridden if we need to store info in a persisting location
      * @param monitor this is the monitor used in the visit
      */
     public void visitingEnded(IProgressMonitor monitor) {
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevDeltaCounter.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevDeltaCounter.java
index 76720a7..2c713f2 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevDeltaCounter.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PyDevDeltaCounter.java
@@ -21,12 +21,12 @@ import org.python.pydev.shared_core.callbacks.ICallback0;
 /**
  * @author Fabio Zadrozny
  */
-public class PyDevDeltaCounter extends PydevInternalResourceDeltaVisitor {
+public final class PyDevDeltaCounter extends PydevInternalResourceDeltaVisitor {
 
     private int nVisited = 0;
 
     public PyDevDeltaCounter() {
-        super(null, 0);
+        super(null);
     }
 
     @Override
@@ -38,21 +38,18 @@ public class PyDevDeltaCounter extends PydevInternalResourceDeltaVisitor {
      * Overridden so that we don't load the document on this visitor (there is no need for that).
      */
     @Override
-    protected boolean chooseVisit(IResourceDelta delta, IResource resource, boolean isAddOrChange) {
+    protected void onVisitDelta(IResourceDelta delta) {
         switch (delta.getKind()) {
             case IResourceDelta.ADDED:
-                visitAddedResource(resource, null, monitor);
-                isAddOrChange = true;
+                visitAddedResource(null, null, monitor);
                 break;
             case IResourceDelta.CHANGED:
-                visitChangedResource(resource, null, monitor);
-                isAddOrChange = true;
+                visitChangedResource(null, null, monitor);
                 break;
             case IResourceDelta.REMOVED:
-                visitRemovedResource(resource, null, monitor);
+                visitRemovedResource(null, null, monitor);
                 break;
         }
-        return isAddOrChange;
     }
 
     /**
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PydevGrouperVisitor.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PydevGrouperVisitor.java
index 0ab2d51..15a94fd 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PydevGrouperVisitor.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PydevGrouperVisitor.java
@@ -13,8 +13,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.text.IDocument;
+import org.python.pydev.core.FileUtilsFileBuffer;
 import org.python.pydev.core.IPythonNature;
 import org.python.pydev.core.log.Log;
 import org.python.pydev.plugin.nature.PythonNature;
@@ -23,15 +25,35 @@ import org.python.pydev.shared_core.string.FastStringBuffer;
 
 /**
  * Groups the visitors to be added and visits them according to their priority
- * 
+ *
  * @author fabioz
  */
 public class PydevGrouperVisitor extends PydevInternalResourceDeltaVisitor {
 
-    private List<PyDevBuilderVisitor> visitors;
+    private final List<PyDevBuilderVisitor> visitors;
+
+    //variables used to communicate the progress
+    /**
+     * number of total resources to be visited (only used when the monitor is set)
+     * (set externally)
+     */
+    private final int totalResources;
+    /**
+     * number of resources visited to the moment
+     * (updated in this class)
+     */
+    private int currentResourcesVisited = 0;
+
+    //end variables used to communicate the progress
+
+    private final List<IResourceDelta> delayedVisits;
 
     public PydevGrouperVisitor(List<PyDevBuilderVisitor> _visitors, IProgressMonitor monitor, int totalResources) {
-        super(monitor, totalResources);
+        super(monitor);
+        this.monitor = monitor;
+        this.totalResources = totalResources;
+        this.delayedVisits = new ArrayList<>();
+
         //make a copy - should be already sorted at this point
         this.visitors = new ArrayList<PyDevBuilderVisitor>(_visitors);
     }
@@ -44,7 +66,7 @@ public class PydevGrouperVisitor extends PydevInternalResourceDeltaVisitor {
      * @param name determines the name of the method to visit (added removed or changed)
      * @param resource the resource to visit
      * @param document the document from the resource
-     * @param monitor 
+     * @param monitor
      */
     private void visitWith(int visitType, final IResource resource, ICallback0<IDocument> document,
             IProgressMonitor monitor) {
@@ -111,6 +133,28 @@ public class PydevGrouperVisitor extends PydevInternalResourceDeltaVisitor {
 
     }
 
+    /**
+     * This will use the internal builders to traverse the delta. Note that the resource is always a valid
+     * python file and is also always located in the pythonpath.
+     */
+    @Override
+    protected void onVisitDelta(IResourceDelta delta) {
+        //Note: removals happen now, additions and changes happen later (so that renames are
+        //properly treated).
+
+        switch (delta.getKind()) {
+            case IResourceDelta.ADDED:
+            case IResourceDelta.CHANGED:
+                delayedVisits.add(delta);
+                break;
+            case IResourceDelta.REMOVED:
+                IResource resource = delta.getResource();
+                memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
+                visitRemovedResource(resource, null, monitor);
+                break;
+        }
+    }
+
     @Override
     public void visitAddedResource(IResource resource, ICallback0<IDocument> document, IProgressMonitor monitor) {
         visitWith(VISIT_ADD, resource, document, monitor);
@@ -126,4 +170,41 @@ public class PydevGrouperVisitor extends PydevInternalResourceDeltaVisitor {
         visitWith(VISIT_REMOVE, resource, document, monitor);
     }
 
+    public void finishDelayedVisits() {
+        for (IResourceDelta delta : delayedVisits) {
+            try {
+                IResource resource = delta.getResource();
+
+                boolean isAddRemove = false;
+                switch (delta.getKind()) {
+                    case IResourceDelta.ADDED:
+                        memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
+                        visitAddedResource(resource, FileUtilsFileBuffer.getDocOnCallbackFromResource(resource),
+                                monitor);
+                        isAddRemove = true;
+                        break;
+
+                    case IResourceDelta.CHANGED:
+                        memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
+                        visitChangedResource(resource, FileUtilsFileBuffer.getDocOnCallbackFromResource(resource),
+                                monitor);
+                        isAddRemove = true;
+                        break;
+                }
+
+                if (isAddRemove) {
+                    //communicate the progress
+                    currentResourcesVisited++;
+                    FastStringBuffer bufferToCreateString = new FastStringBuffer();
+                    PyDevBuilder.communicateProgress(monitor, totalResources, currentResourcesVisited,
+                            resource,
+                            this, bufferToCreateString);
+                }
+            } catch (Exception e) {
+                Log.log(e);
+            }
+        }
+
+    }
+
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/builder/PydevInternalResourceDeltaVisitor.java b/plugins/org.python.pydev/src/org/python/pydev/builder/PydevInternalResourceDeltaVisitor.java
index 58aafd9..c251cbe 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/builder/PydevInternalResourceDeltaVisitor.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/builder/PydevInternalResourceDeltaVisitor.java
@@ -16,47 +16,29 @@ import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.resources.IResourceDeltaVisitor;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.text.IDocument;
 import org.python.pydev.builder.pycremover.PycHandlerBuilderVisitor;
-import org.python.pydev.core.FileUtilsFileBuffer;
 import org.python.pydev.core.log.Log;
 import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
 import org.python.pydev.plugin.nature.PythonNature;
-import org.python.pydev.shared_core.callbacks.ICallback0;
-import org.python.pydev.shared_core.string.FastStringBuffer;
 
 public abstract class PydevInternalResourceDeltaVisitor extends PyDevBuilderVisitor implements IResourceDeltaVisitor {
 
-    PydevInternalResourceDeltaVisitor(IProgressMonitor monitor, int totalResources) {
-        this.monitor = monitor;
-        this.totalResources = totalResources;
-    }
-
-    //variables used to communicate the progress
     /**
-     * this monitor might be set externally so that we can comunicate the progress to the user
+     * this monitor might be set externally so that we can communicate the progress to the user
      * (set externally)
      */
     public IProgressMonitor monitor;
-    /**
-     * number of total resources to be visited (only used when the monitor is set)
-     * (set externally)
-     */
-    public int totalResources;
-    /**
-     * number of resources visited to the moment 
-     * (updated in this class)
-     */
-    public int currentResourcesVisited = 0;
 
-    //end variables used to communicate the progress
+    protected PydevInternalResourceDeltaVisitor(IProgressMonitor monitor) {
+        this.monitor = monitor;
+    }
 
     /**
      * Visits the resource delta tree determining which files to rebuild (*.py).
-     * 
-     * Subclasses should only reimplement visitChanged, visitAdded and visitRemoved. This method will not be called 
+     *
+     * Subclasses should only reimplement visitChanged, visitAdded and visitRemoved. This method will not be called
      * in the structure provided by pydev.
-     * 
+     *
      * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
      */
     public boolean visit(IResourceDelta delta) throws CoreException {
@@ -64,7 +46,7 @@ public abstract class PydevInternalResourceDeltaVisitor extends PyDevBuilderVisi
             return true;
         }
 
-        IResource resource = delta.getResource();
+        final IResource resource = delta.getResource();
 
         if (resource == null) {
             return true;
@@ -108,19 +90,8 @@ public abstract class PydevInternalResourceDeltaVisitor extends PyDevBuilderVisi
             if (project != null && nature != null) {
                 //we just want to make the visit if it is a valid python file and it is in the pythonpath
                 if (PythonPathHelper.isValidSourceFile("." + ext)) {
+                    onVisitDelta(delta);
 
-                    boolean isAddOrChange = false;
-
-                    //document time is updated here
-                    isAddOrChange = chooseVisit(delta, resource, isAddOrChange);
-
-                    if (isAddOrChange) {
-                        //communicate the progress
-                        currentResourcesVisited++;
-                        FastStringBuffer bufferToCreateString = new FastStringBuffer();
-                        PyDevBuilder.communicateProgress(monitor, totalResources, currentResourcesVisited, resource,
-                                this, bufferToCreateString);
-                    }
                 } else if (ext.equals("pyc")) {
                     if (delta.getKind() == IResourceDelta.ADDED) {
                         handleAddedPycFiles(resource, nature);
@@ -151,30 +122,6 @@ public abstract class PydevInternalResourceDeltaVisitor extends PyDevBuilderVisi
         }
     }
 
-    /**
-     * This will use the internal builders to traverse the delta. Note that the resource is always a valid
-     * python file and is also always located in the pythonpath.
-     */
-    protected boolean chooseVisit(IResourceDelta delta, IResource resource, boolean isAddOrChange) {
-        switch (delta.getKind()) {
-            case IResourceDelta.ADDED:
-                ICallback0<IDocument> doc = FileUtilsFileBuffer.getDocOnCallbackFromResource(resource);
-                memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
-                visitAddedResource(resource, doc, monitor);
-                isAddOrChange = true;
-                break;
-            case IResourceDelta.CHANGED:
-                doc = FileUtilsFileBuffer.getDocOnCallbackFromResource(resource);
-                memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
-                visitChangedResource(resource, doc, monitor);
-                isAddOrChange = true;
-                break;
-            case IResourceDelta.REMOVED:
-                memo.put(PyDevBuilderVisitor.DOCUMENT_TIME, System.currentTimeMillis());
-                visitRemovedResource(resource, null, monitor);
-                break;
-        }
-        return isAddOrChange;
-    }
+    protected abstract void onVisitDelta(IResourceDelta delta);
 
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/compare/PyMergeViewer.java b/plugins/org.python.pydev/src/org/python/pydev/compare/PyMergeViewer.java
index d21acfb..0e1147a 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/compare/PyMergeViewer.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/compare/PyMergeViewer.java
@@ -17,7 +17,9 @@ import org.eclipse.compare.ITypedElement;
 import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
 import org.eclipse.compare.structuremergeviewer.ICompareInput;
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.IDocumentPartitioner;
@@ -178,11 +180,25 @@ public class PyMergeViewer extends TextMergeViewer {
     @SuppressWarnings("unchecked")
     @Override
     protected void configureTextViewer(TextViewer textViewer) {
-        if (!(textViewer instanceof SourceViewer))
+        if (!(textViewer instanceof SourceViewer)) {
             return;
+        }
         final SourceViewer sourceViewer = (SourceViewer) textViewer;
 
-        final IIndentPrefs indentPrefs = new DefaultIndentPrefs();
+        IAdaptable adaptable;
+        if (sourceViewer instanceof IAdaptable) {
+            adaptable = (IAdaptable) sourceViewer;
+        } else {
+            adaptable = new IAdaptable() {
+
+                @Override
+                public Object getAdapter(Class adapter) {
+                    return null;
+                }
+            };
+        }
+
+        final IIndentPrefs indentPrefs = new DefaultIndentPrefs(adaptable);
 
         //Hack to provide the source viewer configuration that'll only be created later (there's a cycle there).
         final WeakReference<PyEditConfigurationWithoutEditor>[] sourceViewerConfigurationObj = new WeakReference[1];
@@ -202,8 +218,9 @@ public class PyMergeViewer extends TextMergeViewer {
                 String[] types = configuration.getConfiguredContentTypes(sourceViewer);
                 for (int i = 0; i < types.length; i++) {
                     String[] prefixes = configuration.getIndentPrefixes(sourceViewer, types[i]);
-                    if (prefixes != null && prefixes.length > 0)
+                    if (prefixes != null && prefixes.length > 0) {
                         sourceViewer.setIndentPrefixes(prefixes, types[i]);
+                    }
                 }
             }
 
@@ -255,11 +272,18 @@ public class PyMergeViewer extends TextMergeViewer {
                         return resource;
                     }
                 }
+                if (adapter == IProject.class) {
+                    IResource resource = PyMergeViewer.this.getResource(PyMergeViewer.this.getInput());
+                    if (resource instanceof IFile) {
+                        return resource.getProject();
+                    }
+                }
                 return null;
             }
         };
 
         final PyEditConfiguration sourceViewerConfiguration = new PyEditConfiguration(c, editor, chainedPrefStore);
+        sourceViewerConfiguration.getPyAutoIndentStrategy(editor); // Force its initialization
         sourceViewerConfigurationObj[0] = new WeakReference<PyEditConfigurationWithoutEditor>(sourceViewerConfiguration);
         sourceViewer.configure(sourceViewerConfiguration);
 
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/PyEdit.java b/plugins/org.python.pydev/src/org/python/pydev/editor/PyEdit.java
index 917ab15..acbdfac 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/PyEdit.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/PyEdit.java
@@ -86,6 +86,7 @@ import org.python.pydev.core.IIndentPrefs;
 import org.python.pydev.core.IModulesManager;
 import org.python.pydev.core.IPyEdit;
 import org.python.pydev.core.IPythonNature;
+import org.python.pydev.core.ITabChangedListener;
 import org.python.pydev.core.MisconfigurationException;
 import org.python.pydev.core.NotConfiguredInterpreterException;
 import org.python.pydev.core.docutils.PyPartitionScanner;
@@ -104,7 +105,6 @@ import org.python.pydev.editor.actions.PyMoveLineUpAction;
 import org.python.pydev.editor.actions.PyOpenAction;
 import org.python.pydev.editor.actions.PyOrganizeImports;
 import org.python.pydev.editor.actions.PyPeerLinker;
-import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
 import org.python.pydev.editor.autoedit.PyAutoIndentStrategy;
 import org.python.pydev.editor.codecompletion.revisited.CompletionCache;
 import org.python.pydev.editor.codecompletion.revisited.CompletionStateFactory;
@@ -141,6 +141,7 @@ import org.python.pydev.plugin.preferences.CheckDefaultPreferencesDialog;
 import org.python.pydev.plugin.preferences.PyCodeFormatterPage;
 import org.python.pydev.plugin.preferences.PydevPrefs;
 import org.python.pydev.shared_core.callbacks.CallbackWithListeners;
+import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.callbacks.ICallbackWithListeners;
 import org.python.pydev.shared_core.model.ErrorDescription;
 import org.python.pydev.shared_core.model.ISimpleNode;
@@ -189,7 +190,7 @@ import org.python.pydev.ui.filetypes.FileTypesPreferencesPage;
  *
  */
 public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersionProvider,
-        IPySyntaxHighlightingAndCodeCompletionEditor, IParserObserver3 {
+        IPySyntaxHighlightingAndCodeCompletionEditor, IParserObserver3, ITabChangedListener {
 
     static {
         ParseException.verboseExceptions = true;
@@ -333,7 +334,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
 
             editConfiguration = new PyEditConfiguration(colorCache, this, PydevPrefs.getChainedPrefStore());
             setSourceViewerConfiguration(editConfiguration);
-            indentStrategy = editConfiguration.getPyAutoIndentStrategy();
+            indentStrategy = editConfiguration.getPyAutoIndentStrategy(this);
             setRangeIndicator(new DefaultRangeIndicator()); // enables standard
             // vertical ruler
 
@@ -394,8 +395,9 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
             return;
         }
 
-        if (!PydevPrefs.getPreferences().getBoolean(PydevEditorPrefs.GUESS_TAB_SUBSTITUTION)) {
-            getIndentPrefs().setForceTabs(false);
+        IIndentPrefs indentPrefs = getIndentPrefs();
+        if (!indentPrefs.getGuessTabSubstitution()) {
+            indentPrefs.setForceTabs(false);
             return;
         }
 
@@ -422,7 +424,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
             }
             i++;
         }
-        getIndentPrefs().setForceTabs(forceTabs);
+        indentPrefs.setForceTabs(forceTabs);
         editConfiguration.resetIndentPrefixes();
         // display a message in the status line
         if (forceTabs) {
@@ -464,7 +466,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
     }
 
     /**
-     * Overriden becaus pydev already handles spaces -> tabs
+     * Overriden because pydev already handles spaces -> tabs
      */
     @Override
     protected void installTabsToSpacesConverter() {
@@ -522,6 +524,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
 
             // listen to changes in TAB_WIDTH preference
             prefListener = createPrefChangeListener(this);
+            this.getIndentPrefs().addTabChangedListener(this);
             resetForceTabs();
             PydevPrefs.getChainedPrefStore().addPropertyChangeListener(prefListener);
 
@@ -547,6 +550,23 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
         }
     }
 
+    @Override
+    public void onTabSettingsChanged(IIndentPrefs prefs) {
+        onTabSettingsChanged(this);
+    }
+
+    private static void onTabSettingsChanged(final IPySyntaxHighlightingAndCodeCompletionEditor editor) {
+        ISourceViewer sourceViewer = editor.getEditorSourceViewer();
+        if (sourceViewer == null) {
+            return;
+        }
+        IIndentPrefs indentPrefs = editor.getIndentPrefs();
+        indentPrefs.regenerateIndentString();
+        sourceViewer.getTextWidget().setTabs(indentPrefs.getTabWidth());
+        editor.resetForceTabs();
+        editor.resetIndentPrefixes();
+    }
+
     public static IPropertyChangeListener createPrefChangeListener(
             final IPySyntaxHighlightingAndCodeCompletionEditor editor) {
         return new IPropertyChangeListener() {
@@ -556,22 +576,14 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
                     String property = event.getProperty();
                     //tab width
                     if (property.equals(PydevEditorPrefs.TAB_WIDTH)) {
-                        ISourceViewer sourceViewer = editor.getEditorSourceViewer();
-                        if (sourceViewer == null) {
-                            return;
-                        }
-                        editor.getIndentPrefs().regenerateIndentString();
-                        sourceViewer.getTextWidget().setTabs(DefaultIndentPrefs.getStaticTabWidth());
-                        editor.resetIndentPrefixes();
+                        onTabSettingsChanged(editor);
 
                     } else if (property.equals(PydevEditorPrefs.SUBSTITUTE_TABS)) {
-                        editor.getIndentPrefs().regenerateIndentString();
-                        editor.resetIndentPrefixes();
+                        onTabSettingsChanged(editor);
 
                         //auto adjust for file tabs
                     } else if (property.equals(PydevEditorPrefs.GUESS_TAB_SUBSTITUTION)) {
-                        editor.resetForceTabs();
-                        editor.resetIndentPrefixes();
+                        onTabSettingsChanged(editor);
 
                         //colors and styles
                     } else if (ColorAndStyleCache.isColorOrStyleProperty(property)) {
@@ -725,22 +737,39 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
     protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
         final IDocument document = getDocument();
 
-        //Before saving, let's see if the auto-code formatting is turned on.
+        boolean keepOn;
         try {
-            boolean keepOn = true;
-            if (PyCodeFormatterPage.getAutoformatOnlyWorkspaceFiles()) {
+            keepOn = true;
+            if (PydevSaveActionsPrefPage.getAutoformatOnlyWorkspaceFiles(this)) {
                 if (getIFile() == null) { //not a workspace file and user has chosen to only auto-format workspace files.
                     keepOn = false;
                 }
             }
+        } catch (Exception e1) {
+            Log.log(e1);
+            // Shouldn't happen: let's skip the save actions...
+            keepOn = false;
+        }
+
+        // Save actions before code-formatting (so that we apply the formatting to it afterwards).
+        try {
+            if (keepOn) {
+                executeSaveActions(document);
+            }
+        } catch (final Throwable e) {
+            Log.log(e);
+        }
+
+        //Before saving, let's see if the auto-code formatting is turned on.
+        try {
 
             //TODO CYTHON: support code-formatter.
-            if (keepOn && PydevSaveActionsPrefPage.getFormatBeforeSaving() && !isCythonFile()) {
+            if (keepOn && PydevSaveActionsPrefPage.getFormatBeforeSaving(this) && !isCythonFile()) {
                 IStatusLineManager statusLineManager = this.getStatusLineManager();
                 IDocumentProvider documentProvider = getDocumentProvider();
                 int[] regionsForSave = null;
 
-                if (PyCodeFormatterPage.getFormatOnlyChangedLines()) {
+                if (PyCodeFormatterPage.getFormatOnlyChangedLines(this)) {
                     if (documentProvider instanceof PyDocumentProvider) {
                         PyDocumentProvider pyDocumentProvider = (PyDocumentProvider) documentProvider;
                         ITextFileBuffer fileBuffer = pyDocumentProvider.getFileBuffer(getEditorInput());
@@ -785,20 +814,14 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
             Log.log(e);
         }
 
-        try {
-            executeSaveActions(document);
-        } catch (final Throwable e) {
-            Log.log(e);
-        }
-
         //will provide notifications
         super.performSave(overwrite, progressMonitor);
     }
 
     private void executeSaveActions(IDocument document) throws BadLocationException {
-        if (PydevSaveActionsPrefPage.getDateFieldActionEnabled()) {
+        if (PydevSaveActionsPrefPage.getDateFieldActionEnabled(this)) {
             final String contents = document.get();
-            final String fieldName = PydevSaveActionsPrefPage.getDateFieldName();
+            final String fieldName = PydevSaveActionsPrefPage.getDateFieldName(this);
             final String fieldPattern = String
                     .format("^%s(\\s*)=(\\s*[ur]{0,2}['\"]{1,3})(.+?)(['\"]{1,3})", fieldName);
             final Pattern pattern = Pattern.compile(fieldPattern, Pattern.MULTILINE);
@@ -810,7 +833,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
                     final String spAfterQuoteBegin = matchResult.group(2);
                     final String dateStr = matchResult.group(3);
                     final String quoteEnd = matchResult.group(4);
-                    final String dateFormat = PydevSaveActionsPrefPage.getDateFieldFormat();
+                    final String dateFormat = PydevSaveActionsPrefPage.getDateFieldFormat(this);
                     final Date nowDate = new Date();
                     final SimpleDateFormat ft = new SimpleDateFormat(dateFormat);
                     try {
@@ -829,7 +852,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
             }
         }
 
-        if (PydevSaveActionsPrefPage.getSortImportsOnSave()) {
+        if (PydevSaveActionsPrefPage.getSortImportsOnSave(this)) {
             boolean automatic = true;
             PyOrganizeImports organizeImports = new PyOrganizeImports(automatic);
             try {
@@ -1101,6 +1124,10 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
             return fOfflineActionTarget;
         }
 
+        if (IProject.class.equals(adapter)) {
+            return this.getProject();
+        }
+
         if (ICodeScannerKeywords.class.equals(adapter)) {
             return new PyEditBasedCodeScannerKeywords(this);
         }
@@ -1555,15 +1582,33 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
         }
     }
 
+    public static Object iterOpenEditorsUntilFirstReturn(ICallback<Object, PyEdit> callback) {
+        HashSet<PyEdit> hashSet;
+        synchronized (currentlyOpenedEditorsLock) {
+            hashSet = new HashSet<>(currentlyOpenedEditors);
+        }
+        // Iterate in unsynchronized copy
+        for (PyEdit edit : hashSet) {
+            Object ret = callback.call(edit);
+            if (ret != null) {
+                return ret;
+            }
+        }
+        return null;
+    }
+
     public static boolean isEditorOpenForResource(IResource r) {
+        HashSet<PyEdit> hashSet;
         synchronized (currentlyOpenedEditorsLock) {
-            for (PyEdit edit : currentlyOpenedEditors) {
-                IEditorInput input = edit.getEditorInput();
-                if (input != null) {
-                    Object adapter = input.getAdapter(IResource.class);
-                    if (adapter != null && r.equals(adapter)) {
-                        return true;
-                    }
+            hashSet = new HashSet<>(currentlyOpenedEditors);
+        }
+        // Iterate in unsynchronized copy
+        for (PyEdit edit : hashSet) {
+            IEditorInput input = edit.getEditorInput();
+            if (input != null) {
+                Object adapter = input.getAdapter(IResource.class);
+                if (adapter != null && r.equals(adapter)) {
+                    return true;
                 }
             }
         }
@@ -1571,7 +1616,7 @@ public class PyEdit extends PyEditProjection implements IPyEdit, IGrammarVersion
     }
 
     public FormatStd getFormatStd() {
-        return PyFormatStd.getFormat();
+        return PyFormatStd.getFormat(this);
     }
 
     /**
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/PyEditConfigurationWithoutEditor.java b/plugins/org.python.pydev/src/org/python/pydev/editor/PyEditConfigurationWithoutEditor.java
index f19ce38..8e82921 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/PyEditConfigurationWithoutEditor.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/PyEditConfigurationWithoutEditor.java
@@ -24,8 +24,9 @@ import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.ui.editors.text.EditorsUI;
 import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
 import org.eclipse.ui.texteditor.spelling.SpellingService;
+import org.python.pydev.core.IIndentPrefs;
 import org.python.pydev.core.IPythonPartitions;
-import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
+import org.python.pydev.core.log.Log;
 import org.python.pydev.editor.autoedit.PyAutoIndentStrategy;
 import org.python.pydev.editor.codecompletion.PyContentAssistant;
 import org.python.pydev.editor.preferences.PydevEditorPrefs;
@@ -60,7 +61,7 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * Has to return all the types generated by partition scanner.
-     * 
+     *
      * The SourceViewer will ignore double-clicks and any other configuration behaviors inside any partition not declared here
      */
     @Override
@@ -78,12 +79,12 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * Cache the result, because we'll get asked for it multiple times Now, we always return the PyAutoIndentStrategy. (even on commented lines).
-     * 
+     *
      * @return PyAutoIndentStrategy which deals with spaces/tabs
      */
     @Override
     public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
-        return new IAutoEditStrategy[] { getPyAutoIndentStrategy() };
+        return new IAutoEditStrategy[] { getPyAutoIndentStrategy(null) };
     }
 
     @Override
@@ -109,33 +110,33 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * Cache the result, because we'll get asked for it multiple times Now, we always return the PyAutoIndentStrategy. (even on commented lines).
-     * 
+     * @param projectAdaptable
+     *
      * @return PyAutoIndentStrategy which deals with spaces/tabs
      */
-    public PyAutoIndentStrategy getPyAutoIndentStrategy() {
+    public PyAutoIndentStrategy getPyAutoIndentStrategy(IAdaptable projectAdaptable) {
         if (autoIndentStrategy == null) {
-            autoIndentStrategy = new PyAutoIndentStrategy();
+            if (projectAdaptable == null) {
+                Log.log("Received null for projectAdaptable. Usig default preferences instead of project-specific preferences.");
+            }
+            autoIndentStrategy = new PyAutoIndentStrategy(projectAdaptable);
         }
         return autoIndentStrategy;
     }
 
     /**
      * Recalculates indent prefixes based upon preferences
-     * 
+     *
      * we hold onto the same array SourceViewer has, and write directly into it. This is because there is no way to tell SourceViewer that indent prefixes have changed. And we need this functionality
      * when user resets the tabs vs. spaces preference
      */
     public void resetIndentPrefixes() {
-        IPreferenceStore prefs = PydevPlugin.getDefault().getPreferenceStore();
-        int tabWidth = DefaultIndentPrefs.getStaticTabWidth();
+        IIndentPrefs indentPrefs = (getPyAutoIndentStrategy(null)).getIndentPrefs();
+        int tabWidth = indentPrefs.getTabWidth();
         FastStringBuffer spaces = new FastStringBuffer(8);
+        spaces.appendN(' ', tabWidth);
 
-        for (int i = 0; i < tabWidth; i++) {
-            spaces.append(" ");
-        }
-
-        boolean spacesFirst = prefs.getBoolean(PydevEditorPrefs.SUBSTITUTE_TABS)
-                && !(getPyAutoIndentStrategy()).getIndentPrefs().getForceTabs();
+        boolean spacesFirst = indentPrefs.getUseSpaces(true);
 
         if (spacesFirst) {
             indentPrefixes[0] = spaces.toString();
@@ -148,9 +149,9 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * Prefixes used in shift-left/shift-right editor operations
-     * 
+     *
      * shift-right uses prefix[0] shift-left removes a single instance of the first prefix from the array that matches
-     * 
+     *
      * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getIndentPrefixes(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
      */
     @Override
@@ -162,7 +163,7 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * Just the default double-click strategy for now. But we should be smarter.
-     * 
+     *
      * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getDoubleClickStrategy(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
      */
     @Override
@@ -172,12 +173,12 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /**
      * TabWidth is defined inside pydev preferences.
-     * 
+     *
      * Python uses its own tab width, since I think that its standard is 8
      */
     @Override
     public int getTabWidth(ISourceViewer sourceViewer) {
-        return DefaultIndentPrefs.getStaticTabWidth();
+        return getPyAutoIndentStrategy(null).getIndentPrefs().getTabWidth();
     }
 
     @Override
@@ -242,7 +243,7 @@ public class PyEditConfigurationWithoutEditor extends TextSourceViewerConfigurat
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getInformationControlCreator(org.eclipse.jface.text.source.ISourceViewer)
      */
     @Override
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyAddBlockComment.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyAddBlockComment.java
index b843e71..c79542b 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyAddBlockComment.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyAddBlockComment.java
@@ -185,7 +185,7 @@ public class PyAddBlockComment extends AbstractBlockCommentAction {
                 strbuf.append(strBefore).append("#").append(fullCommentLine).append(endLineDelim);
 
                 String spacesInStartComment = null;
-                FormatStd std = this.std != null ? this.std : PyFormatStd.getFormat();
+                FormatStd std = this.std != null ? this.std : PyFormatStd.getFormat(getPyEdit());
                 if (std.spacesInStartComment != 0) {
                     if (std.spacesInStartComment < 0) {
                         //Negative means that we manage it manually!
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyBackspace.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyBackspace.java
index ab7bb12..892f72e 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyBackspace.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyBackspace.java
@@ -10,6 +10,7 @@
  */
 package org.python.pydev.editor.actions;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
@@ -135,6 +136,7 @@ public class PyBackspace extends PyAction {
      *  - erase all whitespace characters until we find some character.
      *  - erase a single character.
      */
+    @Override
     public void run(IAction action) {
         OfflineActionTarget adapter = (OfflineActionTarget) getPyEdit().getAdapter(OfflineActionTarget.class);
         if (adapter != null) {
@@ -408,7 +410,19 @@ public class PyBackspace extends PyAction {
                             if (edit != null) {
                                 pyBackspace.setEditor(edit);
                             } else {
-                                pyBackspace.setIndentPrefs(new DefaultIndentPrefs());
+                                IAdaptable adaptable;
+                                if (viewer instanceof IAdaptable) {
+                                    adaptable = (IAdaptable) viewer;
+                                } else {
+                                    adaptable = new IAdaptable() {
+
+                                        @Override
+                                        public Object getAdapter(Class adapter) {
+                                            return null;
+                                        }
+                                    };
+                                }
+                                pyBackspace.setIndentPrefs(new DefaultIndentPrefs(adaptable));
                             }
                             PySelection ps = new PySelection(viewer.getDocument(), (ITextSelection) selection);
                             pyBackspace.perform(ps);
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertSpaceToTab.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertSpaceToTab.java
index 701ab9d..53071f2 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertSpaceToTab.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertSpaceToTab.java
@@ -16,6 +16,7 @@ import org.eclipse.jface.dialogs.IInputValidator;
 import org.eclipse.jface.dialogs.InputDialog;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
+import org.eclipse.ui.texteditor.ITextEditor;
 import org.python.pydev.core.docutils.PySelection;
 import org.python.pydev.editor.autoedit.DefaultIndentPrefs;
 import org.python.pydev.shared_core.string.FastStringBuffer;
@@ -35,6 +36,7 @@ public class PyConvertSpaceToTab extends PyAction {
     /**
      * Grabs the selection information and performs the action.
      */
+    @Override
     public void run(IAction action) {
         try {
             if (!canModifyEditor()) {
@@ -42,13 +44,14 @@ public class PyConvertSpaceToTab extends PyAction {
             }
 
             // Select from text editor
-            ps = new PySelection(getTextEditor());
+            ITextEditor textEditor = getTextEditor();
+            ps = new PySelection(textEditor);
             ps.selectAll(false);
             // Perform the action
-            perform(ps);
+            perform(ps, textEditor);
 
             // Put cursor at the first area of the selection
-            getTextEditor().selectAndReveal(ps.getLineOffset(), 0);
+            textEditor.selectAndReveal(ps.getLineOffset(), 0);
         } catch (Exception e) {
             beep(e);
         }
@@ -59,9 +62,10 @@ public class PyConvertSpaceToTab extends PyAction {
      * 
      * @param ps
      *            Given PySelection
+     * @param textEditor 
      * @return boolean The success or failure of the action
      */
-    public static boolean perform(PySelection ps) {
+    public static boolean perform(PySelection ps, ITextEditor textEditor) {
         // What we'll be replacing the selected text with
         FastStringBuffer strbuf = new FastStringBuffer();
 
@@ -72,7 +76,7 @@ public class PyConvertSpaceToTab extends PyAction {
 
         try {
             // For each line, strip their whitespace
-            String tabSpace = getTabSpace();
+            String tabSpace = getTabSpace(textEditor);
             if (tabSpace == null) {
                 return false; //could not get it
             }
@@ -99,10 +103,11 @@ public class PyConvertSpaceToTab extends PyAction {
 
     /**
      * Currently returns an int of the Preferences' Tab Width.
+     * @param textEditor 
      * 
      * @return Tab width in preferences
      */
-    protected static String getTabSpace() {
+    protected static String getTabSpace(ITextEditor textEditor) {
         class NumberValidator implements IInputValidator {
 
             /*
@@ -110,13 +115,15 @@ public class PyConvertSpaceToTab extends PyAction {
              */
             public String isValid(String input) {
 
-                if (input == null || input.length() == 0)
+                if (input == null || input.length() == 0) {
                     return " ";
+                }
 
                 try {
                     int i = Integer.parseInt(input);
-                    if (i <= 0)
+                    if (i <= 0) {
                         return "Must be more than 0.";
+                    }
 
                 } catch (NumberFormatException x) {
                     return x.getMessage();
@@ -127,19 +134,15 @@ public class PyConvertSpaceToTab extends PyAction {
         }
 
         InputDialog inputDialog = new InputDialog(EditorUtils.getShell(), "Tab length",
-                "How many spaces should be considered for each tab?", "" + DefaultIndentPrefs.getStaticTabWidth(),
+                "How many spaces should be considered for each tab?", ""
+                        + DefaultIndentPrefs.get(textEditor).getTabWidth(),
                 new NumberValidator());
 
         if (inputDialog.open() != InputDialog.OK) {
             return null;
         }
 
-        StringBuffer sbuf = new StringBuffer();
         int tabWidth = Integer.parseInt(inputDialog.getValue());
-        for (int i = 0; i < tabWidth; i++) {
-            sbuf.append(" ");
-        }
-        return sbuf.toString();
+        return new FastStringBuffer(tabWidth).appendN(' ', tabWidth).toString();
     }
-
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertTabToSpace.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertTabToSpace.java
index 642706e..dd78a37 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertTabToSpace.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyConvertTabToSpace.java
@@ -14,6 +14,7 @@ package org.python.pydev.editor.actions;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
+import org.eclipse.ui.texteditor.ITextEditor;
 import org.python.pydev.core.docutils.PySelection;
 import org.python.pydev.shared_core.string.FastStringBuffer;
 
@@ -30,6 +31,7 @@ public class PyConvertTabToSpace extends PyConvertSpaceToTab {
     /**
      * Grabs the selection information and performs the action.
      */
+    @Override
     public void run(IAction action) {
         try {
             if (!canModifyEditor()) {
@@ -37,13 +39,14 @@ public class PyConvertTabToSpace extends PyConvertSpaceToTab {
             }
 
             // Select from text editor
-            ps = new PySelection(getTextEditor());
+            ITextEditor textEditor = getTextEditor();
+            ps = new PySelection(textEditor);
             ps.selectAll(false);
             // Perform the action
-            perform();
+            perform(textEditor);
 
             // Put cursor at the first area of the selection
-            getTextEditor().selectAndReveal(ps.getLineOffset(), 0);
+            textEditor.selectAndReveal(ps.getLineOffset(), 0);
         } catch (Exception e) {
             beep(e);
         }
@@ -54,8 +57,8 @@ public class PyConvertTabToSpace extends PyConvertSpaceToTab {
      * 
      * @return boolean The success or failure of the action
      */
-    public static boolean perform() {
-        return perform(ps);
+    public static boolean perform(ITextEditor textEditor) {
+        return perform(ps, textEditor);
     }
 
     /**
@@ -64,7 +67,7 @@ public class PyConvertTabToSpace extends PyConvertSpaceToTab {
      * @param ps Given PySelection
      * @return boolean The success or failure of the action
      */
-    public static boolean perform(PySelection ps) {
+    public static boolean perform(PySelection ps, ITextEditor textEditor) {
         // What we'll be replacing the selected text with
         FastStringBuffer strbuf = new FastStringBuffer();
 
@@ -76,7 +79,7 @@ public class PyConvertTabToSpace extends PyConvertSpaceToTab {
         try {
             // For each line, strip their whitespace
             IDocument doc = ps.getDoc();
-            String tabSpace = getTabSpace();
+            String tabSpace = getTabSpace(textEditor);
             int endLineIndex = ps.getEndLineIndex();
             String endLineDelim = ps.getEndLineDelim();
             for (i = ps.getStartLineIndex(); i <= endLineIndex; i++) {
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyFormatStd.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyFormatStd.java
index 8cd1f15..ad542ff 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyFormatStd.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyFormatStd.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.action.IAction;
@@ -239,7 +240,7 @@ public class PyFormatStd extends PyAction implements IFormatter {
     }
 
     public void formatSelection(IDocument doc, int[] regionsForSave, IPyFormatStdProvider edit, PySelection ps) {
-        FormatStd formatStd = getFormat();
+        FormatStd formatStd = getFormat(edit);
         formatSelection(doc, regionsForSave, edit, ps, formatStd);
     }
 
@@ -323,7 +324,7 @@ public class PyFormatStd extends PyAction implements IFormatter {
         //        Formatter formatter = new Formatter();
         //        formatter.formatAll(doc, edit);
 
-        FormatStd formatStd = (FormatStd) (edit != null ? edit.getFormatStd() : getFormat());
+        FormatStd formatStd = (FormatStd) (edit != null ? edit.getFormatStd() : getFormat(f));
         formatAll(doc, edit, isOpenedFile, formatStd, throwSyntaxError);
 
     }
@@ -370,19 +371,20 @@ public class PyFormatStd extends PyAction implements IFormatter {
     /**
      * @return the format standard that should be used to do the formatting
      */
-    public static FormatStd getFormat() {
+    public static FormatStd getFormat(IAdaptable projectAdaptable) {
         FormatStd formatStd = new FormatStd();
-        formatStd.assignWithSpaceInsideParens = PyCodeFormatterPage.useAssignWithSpacesInsideParenthesis();
-        formatStd.operatorsWithSpace = PyCodeFormatterPage.useOperatorsWithSpace();
-        formatStd.parametersWithSpace = PyCodeFormatterPage.useSpaceForParentesis();
-        formatStd.spaceAfterComma = PyCodeFormatterPage.useSpaceAfterComma();
-        formatStd.addNewLineAtEndOfFile = PyCodeFormatterPage.getAddNewLineAtEndOfFile();
-        formatStd.trimLines = PyCodeFormatterPage.getTrimLines();
-        formatStd.trimMultilineLiterals = PyCodeFormatterPage.getTrimMultilineLiterals();
-        formatStd.spacesBeforeComment = PyCodeFormatterPage.getSpacesBeforeComment();
-        formatStd.spacesInStartComment = PyCodeFormatterPage.getSpacesInStartComment();
-        formatStd.formatWithAutopep8 = PyCodeFormatterPage.getFormatWithAutopep8();
-        formatStd.autopep8Parameters = PyCodeFormatterPage.getAutopep8Parameters();
+        formatStd.assignWithSpaceInsideParens = PyCodeFormatterPage
+                .useAssignWithSpacesInsideParenthesis(projectAdaptable);
+        formatStd.operatorsWithSpace = PyCodeFormatterPage.useOperatorsWithSpace(projectAdaptable);
+        formatStd.parametersWithSpace = PyCodeFormatterPage.useSpaceForParentesis(projectAdaptable);
+        formatStd.spaceAfterComma = PyCodeFormatterPage.useSpaceAfterComma(projectAdaptable);
+        formatStd.addNewLineAtEndOfFile = PyCodeFormatterPage.getAddNewLineAtEndOfFile(projectAdaptable);
+        formatStd.trimLines = PyCodeFormatterPage.getTrimLines(projectAdaptable);
+        formatStd.trimMultilineLiterals = PyCodeFormatterPage.getTrimMultilineLiterals(projectAdaptable);
+        formatStd.spacesBeforeComment = PyCodeFormatterPage.getSpacesBeforeComment(projectAdaptable);
+        formatStd.spacesInStartComment = PyCodeFormatterPage.getSpacesInStartComment(projectAdaptable);
+        formatStd.formatWithAutopep8 = PyCodeFormatterPage.getFormatWithAutopep8(projectAdaptable);
+        formatStd.autopep8Parameters = PyCodeFormatterPage.getAutopep8Parameters(projectAdaptable);
         formatStd.updateAutopep8();
         return formatStd;
     }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyMoveLineAction.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyMoveLineAction.java
index 6bc32df..e51e9df 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyMoveLineAction.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyMoveLineAction.java
@@ -9,6 +9,7 @@ package org.python.pydev.editor.actions;
 import java.util.ResourceBundle;
 
 import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DocumentCommand;
 import org.eclipse.jface.text.IDocument;
@@ -36,7 +37,6 @@ import org.python.pydev.editor.PyEdit;
 import org.python.pydev.editor.autoedit.PyAutoIndentStrategy;
 import org.python.pydev.shared_core.utils.DocCmd;
 
-
 /**
  * Base class for actions that do a move action (Alt+Up or Alt+Down).
  * 
@@ -54,30 +54,36 @@ public abstract class PyMoveLineAction extends TextEditorAction {
         update();
     }
 
+    @Override
     public void runWithEvent(Event event) {
         run();
     }
 
+    @Override
     public void run() {
         // get involved objects
         if (pyEdit == null) {
             return;
         }
 
-        if (!validateEditorInputState())
+        if (!validateEditorInputState()) {
             return;
+        }
 
         ISourceViewer viewer = pyEdit.getEditorSourceViewer();
-        if (viewer == null)
+        if (viewer == null) {
             return;
+        }
 
         IDocument document = viewer.getDocument();
-        if (document == null)
+        if (document == null) {
             return;
+        }
 
         StyledText widget = viewer.getTextWidget();
-        if (widget == null)
+        if (widget == null) {
             return;
+        }
 
         // get selection
         ITextSelection sel = (ITextSelection) viewer.getSelectionProvider().getSelection();
@@ -85,12 +91,14 @@ public abstract class PyMoveLineAction extends TextEditorAction {
     }
 
     public void move(PyEdit pyEdit, ISourceViewer viewer, IDocument document, ITextSelection sel) {
-        if (sel.isEmpty())
+        if (sel.isEmpty()) {
             return;
+        }
 
         ITextSelection skippedLine = getSkippedLine(document, sel);
-        if (skippedLine == null)
+        if (skippedLine == null) {
             return;
+        }
 
         ITextSelection movingArea;
         try {
@@ -102,16 +110,18 @@ public abstract class PyMoveLineAction extends TextEditorAction {
 
             // if either the skipped line or the moving lines are outside the widget's
             // visible area, bail out
-            if (!containedByVisibleRegion(movingArea, viewer) || !containedByVisibleRegion(skippedLine, viewer))
+            if (!containedByVisibleRegion(movingArea, viewer) || !containedByVisibleRegion(skippedLine, viewer)) {
                 return;
+            }
 
             PySelection skippedPs = new PySelection(document, skippedLine);
 
             // get the content to be moved around: the moving (selected) area and the skipped line
             String moving = movingArea.getText();
             String skipped = skippedLine.getText();
-            if (moving == null || skipped == null || document.getLength() == 0)
+            if (moving == null || skipped == null || document.getLength() == 0) {
                 return;
+            }
 
             String delim;
             String insertion;
@@ -168,7 +178,13 @@ public abstract class PyMoveLineAction extends TextEditorAction {
                     indentStrategy = pyEdit.getAutoEditStrategy();
                 }
                 if (indentStrategy == null) {
-                    indentStrategy = new PyAutoIndentStrategy();
+                    indentStrategy = new PyAutoIndentStrategy(new IAdaptable() {
+
+                        @Override
+                        public Object getAdapter(Class adapter) {
+                            return null;
+                        }
+                    });
                 }
 
                 if (!isStringPartition) {
@@ -272,15 +288,18 @@ public abstract class PyMoveLineAction extends TextEditorAction {
         //viewer.revealRange(offset, length); // will trigger jumping
         StyledText st = viewer.getTextWidget();
         if (st != null)
+        {
             st.showSelection(); // only minimal scrolling
+        }
     }
 
     private IRegion getRegion(IDocument document, ILineRange lineRange) throws BadLocationException {
         final int startLine = lineRange.getStartLine();
         int offset = document.getLineOffset(startLine);
         final int numberOfLines = lineRange.getNumberOfLines();
-        if (numberOfLines < 1)
+        if (numberOfLines < 1) {
             return new Region(offset, 0);
+        }
         int endLine = startLine + numberOfLines - 1;
         int endOffset;
         boolean blockSelectionModeEnabled = false;
@@ -304,6 +323,7 @@ public abstract class PyMoveLineAction extends TextEditorAction {
     /*
      * @see org.eclipse.ui.texteditor.IUpdate#update()
      */
+    @Override
     public void update() {
         super.update();
 
@@ -325,8 +345,9 @@ public abstract class PyMoveLineAction extends TextEditorAction {
     private ITextSelection getSkippedLine(IDocument document, ITextSelection selection) {
         int skippedLineN = (getMoveUp() ? selection.getStartLine() - 1 : selection.getEndLine() + 1);
         if (skippedLineN > document.getNumberOfLines()
-                || ((skippedLineN < 0 || skippedLineN == document.getNumberOfLines())))
+                || ((skippedLineN < 0 || skippedLineN == document.getNumberOfLines()))) {
             return null;
+        }
         try {
             IRegion line = document.getLineInformation(skippedLineN);
             return new TextSelection(document, line.getOffset(), line.getLength());
@@ -361,8 +382,9 @@ public abstract class PyMoveLineAction extends TextEditorAction {
 
         // get everything up to last line without its delimiter
         String delim = document.getLineDelimiter(endLine);
-        if (delim != null)
+        if (delim != null) {
             high -= delim.length();
+        }
 
         return new TextSelection(document, low, high - low);
     }
@@ -385,16 +407,18 @@ public abstract class PyMoveLineAction extends TextEditorAction {
         IDocument document = viewer.getDocument();
 
         IRegion visible;
-        if (viewer instanceof ITextViewerExtension5)
+        if (viewer instanceof ITextViewerExtension5) {
             visible = ((ITextViewerExtension5) viewer).getModelCoverage();
-        else
+        } else {
             visible = viewer.getVisibleRegion();
+        }
 
         int visOffset = visible.getOffset();
         try {
             if (visOffset > min) {
-                if (document.getLineOfOffset(visOffset) != selection.getStartLine())
+                if (document.getLineOfOffset(visOffset) != selection.getStartLine()) {
                     return false;
+                }
                 if (!isWhitespace(document.get(min, visOffset - min))) {
                     showStatus();
                     return false;
@@ -402,8 +426,9 @@ public abstract class PyMoveLineAction extends TextEditorAction {
             }
             int visEnd = visOffset + visible.getLength();
             if (visEnd < max) {
-                if (document.getLineOfOffset(visEnd) != selection.getEndLine())
+                if (document.getLineOfOffset(visEnd) != selection.getEndLine()) {
                     return false;
+                }
                 if (!isWhitespace(document.get(visEnd, max - visEnd))) {
                     showStatus();
                     return false;
@@ -432,8 +457,9 @@ public abstract class PyMoveLineAction extends TextEditorAction {
     private void showStatus() {
         ITextEditor textEditor = getTextEditor();
         IEditorStatusLine status = (IEditorStatusLine) textEditor.getAdapter(IEditorStatusLine.class);
-        if (status == null)
+        if (status == null) {
             return;
+        }
         status.setMessage(false,
                 "Move not possible - Uncheck \"Show Source of Selected Element Only\" to see the entire document", null);
     }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyOrganizeImports.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyOrganizeImports.java
index 61592fb..1325ab8 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyOrganizeImports.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyOrganizeImports.java
@@ -19,6 +19,7 @@ import java.util.List;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
@@ -56,6 +57,7 @@ public class PyOrganizeImports extends PyAction implements IFormatter {
     /**
      * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
      */
+    @Override
     public void run(IAction action) {
         try {
             if (!canModifyEditor()) {
@@ -97,9 +99,10 @@ public class PyOrganizeImports extends PyAction implements IFormatter {
             }
         }
 
+        IAdaptable projectAdaptable = edit != null ? edit : f;
         String indentStr = edit != null ?
                 edit.getIndentPrefs().getIndentationString() :
-                DefaultIndentPrefs.get().getIndentationString();
+                DefaultIndentPrefs.get(f).getIndentationString();
         session = startWrite(doc);
         try {
             //Important: the remove and later update have to be done in the same session (since the remove
@@ -109,13 +112,13 @@ public class PyOrganizeImports extends PyAction implements IFormatter {
             boolean removeUnusedImports = false;
             if (!automatic) {
                 //Only go through the removal of unused imports if it's manually activated (not on automatic mode).
-                removeUnusedImports = ImportsPreferencesPage.getDeleteUnusedImports();
+                removeUnusedImports = ImportsPreferencesPage.getDeleteUnusedImports(projectAdaptable);
                 if (removeUnusedImports) {
                     new OrganizeImportsFixesUnused().beforePerformArrangeImports(ps, edit, f);
                 }
             }
 
-            boolean pep8 = ImportsPreferencesPage.getPep8Imports();
+            boolean pep8 = ImportsPreferencesPage.getPep8Imports(projectAdaptable);
 
             if (pep8) {
                 if (f == null) {
@@ -171,7 +174,7 @@ public class PyOrganizeImports extends PyAction implements IFormatter {
      */
     public static void performArrangeImports(IDocument doc, boolean removeUnusedImports, String endLineDelim,
             String indentStr, boolean automatic, IPyFormatStdProvider edit) {
-        new ImportArranger(doc, removeUnusedImports, endLineDelim, indentStr, automatic).perform(edit);
+        new ImportArranger(doc, removeUnusedImports, endLineDelim, indentStr, automatic, edit).perform();
     }
 
     /**
@@ -183,7 +186,7 @@ public class PyOrganizeImports extends PyAction implements IFormatter {
      */
     public static void pep8PerformArrangeImports(IDocument doc, boolean removeUnusedImports, String endLineDelim,
             IProject prj, String indentStr, boolean automatic, IPyFormatStdProvider edit) {
-        new Pep8ImportArranger(doc, removeUnusedImports, endLineDelim, prj, indentStr, automatic).perform(edit);
+        new Pep8ImportArranger(doc, removeUnusedImports, endLineDelim, prj, indentStr, automatic, edit).perform();
     }
 
     /**
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyPeerLinker.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyPeerLinker.java
index e7c4ada..6944b6c 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyPeerLinker.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyPeerLinker.java
@@ -6,6 +6,7 @@
  */
 package org.python.pydev.editor.actions;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DocumentCommand;
 import org.eclipse.jface.text.IDocument;
@@ -91,10 +92,22 @@ public class PyPeerLinker {
 
                         ISelection selection = viewer.getSelection();
                         if (selection instanceof ITextSelection) {
+                            IAdaptable adaptable;
+                            if (viewer instanceof IAdaptable) {
+                                adaptable = (IAdaptable) viewer;
+                            } else {
+                                adaptable = new IAdaptable() {
+
+                                    @Override
+                                    public Object getAdapter(Class adapter) {
+                                        return null;
+                                    }
+                                };
+                            }
 
                             //Don't bother in getting the indent prefs from the editor: the default indent prefs are 
                             //always global for the settings we want.
-                            pyPeerLinker.setIndentPrefs(new DefaultIndentPrefs());
+                            pyPeerLinker.setIndentPrefs(new DefaultIndentPrefs(adaptable));
                             PySelection ps = new PySelection(viewer.getDocument(), (ITextSelection) selection);
 
                             if (pyPeerLinker.perform(ps, event.character, viewer)) {
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyRemoveBlockComment.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyRemoveBlockComment.java
index e164b86..a962eb5 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyRemoveBlockComment.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/PyRemoveBlockComment.java
@@ -226,7 +226,7 @@ public class PyRemoveBlockComment extends PyAddBlockComment {
                                 PyEdit pyEdit = (PyEdit) targetEditor;
                                 indentPrefs = pyEdit.getIndentPrefs();
                             } else {
-                                indentPrefs = DefaultIndentPrefs.get();
+                                indentPrefs = DefaultIndentPrefs.get(null);
                             }
 
                             String indentationString = indentPrefs.getIndentationString();
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/ImportArranger.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/ImportArranger.java
index c166748..5c65390 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/ImportArranger.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/ImportArranger.java
@@ -37,6 +37,8 @@ import org.python.pydev.ui.importsconf.ImportsPreferencesPage;
 
 public class ImportArranger {
 
+    public boolean addNewLinesToImports = false;
+
     private final class FromImportEntries {
         private final List<ImportHandleInfo> containedImports = new ArrayList<>();
 
@@ -201,8 +203,8 @@ public class ImportArranger {
     /**
      * @return true if the imports should be split with parenthesis (instead of escaping)
      */
-    private static boolean getBreakImportsWithParenthesis() {
-        String breakIportMode = ImportsPreferencesPage.getBreakIportMode();
+    private static boolean getBreakImportsWithParenthesis(IPyFormatStdProvider edit) {
+        String breakIportMode = ImportsPreferencesPage.getBreakIportMode(edit);
         boolean breakWithParenthesis = true;
         if (!breakIportMode.equals(ImportsPreferencesPage.BREAK_IMPORTS_MODE_PARENTHESIS)) {
             breakWithParenthesis = false;
@@ -214,24 +216,30 @@ public class ImportArranger {
     protected final String endLineDelim;
     private final String indentStr;
     private int lineForNewImports = -1;
-    private final boolean multilineImports = ImportsPreferencesPage.getMultilineImports();
-    private final boolean sortNamesGrouped = ImportsPreferencesPage.getSortNamesGrouped();
-    private int maxCols = getMaxCols(multilineImports);
-    private final boolean breakWithParenthesis = getBreakImportsWithParenthesis();
+    private final boolean multilineImports;
+    private final boolean sortNamesGrouped;
+    private int maxCols;
+    private final boolean breakWithParenthesis;
     private final boolean removeUnusedImports;
     private final boolean automatic;
+    protected final IPyFormatStdProvider edit;
 
     public ImportArranger(IDocument doc, boolean removeUnusedImports, String endLineDelim, String indentStr,
-            boolean automatic) {
+            boolean automatic, IPyFormatStdProvider edit) {
         this.doc = doc;
         this.endLineDelim = endLineDelim;
         this.indentStr = indentStr;
         this.removeUnusedImports = removeUnusedImports;
         this.automatic = automatic;
+        this.edit = edit;
+        multilineImports = ImportsPreferencesPage.getMultilineImports(edit);
+        sortNamesGrouped = ImportsPreferencesPage.getSortNamesGrouped(edit);
+        breakWithParenthesis = getBreakImportsWithParenthesis(edit);
+        maxCols = getMaxCols(multilineImports);
     }
 
-    public void perform(IPyFormatStdProvider edit) {
-        perform(ImportsPreferencesPage.getGroupImports(), edit);
+    public void perform() {
+        perform(ImportsPreferencesPage.getGroupImports(edit), edit);
     }
 
     protected void perform(boolean groupFromImports, IPyFormatStdProvider edit) {
@@ -311,6 +319,13 @@ public class ImportArranger {
             PySelection ps = new PySelection(psDoc);
             std.applyFormatAction(edit, ps, regionsToFormat, throwSyntaxError, selectionProvider);
             finalStr = psDoc.get();
+            if (addNewLinesToImports) {
+                // Leave 2 empty new lines separating imports from code 
+                String expectedEnd = endLineDelim + endLineDelim + endLineDelim;
+                while (!finalStr.endsWith(expectedEnd)) {
+                    finalStr += endLineDelim;
+                }
+            }
         } catch (Exception e) {
             Log.log(e);
         }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/Pep8ImportArranger.java b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/Pep8ImportArranger.java
index 1712858..5ff6876 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/Pep8ImportArranger.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/actions/organize_imports/Pep8ImportArranger.java
@@ -177,8 +177,8 @@ public class Pep8ImportArranger extends ImportArranger {
     final ImportClassifier classifier;
 
     public Pep8ImportArranger(IDocument doc, boolean removeUnusedImports, String endLineDelim, IProject prj,
-            String indentStr, boolean automatic) {
-        super(doc, removeUnusedImports, endLineDelim, indentStr, automatic);
+            String indentStr, boolean automatic, IPyFormatStdProvider edit) {
+        super(doc, removeUnusedImports, endLineDelim, indentStr, automatic, edit);
         classifier = getClassifier(prj);
     }
 
@@ -194,7 +194,7 @@ public class Pep8ImportArranger extends ImportArranger {
     }
 
     @Override
-    public void perform(IPyFormatStdProvider edit) {
+    public void perform() {
         //        if (ImportsPreferencesPage.getGroupImports()) {
         //            perform(true); -- TODO: This mode is flawed (must be reviewed).
         //        } else {
@@ -215,7 +215,7 @@ public class Pep8ImportArranger extends ImportArranger {
                     return class1 - class2;
                 }
 
-                if (ImportsPreferencesPage.getSortFromImportsFirst())
+                if (ImportsPreferencesPage.getSortFromImportsFirst(edit))
                 {
                     int type1 = getImportType(o1.o3);
                     int type2 = getImportType(o2.o3);
@@ -423,6 +423,7 @@ public class Pep8ImportArranger extends ImportArranger {
                         }
                     case BlankLine:
                         // delete all blank lines in imports section of document
+                        addNewLinesToImports = true;
                         l--;
                         doc.replace(lineInfo.getOffset(),
                                 lineInfo.getLength() + endLineDelim.length(),
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/DefaultIndentPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/DefaultIndentPrefs.java
index 0821cfc..83d3a2f 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/DefaultIndentPrefs.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/DefaultIndentPrefs.java
@@ -6,38 +6,50 @@
  */
 /*
  * Created on May 5, 2005
- * 
+ *
  * @author Fabio Zadrozny
  */
 package org.python.pydev.editor.autoedit;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.python.pydev.core.IIndentPrefs;
-import org.python.pydev.core.cache.PyPreferencesCache;
+import org.python.pydev.core.ITabChangedListener;
+import org.python.pydev.editor.preferences.PyScopedPreferences;
 import org.python.pydev.editor.preferences.PydevEditorPrefs;
-import org.python.pydev.plugin.PydevPlugin;
+import org.python.pydev.editor.preferences.PydevTypingPrefs;
 import org.python.pydev.shared_core.SharedCorePlugin;
+import org.python.pydev.shared_core.callbacks.ListenerList;
 
 /**
  * Provides indentation preferences from the preferences set in the preferences pages within eclipse.
  */
 public class DefaultIndentPrefs extends AbstractIndentPrefs {
 
-    /** 
-     * Cache for indentation string 
+    /**
+     * Cache for indentation string
      */
     private String indentString = null;
 
-    private boolean useSpaces;
+    private String lastIndentString = null;
+
+    private boolean lastUseSpaces;
 
-    private int tabWidth;
+    private int lastTabWidth;
 
-    private static PyPreferencesCache cache;
+    private final IAdaptable projectAdaptable;
 
     /**
      * Singleton instance for the preferences
      */
     private static IIndentPrefs indentPrefs;
 
+    private ListenerList<ITabChangedListener> listenerList = new ListenerList<>(ITabChangedListener.class);
+
+    @Override
+    public void addTabChangedListener(ITabChangedListener listener) {
+        listenerList.add(listener);
+    }
+
     /**
      * Should only be used on tests (and on a finally it should be set to null again in the test).
      */
@@ -46,47 +58,38 @@ public class DefaultIndentPrefs extends AbstractIndentPrefs {
     }
 
     /**
+     * @param an IAdaptable which must adapt to IProject.
      * @return the indentation preferences to be used
      */
-    public synchronized static IIndentPrefs get() {
-        if (indentPrefs == null) {
-            if (SharedCorePlugin.inTestMode()) {
-                return new TestIndentPrefs(true, 4);
-            }
-            indentPrefs = new DefaultIndentPrefs();
+    public static IIndentPrefs get(IAdaptable projectAdaptable) {
+        if (indentPrefs != null) {
+            return indentPrefs;
         }
-        return indentPrefs;
-    }
-
-    /**
-     * @return a cache for the preferences.
-     */
-    private PyPreferencesCache getCache() {
-        if (cache == null) {
-            cache = new PyPreferencesCache(PydevPlugin.getDefault().getPreferenceStore());
+        if (SharedCorePlugin.inTestMode()) {
+            return new TestIndentPrefs(true, 4);
         }
-        return cache;
+        return new DefaultIndentPrefs(projectAdaptable);
     }
 
     /**
      * Not singleton (each pyedit may force to use tabs or not).
      */
-    public DefaultIndentPrefs() {
-        PyPreferencesCache c = getCache();
-        useSpaces = c.getBoolean(PydevEditorPrefs.SUBSTITUTE_TABS);
-        tabWidth = c.getInt(PydevEditorPrefs.TAB_WIDTH, 4);
+    public DefaultIndentPrefs(IAdaptable projectAdaptable) {
+        this.projectAdaptable = projectAdaptable;
+        lastUseSpaces = getBoolFromPreferences(PydevEditorPrefs.SUBSTITUTE_TABS);
+        regenerateIndentString();
     }
 
     public boolean getUseSpaces(boolean considerForceTabs) {
-        PyPreferencesCache c = getCache();
-        if (useSpaces != c.getBoolean(PydevEditorPrefs.SUBSTITUTE_TABS)) {
-            useSpaces = c.getBoolean(PydevEditorPrefs.SUBSTITUTE_TABS);
+        boolean boolFromPreferences = getBoolFromPreferences(PydevEditorPrefs.SUBSTITUTE_TABS);
+        if (lastUseSpaces != boolFromPreferences) {
+            lastUseSpaces = boolFromPreferences;
             regenerateIndentString();
         }
         if (considerForceTabs && getForceTabs()) {
             return false; //forcing tabs.
         }
-        return useSpaces;
+        return lastUseSpaces;
     }
 
     @Override
@@ -95,98 +98,105 @@ public class DefaultIndentPrefs extends AbstractIndentPrefs {
         regenerateIndentString(); //When forcing tabs, we must update the cache.
     }
 
-    public static int getStaticTabWidth() {
-        PydevPlugin default1 = PydevPlugin.getDefault();
-        if (default1 == null) {
-            return 4;
-        }
-        int w = default1.getPluginPreferences().getInt(PydevEditorPrefs.TAB_WIDTH);
-        if (w <= 0) { //tab width should never be 0 or less (in this case, let's make the default 4)
-            w = 4;
+    public int getTabWidth() {
+        if (lastTabWidth != getIntFromPreferences(PydevEditorPrefs.TAB_WIDTH, 1)) {
+            lastTabWidth = getIntFromPreferences(PydevEditorPrefs.TAB_WIDTH, 1);
+            regenerateIndentString();
         }
-        return w;
+        return lastTabWidth;
     }
 
-    public int getTabWidth() {
-        PyPreferencesCache c = getCache();
-        if (tabWidth != c.getInt(PydevEditorPrefs.TAB_WIDTH, 4)) {
-            tabWidth = c.getInt(PydevEditorPrefs.TAB_WIDTH, 4);
+    Boolean lastGuessTabSubstitution = null;
+
+    @Override
+    public boolean getGuessTabSubstitution() {
+        boolean curr = getBoolFromPreferences(PydevEditorPrefs.GUESS_TAB_SUBSTITUTION);
+        if (lastGuessTabSubstitution != null && lastGuessTabSubstitution != curr) {
             regenerateIndentString();
         }
-        return tabWidth;
+        lastGuessTabSubstitution = curr;
+        return curr;
     }
 
     public void regenerateIndentString() {
-        PyPreferencesCache c = getCache();
-        c.clear(PydevEditorPrefs.TAB_WIDTH);
-        c.clear(PydevEditorPrefs.SUBSTITUTE_TABS);
         indentString = super.getIndentationString();
+        if (lastIndentString == null || !lastIndentString.equals(indentString)) {
+            lastIndentString = indentString;
+            ITabChangedListener[] listeners = this.listenerList.getListeners();
+            for (ITabChangedListener iTabChangedListener : listeners) {
+                iTabChangedListener.onTabSettingsChanged(this);
+            }
+        }
     }
 
     /**
-     * This class also puts the indentation string in a cache and redoes it 
+     * This class also puts the indentation string in a cache and redoes it
      * if the preferences are changed.
-     * 
-     * @return the indentation string. 
+     *
+     * @return the indentation string.
      */
     @Override
     public String getIndentationString() {
-        if (indentString == null) {
-            regenerateIndentString();
-        }
-
         return indentString;
     }
 
-    /** 
+    /**
      * @see org.python.pydev.core.IIndentPrefs#getAutoParentesis()
      */
     public boolean getAutoParentesis() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_PAR);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_PAR);
     }
 
     public boolean getAutoLink() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_LINK);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_LINK);
     }
 
     public boolean getIndentToParLevel() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_INDENT_TO_PAR_LEVEL);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_INDENT_TO_PAR_LEVEL);
     }
 
     public boolean getAutoColon() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_COLON);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_COLON);
     }
 
     public boolean getAutoBraces() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_BRACES);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_BRACES);
     }
 
     public boolean getAutoWriteImport() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_WRITE_IMPORT_STR);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_WRITE_IMPORT_STR);
     }
 
     public boolean getSmartIndentPar() {
-        return getCache().getBoolean(PydevEditorPrefs.SMART_INDENT_PAR);
+        return getBoolFromPreferences(PydevTypingPrefs.SMART_INDENT_PAR);
     }
 
     public boolean getAutoAddSelf() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_ADD_SELF);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_ADD_SELF);
     }
 
     public boolean getAutoDedentElse() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_DEDENT_ELSE);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_DEDENT_ELSE);
     }
 
     public int getIndentAfterParWidth() {
-        return getCache().getInt(PydevEditorPrefs.AUTO_INDENT_AFTER_PAR_WIDTH, 1);
+        return getIntFromPreferences(PydevTypingPrefs.AUTO_INDENT_AFTER_PAR_WIDTH, 1);
     }
 
     public boolean getSmartLineMove() {
-        return getCache().getBoolean(PydevEditorPrefs.SMART_LINE_MOVE);
+        return getBoolFromPreferences(PydevTypingPrefs.SMART_LINE_MOVE);
     }
 
     public boolean getAutoLiterals() {
-        return getCache().getBoolean(PydevEditorPrefs.AUTO_LITERALS);
+        return getBoolFromPreferences(PydevTypingPrefs.AUTO_LITERALS);
+    }
+
+    private boolean getBoolFromPreferences(String pref) {
+        return PyScopedPreferences.getBoolean(pref, projectAdaptable);
+    }
+
+    private int getIntFromPreferences(String pref, int minVal) {
+        return PyScopedPreferences.getInt(pref, projectAdaptable, minVal);
     }
 
 }
\ No newline at end of file
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/PyAutoIndentStrategy.java b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/PyAutoIndentStrategy.java
index 42b0f60..a24d421 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/PyAutoIndentStrategy.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/PyAutoIndentStrategy.java
@@ -11,6 +11,7 @@
 
 package org.python.pydev.editor.autoedit;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.DocumentCommand;
@@ -51,7 +52,10 @@ public final class PyAutoIndentStrategy implements IAutoEditStrategy, IHandleScr
 
     private boolean blockSelection;
 
-    public PyAutoIndentStrategy() {
+    private final IAdaptable projectAdaptable;
+
+    public PyAutoIndentStrategy(IAdaptable projectAdaptable) {
+        this.projectAdaptable = projectAdaptable;
     }
 
     public void setIndentPrefs(IIndentPrefs prefs) {
@@ -63,7 +67,7 @@ public final class PyAutoIndentStrategy implements IAutoEditStrategy, IHandleScr
             if (SharedCorePlugin.inTestMode()) {
                 this.prefs = new TestIndentPrefs(true, 4);
             } else {
-                this.prefs = new DefaultIndentPrefs(); //create a new one (because each pyedit may force the tabs differently).
+                this.prefs = new DefaultIndentPrefs(projectAdaptable); //create a new one (because each pyedit may force the tabs differently).
             }
         }
         return this.prefs;
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/TestIndentPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/TestIndentPrefs.java
index a53cba7..03a147a 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/TestIndentPrefs.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/autoedit/TestIndentPrefs.java
@@ -6,6 +6,8 @@
  */
 package org.python.pydev.editor.autoedit;
 
+import org.python.pydev.core.ITabChangedListener;
+
 /**
  * Code to be used in tests.
  */
@@ -30,6 +32,16 @@ public class TestIndentPrefs extends AbstractIndentPrefs {
         this.tabWidth = tabWidth;
     }
 
+    @Override
+    public boolean getGuessTabSubstitution() {
+        return false;
+    }
+
+    @Override
+    public void addTabChangedListener(ITabChangedListener listener) {
+        // No-op for testing.
+    }
+
     public TestIndentPrefs(boolean useSpaces, int tabWidth, boolean autoPar) {
         this(useSpaces, tabWidth, autoPar, true);
     }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/IgnoreCompletionProposalInSameLine.java b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/IgnoreCompletionProposalInSameLine.java
index 352d500..c4e1552 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/IgnoreCompletionProposalInSameLine.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/IgnoreCompletionProposalInSameLine.java
@@ -11,6 +11,7 @@ import org.eclipse.jface.text.contentassist.IContextInformation;
 import org.eclipse.swt.graphics.Image;
 import org.python.pydev.core.docutils.ParsingUtils;
 import org.python.pydev.core.docutils.PySelection;
+import org.python.pydev.core.log.Log;
 import org.python.pydev.editor.PyEdit;
 import org.python.pydev.editor.actions.PyFormatStd;
 import org.python.pydev.editor.actions.PyFormatStd.FormatStd;
@@ -63,7 +64,9 @@ public class IgnoreCompletionProposalInSameLine extends IgnoreCompletionProposal
                 if (edit != null) {
                     formatStd = edit.getFormatStd();
                 } else {
-                    formatStd = PyFormatStd.getFormat();
+                    // Shouldn't happen when not in test mode
+                    Log.log("Error: using default format (not considering project preferences).");
+                    formatStd = PyFormatStd.getFormat(null);
                 }
             }
 
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/docstrings/AssistDocString.java b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/docstrings/AssistDocString.java
index f350a26..b0f4559 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/docstrings/AssistDocString.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/docstrings/AssistDocString.java
@@ -68,8 +68,8 @@ public class AssistDocString implements IAssistProps {
 
         String initial = PySelection.getIndentationFromLine(ps.getCursorLineContents());
         String delimiter = PyAction.getDelimiter(ps.getDoc());
-        String indentation = edit != null ? edit.getIndentPrefs().getIndentationString() : DefaultIndentPrefs.get()
-                .getIndentationString();
+        String indentation = edit != null ? edit.getIndentPrefs().getIndentationString() : DefaultIndentPrefs.get(
+                nature).getIndentationString();
         String inAndIndent = delimiter + initial + indentation;
 
         FastStringBuffer buf = new FastStringBuffer();
@@ -107,6 +107,7 @@ public class AssistDocString implements IAssistProps {
         }
         l.add(new PyCompletionProposal(comp, offsetPosToAdd, 0, newOffset, image, "Make docstring", null, null,
                 IPyCompletionProposal.PRIORITY_DEFAULT) {
+            @Override
             public void apply(IDocument document) {
                 //remove the next line if it is a pass...
                 PySelection ps = new PySelection(document, fReplacementOffset);
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWith.java b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWith.java
index 807da29..e8f08ae 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWith.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWith.java
@@ -49,15 +49,27 @@ public class AssistSurroundWith extends AbstractTemplateCodeCompletion implement
             PyEdit edit, int offset) throws BadLocationException {
 
         ArrayList<ICompletionProposal> l = new ArrayList<ICompletionProposal>();
-        String indentation = edit != null ? edit.getIndentPrefs().getIndentationString() : DefaultIndentPrefs.get()
-                .getIndentationString();
+        String indentation = edit != null ? edit.getIndentPrefs().getIndentationString() : DefaultIndentPrefs.get(
+                nature).getIndentationString();
 
         ps.selectCompleteLine();
         String selectedText = ps.getSelectedText();
         List<String> splitInLines = StringUtils.splitInLines(selectedText);
         int firstCharPosition = -1;
+        int firstCommentCharPosition = -1;
+
         for (String string : splitInLines) {
-            if (string.trim().length() > 0) {
+            String trimmed = string.trim();
+            if (trimmed.startsWith("#")) {
+                int localFirst = PySelection.getFirstCharPosition(string);
+                if (firstCommentCharPosition == -1) {
+                    firstCommentCharPosition = localFirst;
+                } else if (localFirst < firstCommentCharPosition) {
+                    firstCommentCharPosition = localFirst;
+                }
+                continue;
+            }
+            if (trimmed.length() > 0) {
                 int localFirst = PySelection.getFirstCharPosition(string);
                 if (firstCharPosition == -1) {
                     firstCharPosition = localFirst;
@@ -67,7 +79,12 @@ public class AssistSurroundWith extends AbstractTemplateCodeCompletion implement
             }
         }
         if (firstCharPosition == -1) {
-            return l;
+            if (firstCommentCharPosition != -1) {
+                firstCharPosition = firstCommentCharPosition;
+            } else {
+                // Haven't found any non-empty line.
+                return l;
+            }
         }
 
         //delimiter to use
@@ -130,10 +147,10 @@ public class AssistSurroundWith extends AbstractTemplateCodeCompletion implement
 
     /**
      * Template completions available for surround with... They %s will be replaced later for the actual code/indentation.
-     * 
+     *
      * Could be refactored so that we don't have to put the actual indent here (creating a subclass of PyDocumentTemplateContext)
      * Also, if that refactoring was done, we could give an interface for the user to configure those templates better.
-     * 
+     *
      * Another nice thing may be analyzing the current context for local variables so that
      * for item in collection could have 'good' choices for the collection variable based on the local variables.
      */
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/hover/PyTextHover.java b/plugins/org.python.pydev/src/org/python/pydev/editor/hover/PyTextHover.java
index 34fbfaa..b153135 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/hover/PyTextHover.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/hover/PyTextHover.java
@@ -90,11 +90,6 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
     private final boolean pythonCommentOrMultiline;
 
     /**
-     * A buffer we can fill with the information to be returned.
-     */
-    private final FastStringBuffer buf = new FastStringBuffer();
-
-    /**
      * The text selected
      */
     private ITextSelection textSelection;
@@ -117,12 +112,9 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
         this.pythonCommentOrMultiline = pythonCommentOrMultiline;
     }
 
-    /**
-     * Synchronized because of buffer access.
-     */
     @SuppressWarnings("unchecked")
-    public synchronized String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
-        buf.clear();
+    public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+        FastStringBuffer buf = new FastStringBuffer();
 
         if (!pythonCommentOrMultiline) {
             if (textViewer instanceof PySourceViewer) {
@@ -145,9 +137,9 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
                     }
                 }
 
-                getMarkerHover(hoverRegion, s);
+                getMarkerHover(hoverRegion, s, buf);
                 if (PyHoverPreferencesPage.getShowDocstringOnHover()) {
-                    getDocstringHover(hoverRegion, s, ps);
+                    getDocstringHover(hoverRegion, s, ps, buf);
                 }
 
             }
@@ -158,7 +150,7 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
     /**
      * Fills the buffer with the text for markers we're hovering over.
      */
-    private void getMarkerHover(IRegion hoverRegion, PySourceViewer s) {
+    private void getMarkerHover(IRegion hoverRegion, PySourceViewer s, FastStringBuffer buf) {
         for (Iterator<MarkerAnnotationAndPosition> it = s.getMarkerIterator(); it.hasNext();) {
             MarkerAnnotationAndPosition marker = it.next();
             try {
@@ -187,7 +179,7 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
      * Fills the buffer with the text for docstrings of the selected element.
      */
     @SuppressWarnings("unchecked")
-    private void getDocstringHover(IRegion hoverRegion, PySourceViewer s, PySelection ps) {
+    private void getDocstringHover(IRegion hoverRegion, PySourceViewer s, PySelection ps, FastStringBuffer buf) {
         //Now, aside from the marker, let's check if there's some definition we should show the user about.
         CompletionCache completionCache = new CompletionCache();
         ArrayList<IDefinition> selected = new ArrayList<IDefinition>();
@@ -309,7 +301,7 @@ public class PyTextHover implements ITextHover, ITextHoverExtension {
             if (edit != null) {
                 indentPrefs = edit.getIndentPrefs();
             } else {
-                indentPrefs = DefaultIndentPrefs.get();
+                indentPrefs = DefaultIndentPrefs.get(null);
             }
 
             Str docStr = NodeUtils.getNodeDocStringNode(astToPrint);
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyScopedPreferences.java b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyScopedPreferences.java
new file mode 100644
index 0000000..cf70cab
--- /dev/null
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyScopedPreferences.java
@@ -0,0 +1,39 @@
+package org.python.pydev.editor.preferences;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.python.pydev.plugin.PydevPlugin;
+import org.python.pydev.plugin.preferences.PydevPrefs;
+import org.python.pydev.shared_core.preferences.IScopedPreferences;
+import org.python.pydev.shared_core.preferences.ScopedPreferences;
+
+public class PyScopedPreferences {
+
+    public static boolean getBoolean(String setting, IAdaptable projectAdaptable) {
+        return get().getBoolean(PydevPrefs.getPreferences(), setting, projectAdaptable);
+    }
+
+    public static String getString(String setting, IAdaptable projectAdaptable) {
+        return get().getString(PydevPrefs.getPreferences(), setting, projectAdaptable);
+    }
+
+    public static int getInt(String setting, IAdaptable projectAdaptable, int minVal) {
+        int ret = get().getInt(PydevPrefs.getPreferences(), setting, projectAdaptable);
+        if (ret < minVal) {
+            return minVal;
+        }
+        return ret;
+    }
+
+    public static String getString(String setting, IAdaptable projectAdaptable, String defaultReturn) {
+        String ret = getString(setting, projectAdaptable);
+        if (ret.isEmpty()) {
+            return defaultReturn;
+        }
+        return ret;
+    }
+
+    public static IScopedPreferences get() {
+        return ScopedPreferences.get(PydevPlugin.DEFAULT_PYDEV_SCOPE);
+    }
+
+}
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyTabPreferencesPage.java b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyTabPreferencesPage.java
new file mode 100644
index 0000000..2de3732
--- /dev/null
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PyTabPreferencesPage.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015 by Brainwy Software LTDA. All Rights Reserved.
+ * Licensed under the terms of the Eclipse Public License (EPL).
+ * Please see the license.txt included with this distribution for details.
+ * Any modifications to this file must keep this entire header intact.
+ */
+package org.python.pydev.editor.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.python.pydev.plugin.PydevPlugin;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
+
+public class PyTabPreferencesPage extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+    public PyTabPreferencesPage() {
+        super(GRID);
+        final IPreferenceStore store = PydevPlugin.getDefault().getPreferenceStore();
+        setDescription("Tab preferences for PyDev.\n\nNote: PyDev ignores the 'Insert spaces for tabs' in the general settings.\n\n");
+        setPreferenceStore(store);
+    }
+
+    @Override
+    public void init(IWorkbench workbench) {
+
+    }
+
+    @Override
+    protected void createFieldEditors() {
+        final Composite p = getFieldEditorParent();
+
+        addField(new IntegerFieldEditor(PydevEditorPrefs.TAB_WIDTH, "Tab length:", p));
+        addField(new BooleanFieldEditor(PydevEditorPrefs.SUBSTITUTE_TABS, "Replace tabs with spaces when typing?", p));
+        addField(new BooleanFieldEditor(PydevEditorPrefs.GUESS_TAB_SUBSTITUTION,
+                "Assume tab spacing when files contain tabs?", p));
+
+        addField(new ScopedPreferencesFieldEditor(p, PydevPlugin.DEFAULT_PYDEV_SCOPE, this));
+    }
+
+}
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevEditorPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevEditorPrefs.java
index 4690b6d..c5441a7 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevEditorPrefs.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevEditorPrefs.java
@@ -1,14 +1,14 @@
 /*******************************************************************************
  * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials 
+ * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/cpl-v10.html
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Scott Schlesier - Adapted for use in pydev
- *     Fabio Zadrozny 
+ *     Fabio Zadrozny
  *******************************************************************************/
 
 package org.python.pydev.editor.preferences;
@@ -68,7 +68,7 @@ public class PydevEditorPrefs extends AbstractPydevPrefs {
     private IPropertyChangeListener updateLabelExampleOnPrefsChanges;
 
     public PydevEditorPrefs() {
-        setDescription("PyDev editor appearance settings:\nNote: Pydev ignores the 'Insert spaces for tabs' in the general settings.");
+        setDescription("PyDev editor appearance settings:\n\nNote: PyDev ignores the 'Insert spaces for tabs' in the general settings.");
         setPreferenceStore(PydevPlugin.getDefault().getPreferenceStore());
 
         fOverlayStore = createOverlayStore();
@@ -82,17 +82,26 @@ public class PydevEditorPrefs extends AbstractPydevPrefs {
         layout.numColumns = 1;
         appearanceComposite.setLayout(layout);
 
-        addTextField(appearanceComposite, "Tab length:", TAB_WIDTH, 3, 0, true);
+        LinkFieldEditor tabsFieldEditor = new LinkFieldEditor("UNUSED",
+                "Tab settings for PyDev may be configured at: " + "<a>Tabs</a>", appearanceComposite,
+                new SelectionListener() {
 
-        addCheckBox(appearanceComposite, "Replace tabs with spaces when typing?", SUBSTITUTE_TABS, 0);
+                    public void widgetSelected(SelectionEvent e) {
+                        String id = "org.python.pydev.editor.preferences.PyTabPreferencesPage";
+                        IWorkbenchPreferenceContainer workbenchPreferenceContainer = ((IWorkbenchPreferenceContainer) getContainer());
+                        workbenchPreferenceContainer.openPage(id, null);
+                    }
 
-        addCheckBox(appearanceComposite, "Assume tab spacing when files contain tabs?", GUESS_TAB_SUBSTITUTION, 0);
+                    public void widgetDefaultSelected(SelectionEvent e) {
+                    }
+                });
+        tabsFieldEditor.getLinkControl(appearanceComposite);
 
         createColorOptions(appearanceComposite);
 
         formatAndStyleRangeHelper = new StyledTextForShowingCodeFactory();
         labelExample = formatAndStyleRangeHelper.createStyledTextForCodePresentation(appearanceComposite);
-        updateLabelExample(PyFormatStd.getFormat(), PydevPrefs.getChainedPrefStore());
+        updateLabelExample(PyFormatStd.getFormat(null), PydevPrefs.getChainedPrefStore());
 
         LinkFieldEditor colorsAndFontsLinkFieldEditor = new LinkFieldEditor("UNUSED",
                 "Other settings:\n\n<a>Text Editors</a>: print margin, line numbers ...", appearanceComposite,
@@ -294,7 +303,7 @@ public class PydevEditorPrefs extends AbstractPydevPrefs {
         localStore.setValue(OPERATORS_STYLE, fOverlayStore.getInt(OPERATORS_STYLE));
         localStore.setValue(DOCSTRING_MARKUP_STYLE, fOverlayStore.getInt(DOCSTRING_MARKUP_STYLE));
 
-        this.updateLabelExample(PyFormatStd.getFormat(), localStore);
+        this.updateLabelExample(PyFormatStd.getFormat(null), localStore);
     }
 
     @Override
@@ -325,7 +334,7 @@ public class PydevEditorPrefs extends AbstractPydevPrefs {
                 RunInUiThread.async(new Runnable() {
 
                     public void run() {
-                        updateLabelExample(PyFormatStd.getFormat(), PydevPrefs.getChainedPrefStore());
+                        updateLabelExample(PyFormatStd.getFormat(null), PydevPrefs.getChainedPrefStore());
                     }
                 });
             }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevTypingPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevTypingPrefs.java
index 79a97e5..1a0992c 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevTypingPrefs.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/preferences/PydevTypingPrefs.java
@@ -10,17 +10,23 @@
 package org.python.pydev.editor.preferences;
 
 import org.eclipse.jface.bindings.keys.KeySequence;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
 import org.python.pydev.core.docutils.WrapAndCaseUtils;
 import org.python.pydev.plugin.PydevPlugin;
-import org.python.pydev.plugin.preferences.AbstractPydevPrefs;
 import org.python.pydev.shared_core.string.StringUtils;
 import org.python.pydev.shared_ui.bindings.KeyBindingHelper;
+import org.python.pydev.shared_ui.field_editors.BooleanFieldEditorCustom;
+import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
 
 /**
  * This class is the class that resulted of the separation of the PydevPrefs because
@@ -28,87 +34,163 @@ import org.python.pydev.shared_ui.bindings.KeyBindingHelper;
  * 
  * @author Fabio
  */
-public class PydevTypingPrefs extends AbstractPydevPrefs {
+public class PydevTypingPrefs extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+    public static final String AUTO_PAR = "AUTO_PAR";
+    public static final boolean DEFAULT_AUTO_PAR = true;
+
+    public static final String AUTO_LINK = "AUTO_LINK";
+    public static final boolean DEFAULT_AUTO_LINK = false;
+
+    public static final String AUTO_INDENT_TO_PAR_LEVEL = "AUTO_INDENT_TO_PAR_LEVEL";
+    public static final boolean DEFAULT_AUTO_INDENT_TO_PAR_LEVEL = true;
+
+    public static final String AUTO_INDENT_AFTER_PAR_WIDTH = "AUTO_INDENT_AFTER_PAR_WIDTH";
+    public static final int DEFAULT_AUTO_INDENT_AFTER_PAR_WIDTH = 1;
+
+    public static final String AUTO_DEDENT_ELSE = "AUTO_DEDENT_ELSE";
+    public static final boolean DEFAULT_AUTO_DEDENT_ELSE = true;
+
+    public static final String SMART_INDENT_PAR = "SMART_INDENT_PAR";
+    public static final boolean DEFAULT_SMART_INDENT_PAR = true;
+
+    public static final String SMART_LINE_MOVE = "SMART_LINE_MOVE";
+    //Disabled by default (doesn't seem as useful as I though because Python does not have the end
+    //braces and Java does (so, there are a number of cases where the indentation has to be hand-fixed
+    //anyways)
+    public static final boolean DEFAULT_SMART_LINE_MOVE = false;
+
+    /**
+     * fields for automatically replacing a colon
+     * @see  
+     */
+    public static final String AUTO_COLON = "AUTO_COLON";
+    public static final boolean DEFAULT_AUTO_COLON = true;
+
+    /**
+     * fields for automatically skipping braces
+     * @see  org.python.pydev.editor.autoedit.PyAutoIndentStrategy
+     */
+    public static final String AUTO_BRACES = "AUTO_BRACES";
+    public static final boolean DEFAULT_AUTO_BRACES = true;
+
+    /**
+     * Used if the 'import' should be written automatically in an from xxx import yyy
+     */
+    public static final String AUTO_WRITE_IMPORT_STR = "AUTO_WRITE_IMPORT_STR";
+    public static final boolean DEFAULT_AUTO_WRITE_IMPORT_STR = true;
+
+    public static final String AUTO_LITERALS = "AUTO_LITERALS";
+    public static final boolean DEFAULT_AUTO_LITERALS = true;
+
+    public static final String AUTO_ADD_SELF = "AUTO_ADD_SELF";
+    public static final boolean DEFAULT_AUTO_ADD_SELF = true;
+
+    public static final int TOOLTIP_WIDTH = 80;
 
     public PydevTypingPrefs() {
+        super(GRID);
         setDescription("Editor");
         setPreferenceStore(PydevPlugin.getDefault().getPreferenceStore());
-        this.fOverlayStore = createOverlayStore();
     }
 
     @Override
-    protected Control createAppearancePage(Composite parent) {
-        Composite appearanceComposite = new Composite(parent, SWT.NONE);
-        GridLayout layout = new GridLayout();
-        layout.numColumns = 2;
-        appearanceComposite.setLayout(layout);
+    protected void createFieldEditors() {
+        final Composite initialParent = getFieldEditorParent();
+        final Composite p = initialParent;
 
-        // simply a holder for the current reference for a Button, so you can input a tooltip
-        Button b;
+        String preference = AUTO_LINK;
+        String text = "Enable link on automatic parenthesis or literals closing?";
+        String tooltip = "Enabling this option will enable the linking mode after a parenthesis or literal is auto-closed.";
 
-        b = addCheckBox(appearanceComposite, "Enable link on automatic parenthesis or literals closing", AUTO_LINK, 0);
-        b.setToolTipText(WrapAndCaseUtils.wrap(
-                "Enabling this option will enable the linking mode after a parenthesis or literal is auto-closed.",
-                TOOLTIP_WIDTH));
+        addBooleanField(p, preference, text, tooltip);
 
         //auto par
-        b = addCheckBox(appearanceComposite, "Automatic parentheses insertion", AUTO_PAR, 0);
-        b.setToolTipText(WrapAndCaseUtils.wrap("Enabling this option will enable automatic insertion of parentheses.  "
-                + "Specifically, whenever you hit a brace such as '(', '{', or '[', its related peer will be inserted "
-                + "and your cursor will be placed between the two braces.", TOOLTIP_WIDTH));
-
-        //indent
-        b = addCheckBox(appearanceComposite, "After '(' indent to its level (indents by tabs if unchecked)",
-                AUTO_INDENT_TO_PAR_LEVEL, 0);
-        Control c = addTextField(appearanceComposite, "Number of indentation levels to add:",
-                AUTO_INDENT_AFTER_PAR_WIDTH, 3, 20, true);
-        createInverseDependency(b, AUTO_INDENT_AFTER_PAR_WIDTH, c);
+        addBooleanField(
+                p,
+                AUTO_PAR,
+                "Automatic parentheses insertion",
+                "Enabling this option will enable automatic insertion of parentheses.  "
+                        + "Specifically, whenever you hit a brace such as '(', '{', or '[', its related peer will be inserted "
+                        + "and your cursor will be placed between the two braces.");
+
+        // indent
+        final BooleanFieldEditorCustom autoIndentToParLevel = addBooleanField(p, AUTO_INDENT_TO_PAR_LEVEL,
+                "After '(' indent to its level (indents by tabs if unchecked)", "");
+
+        final IntegerFieldEditor intField = new IntegerFieldEditor(AUTO_INDENT_AFTER_PAR_WIDTH,
+                "    Number of indentation levels to add:", p, 1);
+        addField(intField);
+        final Button checkBox = autoIndentToParLevel.getCheckBox(p);
+        checkBox.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                intField.setEnabled(!autoIndentToParLevel.getBooleanValue(), p);
+            }
+        });
+        intField.setEnabled(!getPreferenceStore().getBoolean(AUTO_INDENT_TO_PAR_LEVEL), p);
 
         //auto dedent 'else:'
-        b = addCheckBox(appearanceComposite, "Automatic dedent of 'else:' and 'elif:'", AUTO_DEDENT_ELSE, 0);
+        addBooleanField(p, AUTO_DEDENT_ELSE, "Automatic dedent of 'else:' and 'elif:'", "");
 
         //auto braces
-        b = addCheckBox(appearanceComposite, "Automatically skip matching braces when typing", AUTO_BRACES, 0);
-        b.setToolTipText(WrapAndCaseUtils
-                .wrap("Enabling this option will enable automatically skipping matching braces "
+        addBooleanField(
+                p,
+                AUTO_BRACES,
+                "Automatically skip matching braces when typing",
+                "Enabling this option will enable automatically skipping matching braces "
                         + "if you try to insert them.  For example, if you have the following code:\n\n"
                         + "def function(self):\n\n"
                         + "...with your cursor before the end parenthesis (after the 'f' in \"self\"), typing a ')' will "
-                        + "simply move the cursor to the position after the ')' without inserting a new one.",
-                        TOOLTIP_WIDTH));
+                        + "simply move the cursor to the position after the ')' without inserting a new one.");
 
         //smart indent
-        b = addCheckBox(appearanceComposite, "Use smart-indent?", SMART_INDENT_PAR, 0);
+        addBooleanField(p, SMART_INDENT_PAR, "Use smart-indent?", "");
 
         //auto colon
-        b = addCheckBox(appearanceComposite, "Automatic colon detection", AUTO_COLON, 0);
-        b.setToolTipText(WrapAndCaseUtils
-                .wrap("Enabling this feature will enable the editor to detect if you are trying "
+        addBooleanField(
+                p,
+                AUTO_COLON,
+                "Automatic colon detection",
+                "Enabling this feature will enable the editor to detect if you are trying "
                         + "to enter a colon which is already there.  Instead of inserting another colon, the editor will "
-                        + "simply move your cursor to the next position after the colon.", TOOLTIP_WIDTH));
+                        + "simply move your cursor to the next position after the colon.");
 
         //auto literals
-        b = addCheckBox(appearanceComposite, "Automatic literal closing", AUTO_LITERALS, 0);
-        b.setToolTipText(WrapAndCaseUtils.wrap("Automatically close literals "
-                + "(when ' or \" is added, another one is added to close it).", TOOLTIP_WIDTH));
+        addBooleanField(p, AUTO_LITERALS, "Automatic literal closing", "Automatically close literals "
+                + "(when ' or \" is added, another one is added to close it).");
 
         //auto import str
-        b = addCheckBox(appearanceComposite, "Automatic insertion of the 'import' string on 'from xxx' ",
-                AUTO_WRITE_IMPORT_STR, 0);
-        b.setToolTipText(WrapAndCaseUtils.wrap("Enabling this will allow the editor to automatically write the"
-                + "'import' string when you write a space after you've written 'from xxx '.", TOOLTIP_WIDTH));
+        addBooleanField(p, AUTO_WRITE_IMPORT_STR, "Automatic insertion of the 'import' string on 'from xxx' ",
+                "Enabling this will allow the editor to automatically write the"
+                        + "'import' string when you write a space after you've written 'from xxx '.");
 
-        addCheckBox(appearanceComposite, "Add 'self' automatically when declaring methods?", AUTO_ADD_SELF, 0);
+        addBooleanField(p, AUTO_ADD_SELF, "Add 'self' automatically when declaring methods?", "");
 
         KeySequence down = KeyBindingHelper.getCommandKeyBinding(ITextEditorActionDefinitionIds.MOVE_LINES_DOWN);
         KeySequence up = KeyBindingHelper.getCommandKeyBinding(ITextEditorActionDefinitionIds.MOVE_LINES_UP);
         String downKey = down != null ? down.format() : "Alt+Down"; //set the default if not there
         String upKey = up != null ? up.format() : "Alt+Up"; //set the default if not there
-        addCheckBox(appearanceComposite,
-                StringUtils.format("Smart move for line up  (%s) and line down (%s)?.", upKey, downKey),
-                SMART_LINE_MOVE, 0);
+        addBooleanField(p, SMART_LINE_MOVE,
+                StringUtils.format("Smart move for line up  (%s) and line down (%s)?.", upKey, downKey), "");
+
+        addField(new LabelFieldEditor("__UNUSED__", "Note: smart move line up/down change applied on editor restart.",
+                p));
+
+        addField(new ScopedPreferencesFieldEditor(p, PydevPlugin.DEFAULT_PYDEV_SCOPE, this));
+
+    }
+
+    private BooleanFieldEditorCustom addBooleanField(Composite p, String preference, String text, String tooltip) {
+        BooleanFieldEditorCustom field = new BooleanFieldEditorCustom(preference, text,
+                BooleanFieldEditor.DEFAULT, p);
+        addField(field);
+        field.setTooltip(p, WrapAndCaseUtils.wrap(tooltip, TOOLTIP_WIDTH));
+        return field;
+    }
+
+    @Override
+    public void init(IWorkbench workbench) {
 
-        addLabel(appearanceComposite, "Note: smart move line up/down change applied on editor restart.", 20);
-        return appearanceComposite;
     }
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/IPyRefactoringRequest.java b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/IPyRefactoringRequest.java
index ba536fc..93a9d2b 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/IPyRefactoringRequest.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/IPyRefactoringRequest.java
@@ -2,6 +2,7 @@ package org.python.pydev.editor.refactoring;
 
 import java.util.List;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.IProgressMonitor;
 
 public interface IPyRefactoringRequest {
@@ -20,9 +21,17 @@ public interface IPyRefactoringRequest {
 
     String getInputName();
 
+    String getInitialName();
+
     boolean isModuleRenameRefactoringRequest();
 
-    String getInitialName();
+    // The ones below are available when isModuleRenameRefactoringRequest() is true.
+
+    IFile getIFileResource();
 
     void setUpdateReferences(boolean selection);
+
+    void setSimpleResourceRename(boolean resourceRenameBool);
+
+    boolean getSimpleResourceRename();
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/ModuleRenameRefactoringRequest.java b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/ModuleRenameRefactoringRequest.java
index 5b13f31..2f1fd97 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/ModuleRenameRefactoringRequest.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/ModuleRenameRefactoringRequest.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2013 by Brainwy Software Ltda, Inc. All Rights Reserved.
+ * Copyright (c) 2013-2015 by Brainwy Software Ltda, Inc. All Rights Reserved.
  * Licensed under the terms of the Eclipse Public License (EPL).
  * Please see the license.txt included with this distribution for details.
  * Any modifications to this file must keep this entire header intact.
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/PyRefactoringRequest.java b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/PyRefactoringRequest.java
index eb293d5..86da802 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/PyRefactoringRequest.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/PyRefactoringRequest.java
@@ -4,11 +4,13 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Stack;
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.python.pydev.core.log.Log;
 
 /**
- * This is a refactoring request which may actually be composed of multiple requests (i.e.: for when we want to 
+ * This is a refactoring request which may actually be composed of multiple requests (i.e.: for when we want to
  * move several resources at once).
  */
 public class PyRefactoringRequest implements IPyRefactoringRequest {
@@ -47,6 +49,55 @@ public class PyRefactoringRequest implements IPyRefactoringRequest {
         }
     }
 
+    @Override
+    public IFile getIFileResource() {
+        IFile f = null;
+        for (RefactoringRequest r : requests) {
+            if (f == null) {
+                f = r.getIFileResource();
+            } else {
+                IFile f2 = r.getIFileResource();
+                if (!f.equals(f2)) {
+                    // This is inconsistent
+                    return null;
+                }
+            }
+        }
+        return f;
+    }
+
+    @Override
+    public void setSimpleResourceRename(boolean simpleResourceRename) {
+        for (RefactoringRequest r : requests) {
+            r.setSimpleResourceRename(simpleResourceRename);
+        }
+    }
+
+    @Override
+    public boolean getSimpleResourceRename() {
+        try {
+            Boolean b = null;
+            for (RefactoringRequest r : requests) {
+                if (b == null) {
+                    b = r.getSimpleResourceRename();
+                } else {
+                    if (b != r.getSimpleResourceRename()) {
+                        // If there's a conflict, we can't do a resource rename
+                        // (this makes no sense).
+                        return false;
+                    }
+                }
+            }
+            if (b == null) {
+                return false;
+            }
+            return b;
+        } catch (Exception e) {
+            Log.log(e);
+            return false;
+        }
+    }
+
     private final Stack<IProgressMonitor> monitors = new Stack<IProgressMonitor>();
 
     @Override
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/RefactoringRequest.java b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/RefactoringRequest.java
index 18ccd7b..abb18bd 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/RefactoringRequest.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/refactoring/RefactoringRequest.java
@@ -34,7 +34,7 @@ import org.python.pydev.shared_core.structure.Tuple;
 /**
  * This class encapsulates all the info needed in order to do a refactoring
  * As we'd have a getter/setter without any side-effects, let's leave them all public...
- * 
+ *
  * It is a Decoratable Object, so that clients can add additional information to this
  * object at runtime.
  */
@@ -45,11 +45,26 @@ public class RefactoringRequest extends DecoratableObject {
     public static final String FIND_DEFINITION_IN_ADDITIONAL_INFO = "findDefinitionInAdditionalInfo";
 
     /**
+     * Flag used when renaming modules. If set and True, we won't do a refactoring rename and will
+     * only really change the resource name.
+     */
+    public static final String SIMPLE_RESOURCE_RENAME = "simpleResourceRename";
+
+    /**
      * The file associated with the editor where the refactoring is being requested
      */
     public final File file;
 
     /**
+     * Only available on module renames.
+     */
+    private IFile iFileResource;
+
+    public IFile getIFileResource() {
+        return iFileResource;
+    }
+
+    /**
      * The current selection when the refactoring was requested
      */
     public PySelection ps;
@@ -57,13 +72,13 @@ public class RefactoringRequest extends DecoratableObject {
     /**
      * The progress monitor to give feedback to the user (may be checked in another thread)
      * May be null
-     * 
+     *
      * Note that this is the monitor for the initial request, but, clients may use it in othe
      */
     private final Stack<IProgressMonitor> monitors = new Stack<IProgressMonitor>();
 
     /**
-     * The nature used 
+     * The nature used
      */
     public IPythonNature nature;
 
@@ -103,14 +118,14 @@ public class RefactoringRequest extends DecoratableObject {
     /**
      * If the file is passed, we also set the document automatically
      * @param file the file correspondent to this request
-     * @throws MisconfigurationException 
+     * @throws MisconfigurationException
      */
     public RefactoringRequest(PyEdit pyEdit, PySelection ps) throws MisconfigurationException {
         this(pyEdit.getEditorFile(), ps, null, pyEdit.getPythonNature(), pyEdit);
     }
 
     /**
-     * Assigns parameters to attributes (tries to resolve the module name and create a SystemPythonNature if the 
+     * Assigns parameters to attributes (tries to resolve the module name and create a SystemPythonNature if the
      * nature is not specified)
      */
     public RefactoringRequest(File file, PySelection ps, IProgressMonitor monitor, IPythonNature nature, PyEdit pyEdit) {
@@ -136,6 +151,10 @@ public class RefactoringRequest extends DecoratableObject {
         this.pyEdit = pyEdit;
     }
 
+    public File getFile() {
+        return file;
+    }
+
     /**
      * Used to make the work communication (also checks to see if it has been cancelled)
      * @param desc Some string to be shown in the progress
@@ -284,10 +303,10 @@ public class RefactoringRequest extends DecoratableObject {
 
     /**
      * Clients using the RefactoringRequest are expected to receive it as a parameter, then:
-     * 
+     *
      * getMonitor().beginTask("my task", total)
-     * 
-     * 
+     *
+     *
      * try{
      *     //Calling another function
      *     req.pushMonitor(new SubProgressMonitor(monitor, 10));
@@ -295,7 +314,7 @@ public class RefactoringRequest extends DecoratableObject {
      * finally{
      *     req.popMonitor().done();
      * }
-     * 
+     *
      * try{
      *     //Calling another function
      *     req.pushMonitor(new SubProgressMonitor(monitor, 90));
@@ -303,15 +322,15 @@ public class RefactoringRequest extends DecoratableObject {
      * finally{
      *     req.popMonitor().done();
      * }
-     * 
-     * 
+     *
+     *
      * getMonitor().done();
-     * 
-     * 
-     * 
-     * 
-     * 
-     * @return the current progress monitor 
+     *
+     *
+     *
+     *
+     *
+     * @return the current progress monitor
      */
     public IProgressMonitor getMonitor() {
         return this.monitors.peek();
@@ -346,4 +365,17 @@ public class RefactoringRequest extends DecoratableObject {
         setAdditionalInfo(FIND_REFERENCES_ONLY_IN_LOCAL_SCOPE, !updateReferences);
     }
 
+    public void setSimpleResourceRename(boolean simpleResourceRename) {
+        setAdditionalInfo(SIMPLE_RESOURCE_RENAME, simpleResourceRename);
+    }
+
+    public boolean getSimpleResourceRename() {
+        return (boolean) getAdditionalInfo(SIMPLE_RESOURCE_RENAME, false);
+    }
+
+    public void setFileResource(IFile file2) {
+        this.iFileResource = file2;
+
+    }
+
 }
\ No newline at end of file
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevSaveActionsPrefPage.java b/plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevSaveActionsPrefPage.java
index c0886b9..0a56d64 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevSaveActionsPrefPage.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editor/saveactions/PydevSaveActionsPrefPage.java
@@ -15,8 +15,8 @@ package org.python.pydev.editor.saveactions;
 import java.net.MalformedURLException;
 import java.net.URL;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.preference.BooleanFieldEditor;
-import org.eclipse.jface.preference.FieldEditorPreferencePage;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.StringFieldEditor;
 import org.eclipse.jface.text.DefaultInformationControl.IInformationPresenter;
@@ -31,10 +31,13 @@ import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
 import org.python.pydev.core.SystemUtils;
 import org.python.pydev.core.log.Log;
+import org.python.pydev.editor.PyEdit;
+import org.python.pydev.editor.preferences.PyScopedPreferences;
 import org.python.pydev.plugin.PydevPlugin;
-import org.python.pydev.plugin.preferences.PydevPrefs;
 import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LinkFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
 import org.python.pydev.shared_ui.tooltips.presenter.AbstractTooltipInformationPresenter;
 import org.python.pydev.shared_ui.tooltips.presenter.ToolTipPresenterHandler;
 
@@ -42,11 +45,11 @@ import org.python.pydev.shared_ui.tooltips.presenter.ToolTipPresenterHandler;
  * Preference page for Pydev editor {@code Save Actions}.
  * Save actions are actions performed on file buffers whenever
  * a file resource is saved.
- * 
+ *
  * @author André Berg
  * @version 0.1
  */
-public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+public class PydevSaveActionsPrefPage extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
 
     private class PydevSaveActionsPageLinkListener implements SelectionListener {
 
@@ -78,18 +81,19 @@ public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implemen
             "name and date format below and updates it to the\n" +
             "current date.";
 
-    private final IPreferenceStore prefStore;
     private ToolTipPresenterHandler tooltipPresenter;
     private BooleanFieldEditor sortImportsOnSave;
 
     public PydevSaveActionsPrefPage() {
         super(GRID);
         final IPreferenceStore store = PydevPlugin.getDefault().getPreferenceStore();
-        prefStore = store;
         setDescription("Save actions are run whenever a file is saved.\n");
         setPreferenceStore(store);
     }
 
+    public static final String SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES = "SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES";
+    public static final boolean DEFAULT_SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES = true;
+
     public static final String FORMAT_BEFORE_SAVING = "FORMAT_BEFORE_SAVING";
     public static final boolean DEFAULT_FORMAT_BEFORE_SAVING = false;
 
@@ -120,6 +124,9 @@ public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implemen
 
         final Composite p = getFieldEditorParent();
 
+        addField(new BooleanFieldEditor(SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES,
+                "Apply save actions only to files in the workspace?", p));
+
         addField(new BooleanFieldEditor(FORMAT_BEFORE_SAVING, "Auto-format editor contents before saving?", p));
 
         addField(new LinkFieldEditor("link_formatpreferences", "Note: config in <a>code formatting preferences</a>", p,
@@ -142,11 +149,27 @@ public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implemen
                 new BooleanFieldEditor(SORT_IMPORTS_ON_SAVE, "Sort imports on save?", p);
         addField(sortImportsOnSave);
 
+        addField(new LinkFieldEditor("link_importpreferences",
+                "Note: config in <a>code style: imports preferences</a>", p,
+                new SelectionListener() {
+
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        String id = "org.python.pydev.ui.importsconf.ImportsPreferencesPage";
+                        IWorkbenchPreferenceContainer workbenchPreferenceContainer = ((IWorkbenchPreferenceContainer) getContainer());
+                        workbenchPreferenceContainer.openPage(id, null);
+                    }
+
+                    @Override
+                    public void widgetDefaultSelected(SelectionEvent e) {
+                    }
+                }));
+
         tooltipPresenter = new ToolTipPresenterHandler(p.getShell(), presenter,
                 "Tip: Click link to open SimpleDateFormat Java docs online.");
 
         // Enable date field action editor (boolean)
-
+        IPreferenceStore prefStore = getPreferenceStore();
         final String fieldName = prefStore.getString(DATE_FIELD_NAME);
         final String enableDateFieldActionEditorTooltip =
                 String.format(enableDateFieldActionEditorTooltipFormat, fieldName);
@@ -203,37 +226,35 @@ public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implemen
         addField(new LabelFieldEditor("__dummy__",
                 "I.e.: __updated__=\"2010-01-01\" will be synched on save.", p));
 
+        addField(new ScopedPreferencesFieldEditor(p, PydevPlugin.DEFAULT_PYDEV_SCOPE, this));
+
     }
 
     public void init(IWorkbench workbench) {
     }
 
-    public static boolean getDateFieldActionEnabled() {
-        return PydevPrefs.getPreferences().getBoolean(ENABLE_DATE_FIELD_ACTION);
+    public static boolean getDateFieldActionEnabled(PyEdit pyEdit) {
+        return PyScopedPreferences.getBoolean(ENABLE_DATE_FIELD_ACTION, pyEdit);
     }
 
-    public static boolean getSortImportsOnSave() {
-        return PydevPrefs.getPreferences().getBoolean(SORT_IMPORTS_ON_SAVE);
+    public static boolean getSortImportsOnSave(PyEdit pyEdit) {
+        return PyScopedPreferences.getBoolean(SORT_IMPORTS_ON_SAVE, pyEdit);
     }
 
-    public static boolean getFormatBeforeSaving() {
-        return PydevPrefs.getPreferences().getBoolean(FORMAT_BEFORE_SAVING);
+    public static boolean getFormatBeforeSaving(PyEdit pyEdit) {
+        return PyScopedPreferences.getBoolean(FORMAT_BEFORE_SAVING, pyEdit);
     }
 
-    public static String getDateFieldName() {
-        final String fieldName = PydevPrefs.getPreferences().getString(DATE_FIELD_NAME);
-        if (fieldName.isEmpty()) {
-            return DEFAULT_DATE_FIELD_NAME;
-        }
-        return fieldName;
+    public static String getDateFieldName(PyEdit pyEdit) {
+        return PyScopedPreferences.getString(DATE_FIELD_NAME, pyEdit, DEFAULT_DATE_FIELD_NAME);
     }
 
-    public static String getDateFieldFormat() {
-        final String fieldName = PydevPrefs.getPreferences().getString(DATE_FIELD_FORMAT);
-        if (fieldName.isEmpty()) {
-            return DEFAULT_DATE_FIELD_FORMAT;
-        }
-        return fieldName;
+    public static String getDateFieldFormat(PyEdit pyEdit) {
+        return PyScopedPreferences.getString(DATE_FIELD_FORMAT, pyEdit, DEFAULT_DATE_FIELD_FORMAT);
+    }
+
+    public static boolean getAutoformatOnlyWorkspaceFiles(IAdaptable projectAdaptable) {
+        return PyScopedPreferences.getBoolean(SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES, projectAdaptable);
     }
 
     @Override
@@ -274,4 +295,5 @@ public class PydevSaveActionsPrefPage extends FieldEditorPreferencePage implemen
             }
         }
     }
+
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/editorinput/PySourceLocatorBase.java b/plugins/org.python.pydev/src/org/python/pydev/editorinput/PySourceLocatorBase.java
index 8a1505d..2ec410a 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/editorinput/PySourceLocatorBase.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/editorinput/PySourceLocatorBase.java
@@ -25,11 +25,7 @@ import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.FileDialog;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorReference;
 import org.eclipse.ui.IPathEditorInput;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.dialogs.ElementListSelectionDialog;
 import org.eclipse.ui.part.FileEditorInput;
@@ -40,21 +36,118 @@ import org.python.pydev.editor.PyEdit;
 import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
 import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.plugin.nature.PythonNature;
+import org.python.pydev.shared_core.callbacks.ICallback;
 import org.python.pydev.shared_core.io.FileUtils;
 import org.python.pydev.shared_core.locator.GetContainers;
 import org.python.pydev.shared_core.locator.GetFiles;
 import org.python.pydev.shared_core.string.StringUtils;
-import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.ui.filetypes.FileTypesPreferencesPage;
 
 /**
- * Refactored from the PydevPlugin: helpers to find some IFile / IEditorInput 
- * from a Path (or java.io.File) 
- * 
+ * Refactored from the PydevPlugin: helpers to find some IFile / IEditorInput
+ * from a Path (or java.io.File)
+ *
  * @author fabioz
  */
 public class PySourceLocatorBase {
 
+    /**
+     * Helper class.
+     */
+    private abstract static class FindFromExistingEditors {
+        private final Object matchName;
+
+        protected FindFromExistingEditors(Object matchName) {
+            this.matchName = matchName;
+        }
+
+        public IEditorInput findFromOpenedPyEdits() {
+            Object ret = PyEdit.iterOpenEditorsUntilFirstReturn(new ICallback<Object, PyEdit>() {
+
+                @Override
+                public Object call(PyEdit pyEdit) {
+                    IEditorInput editorInput = pyEdit.getEditorInput();
+                    if (editorInput instanceof IPathEditorInput) {
+                        IPathEditorInput pathEditorInput = (IPathEditorInput) editorInput;
+                        IPath localPath = pathEditorInput.getPath();
+                        if (localPath != null) {
+                            if (matchesPath(matchName, editorInput, localPath)) {
+                                return editorInput;
+                            }
+                        }
+                    } else {
+                        File editorFile = pyEdit.getEditorFile();
+                        if (editorFile != null) {
+                            if (matchesFile(matchName, editorInput, editorFile)) {
+                                return editorInput;
+                            }
+                        }
+                    }
+                    return null;
+                }
+            });
+            return (IEditorInput) ret;
+        }
+
+        protected abstract boolean matchesFile(final Object match, IEditorInput editorInput, File editorFile);
+
+        protected abstract boolean matchesPath(final Object match, IEditorInput editorInput, IPath localPath);
+
+    }
+
+    private static class FindFromExistingEditorsName extends PySourceLocatorBase.FindFromExistingEditors {
+        protected FindFromExistingEditorsName(String matchName) {
+            super(matchName);
+        }
+
+        @Override
+        protected boolean matchesFile(final Object match, IEditorInput editorInput,
+                File editorFile) {
+            String matchName = (String) match;
+            if (editorFile.getName().equals(matchName)) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        protected boolean matchesPath(final Object match, IEditorInput editorInput, IPath localPath) {
+            String matchName = (String) match;
+            String considerName = localPath.segment(localPath.segmentCount() - 1);
+            if (matchName.equals(considerName)) {
+                return true;
+            }
+            return false;
+        }
+
+    }
+
+    private static class FindFromExistingEditorsFile extends PySourceLocatorBase.FindFromExistingEditors {
+        protected FindFromExistingEditorsFile(File matchFile) {
+            super(matchFile);
+        }
+
+        @Override
+        protected boolean matchesFile(final Object match, IEditorInput editorInput,
+                File editorFile) {
+            File matchFile = (File) match;
+            if (editorFile.equals(matchFile)) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        protected boolean matchesPath(final Object match, IEditorInput editorInput, IPath localPath) {
+            File matchFile = (File) match;
+            if (Path.fromOSString(FileUtils.getFileAbsolutePath(matchFile)).equals(localPath)) {
+                return true;
+            }
+            return false;
+        }
+
+    }
+
     private final static GetFiles getFiles = new GetFiles() {
 
         @Override
@@ -124,10 +217,10 @@ public class PySourceLocatorBase {
      * considering:
      * - The workspace files
      * - The open editors
-     * 
+     *
      * and if all fails, it'll still ask the user which path should be used.
-     * 
-     * 
+     *
+     *
      * @param path
      * @return
      */
@@ -183,13 +276,13 @@ public class PySourceLocatorBase {
 
     /**
      * Creates the editor input from a given path.
-     * 
+     *
      * @param path the path for the editor input we're looking
      * @param askIfDoesNotExist if true, it'll try to ask the user/check existing editors and look
      * in the workspace for matches given the name
      * @param project if provided, and if a matching file is found in this project, that file will be
      * opened before asking the user to select from a list of all matches
-     * 
+     *
      * @return the editor input found or none if None was available for the given path
      */
     public IEditorInput createEditorInput(IPath path, boolean askIfDoesNotExist, IPyStackFrame pyStackFrame,
@@ -197,6 +290,12 @@ public class PySourceLocatorBase {
         int onSourceNotFound = PySourceLocatorPrefs.getOnSourceNotFound();
         IEditorInput edInput = null;
 
+        File systemFile = path.toFile();
+        IEditorInput input = getEditorInputFromExistingEditors(systemFile);
+        if (input != null) {
+            return input;
+        }
+
         String pathTranslation = PySourceLocatorPrefs.getPathTranslation(path);
         if (pathTranslation != null) {
             if (!pathTranslation.equals(PySourceLocatorPrefs.DONTASK)) {
@@ -216,7 +315,6 @@ public class PySourceLocatorBase {
 
         //getFileForLocation() will search all projects starting with the one we pass and references,
         //so, if not found there, it is probably an external file
-        File systemFile = path.toFile();
         if (systemFile.exists()) {
             edInput = PydevFileEditorInput.create(systemFile, true);
         }
@@ -225,7 +323,7 @@ public class PySourceLocatorBase {
             //here we can do one more thing: if the file matches some opened editor, let's use it...
             //(this is done because when debugging, we don't want to be asked over and over
             //for the same file)
-            IEditorInput input = getEditorInputFromExistingEditors(systemFile.getName());
+            input = getEditorInputFromExistingEditors(systemFile.getName());
             if (input != null) {
                 return input;
             }
@@ -298,69 +396,19 @@ public class PySourceLocatorBase {
     }
 
     /**
+     * @param matchFile the file to match in the editor
+     * @return an editor input from an existing editor available
+     */
+    private IEditorInput getEditorInputFromExistingEditors(final File matchFile) {
+        return new FindFromExistingEditorsFile(matchFile).findFromOpenedPyEdits();
+    }
+
+    /**
      * @param matchName the name to match in the editor
      * @return an editor input from an existing editor available
      */
     private IEditorInput getEditorInputFromExistingEditors(final String matchName) {
-        final Tuple<IWorkbenchWindow, IEditorInput> workbenchAndReturn = new Tuple<IWorkbenchWindow, IEditorInput>(
-                PlatformUI.getWorkbench().getActiveWorkbenchWindow(), null);
-
-        Runnable r = new Runnable() {
-
-            public void run() {
-                IWorkbenchWindow workbenchWindow = workbenchAndReturn.o1;
-                if (workbenchWindow == null) {
-                    workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
-                }
-
-                if (workbenchWindow == null) {
-                    return;
-                }
-
-                IWorkbenchPage activePage = workbenchWindow.getActivePage();
-                if (activePage == null) {
-                    return;
-                }
-
-                IEditorReference[] editorReferences = activePage.getEditorReferences();
-                for (IEditorReference editorReference : editorReferences) {
-                    IEditorPart editor = editorReference.getEditor(false);
-                    if (editor != null) {
-                        if (editor instanceof PyEdit) {
-                            PyEdit pyEdit = (PyEdit) editor;
-                            IEditorInput editorInput = pyEdit.getEditorInput();
-                            if (editorInput instanceof IPathEditorInput) {
-                                IPathEditorInput pathEditorInput = (IPathEditorInput) editorInput;
-                                IPath localPath = pathEditorInput.getPath();
-                                if (localPath != null) {
-                                    String considerName = localPath.segment(localPath.segmentCount() - 1);
-                                    if (matchName.equals(considerName)) {
-                                        workbenchAndReturn.o2 = editorInput;
-                                        return;
-                                    }
-                                }
-                            } else {
-                                File editorFile = pyEdit.getEditorFile();
-                                if (editorFile != null) {
-                                    if (editorFile.getName().equals(matchName)) {
-                                        workbenchAndReturn.o2 = editorInput;
-                                        return;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        };
-
-        if (workbenchAndReturn.o1 == null) { //not ui-thread
-            Display.getDefault().syncExec(r);
-        } else {
-            r.run();
-        }
-
-        return workbenchAndReturn.o2;
+        return new FindFromExistingEditorsName(matchName).findFromOpenedPyEdits();
     }
 
     /**
@@ -433,7 +481,7 @@ public class PySourceLocatorBase {
 
     /**
      * Ask the user to select one file of the given list of files (if some is available)
-     * 
+     *
      * @param files the files available for selection.
      * @return the selected file (from the files passed) or null if there was no file available for
      * selection or if the user canceled it.
diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNature.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNature.java
index dadcc54..2d696d6 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNature.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/PythonNature.java
@@ -1320,4 +1320,12 @@ public class PythonNature extends AbstractPythonNature implements IPythonNature
     public String toString() {
         return "PythonNature: " + this.project;
     }
+
+    @Override
+    public Object getAdapter(Class adapter) {
+        if (IProject.class == adapter) {
+            return this.project;
+        }
+        return null;
+    }
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/SystemPythonNature.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/SystemPythonNature.java
index bf61410..a879a4c 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/SystemPythonNature.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/nature/SystemPythonNature.java
@@ -298,4 +298,9 @@ public class SystemPythonNature extends AbstractPythonNature implements IPythonN
     public boolean isOkToUse() {
         return this.manager != null && this.info != null;
     }
+
+    @Override
+    public Object getAdapter(Class adapter) {
+        return null;
+    }
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/AbstractPydevPrefs.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/AbstractPydevPrefs.java
index 710ac01..1ae856d 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/AbstractPydevPrefs.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/AbstractPydevPrefs.java
@@ -57,55 +57,14 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
      * - add what appears in the Preferences page at createAppearancePage()
      * - add the function to the org.python.pydev.editor.autoedit.IIndentPrefs interface
      * - probably add that function to org.python.pydev.editor.autoedit.DefaultIndentPrefs
-     * 
+     *
      */
 
-    public static final String AUTO_PAR = "AUTO_PAR";
-    public static final boolean DEFAULT_AUTO_PAR = true;
-
-    public static final String AUTO_LINK = "AUTO_LINK";
-    public static final boolean DEFAULT_AUTO_LINK = false;
-
-    public static final String AUTO_INDENT_TO_PAR_LEVEL = "AUTO_INDENT_TO_PAR_LEVEL";
-    public static final boolean DEFAULT_AUTO_INDENT_TO_PAR_LEVEL = true;
-
-    public static final String AUTO_INDENT_AFTER_PAR_WIDTH = "AUTO_INDENT_AFTER_PAR_WIDTH";
-    public static final int DEFAULT_AUTO_INDENT_AFTER_PAR_WIDTH = 1;
-
-    public static final String AUTO_DEDENT_ELSE = "AUTO_DEDENT_ELSE";
-    public static final boolean DEFAULT_AUTO_DEDENT_ELSE = true;
-
-    public static final String SMART_INDENT_PAR = "SMART_INDENT_PAR";
-    public static final boolean DEFAULT_SMART_INDENT_PAR = true;
-
     /**
      * Edition of translation paths.
      */
     public static final String SOURCE_LOCATION_PATHS = "SOURCE_LOCATION_PATHS";
 
-    /**
-     * fields for automatically replacing a colon
-     * @see  
-     */
-    public static final String AUTO_COLON = "AUTO_COLON";
-    public static final boolean DEFAULT_AUTO_COLON = true;
-
-    /**
-     * fields for automatically skipping braces
-     * @see  org.python.pydev.editor.autoedit.PyAutoIndentStrategy
-     */
-    public static final String AUTO_BRACES = "AUTO_BRACES";
-    public static final boolean DEFAULT_AUTO_BRACES = true;
-
-    /**
-     * Used if the 'import' should be written automatically in an from xxx import yyy
-     */
-    public static final String AUTO_WRITE_IMPORT_STR = "AUTO_WRITE_IMPORT_STR";
-    public static final boolean DEFAULT_AUTO_WRITE_IMPORT_STR = true;
-
-    public static final String AUTO_LITERALS = "AUTO_LITERALS";
-    public static final boolean DEFAULT_AUTO_LITERALS = true;
-
     //text
     public static final String TAB_WIDTH = "TAB_WIDTH";
     public static final int DEFAULT_TAB_WIDTH = 4;
@@ -114,15 +73,6 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
     public static final String SUBSTITUTE_TABS = "SUBSTITUTE_TABS";
     public static final boolean DEFAULT_SUBSTITUTE_TABS = true;
 
-    public static final String AUTO_ADD_SELF = "AUTO_ADD_SELF";
-    public static final boolean DEFAULT_AUTO_ADD_SELF = true;
-
-    public static final String SMART_LINE_MOVE = "SMART_LINE_MOVE";
-    //Disabled by default (doesn't seem as useful as I though because Python does not have the end
-    //braces and Java does (so, there are a number of cases where the indentation has to be hand-fixed
-    //anyways)
-    public static final boolean DEFAULT_SMART_LINE_MOVE = false;
-
     public static final String GUESS_TAB_SUBSTITUTION = "GUESS_TAB_SUBSTITUTION";
     public static final boolean DEFAULT_GUESS_TAB_SUBSTITUTION = true;
 
@@ -202,7 +152,7 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
     public static final boolean DEFAULT_DONT_TRACE_ENABLED = true;
 
     public static final String TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS = "TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS";
-    public static final boolean DEFAULT_TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS = true;
+    public static final boolean DEFAULT_TRACE_DJANGO_TEMPLATE_RENDER_EXCEPTIONS = false;
 
     public static final String DEBUG_MULTIPROCESSING_ENABLED = "DEBUG_MULTIPROCESSING_ENABLED";
     public static final boolean DEFAULT_DEBUG_MULTIPROCESSING_ENABLED = true;
@@ -336,7 +286,7 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
 
     /**
      * List of master/slave listeners when there's a dependency.
-     * 
+     *
      * @see #createDependency(Button, String, Control)
      * @since 3.0
      */
@@ -346,32 +296,10 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
 
         java.util.List<OverlayPreferenceStore.OverlayKey> overlayKeys = new ArrayList<OverlayPreferenceStore.OverlayKey>();
 
-        //text
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, TAB_WIDTH));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_PAR));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_LINK));
-        overlayKeys
-                .add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_INDENT_TO_PAR_LEVEL));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AUTO_INDENT_AFTER_PAR_WIDTH));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_DEDENT_ELSE));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, SMART_INDENT_PAR));
-
-        //Auto eat colon and braces
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_COLON));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_BRACES));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_WRITE_IMPORT_STR));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_LITERALS));
-
         //matching
         overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, USE_MATCHING_BRACKETS));
         overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, MATCHING_BRACKETS_COLOR));
 
-        //checkbox      
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, SUBSTITUTE_TABS));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AUTO_ADD_SELF));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, SMART_LINE_MOVE));
-        overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, GUESS_TAB_SUBSTITUTION));
-
         //colors
         overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, CODE_COLOR));
         overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, NUMBER_COLOR));
@@ -684,7 +612,7 @@ public abstract class AbstractPydevPrefs extends PreferencePage implements IWork
 
     /**
      * Applies the status to the status line of a dialog page.
-     * 
+     *
      * @param page the dialog page
      * @param status the status
      */
diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PyCodeFormatterPage.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PyCodeFormatterPage.java
index 38beb6b..c268d07 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PyCodeFormatterPage.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PyCodeFormatterPage.java
@@ -11,8 +11,8 @@
  */
 package org.python.pydev.plugin.preferences;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.preference.BooleanFieldEditor;
-import org.eclipse.jface.preference.FieldEditorPreferencePage;
 import org.eclipse.jface.preference.StringFieldEditor;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.eclipse.swt.SWT;
@@ -23,31 +23,31 @@ import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
 import org.python.pydev.editor.StyledTextForShowingCodeFactory;
-import org.python.pydev.editor.actions.PyFormatStd;
 import org.python.pydev.editor.actions.PyFormatStd.FormatStd;
+import org.python.pydev.editor.preferences.PyScopedPreferences;
 import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.shared_core.structure.Tuple;
 import org.python.pydev.shared_ui.field_editors.BooleanFieldEditorCustom;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LinkFieldEditor;
-import org.python.pydev.utils.ComboFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
 
 /**
  * @author Fabio Zadrozny
  */
-public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+public class PyCodeFormatterPage extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
 
     public static final String FORMAT_WITH_AUTOPEP8 = "FORMAT_WITH_AUTOPEP8";
     public static final boolean DEFAULT_FORMAT_WITH_AUTOPEP8 = false;
 
     public static final String AUTOPEP8_PARAMETERS = "AUTOPEP8_PARAMETERS";
 
-    public static final String AUTO_FORMAT_ONLY_WORKSPACE_FILES = "AUTO_FORMAT_ONLY_WORKSPACE_FILES";
-    public static final boolean DEFAULT_AUTO_FORMAT_ONLY_WORKSPACE_FILES = true;
-
     public static final String FORMAT_ONLY_CHANGED_LINES = "FORMAT_ONLY_CHANGED_LINES";
     public static final boolean DEFAULT_FORMAT_ONLY_CHANGED_LINES = false;
 
@@ -100,6 +100,7 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
     private Composite fieldParent;
     private StringFieldEditor autopep8Parameters;
     private LinkFieldEditor autopep8Link;
+    private boolean disposed = false;
 
     public PyCodeFormatterPage() {
         super(GRID);
@@ -146,10 +147,6 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
                     }
                 }));
 
-        addField(createBooleanFieldEditorCustom(AUTO_FORMAT_ONLY_WORKSPACE_FILES,
-                "Auto-format only files in the workspace?",
-                p));
-
         formatWithAutoPep8 = createBooleanFieldEditorCustom(FORMAT_WITH_AUTOPEP8,
                 "Use autopep8.py for code formatting?", p);
         addField(formatWithAutoPep8);
@@ -218,7 +215,7 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
         GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
         labelExample.setLayoutData(layoutData);
 
-        updateLabelExample(PyFormatStd.getFormat());
+        addField(new ScopedPreferencesFieldEditor(p, PydevPlugin.DEFAULT_PYDEV_SCOPE, this));
     }
 
     @Override
@@ -239,6 +236,9 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
             }
         });
         updateState();
+
+        // And update the example when it's already there
+        updateLabelExampleNow(this.getFormatFromEditorContents());
     }
 
     private void updateState() {
@@ -276,7 +276,35 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
         return new BooleanFieldEditorCustom(name, label, BooleanFieldEditor.SEPARATE_LABEL, parent);
     }
 
-    private void updateLabelExample(FormatStd formatStd) {
+    // Note: no locking is needed since we're doing everything in the UI thread.
+    private Runnable currentRunnable;
+
+    private void updateLabelExample(final FormatStd formatStd) {
+        if (!disposed) {
+            Runnable runnable = new Runnable() {
+
+                @Override
+                public void run() {
+                    if (disposed) {
+                        currentRunnable = null;
+                        return;
+                    }
+
+                    if (currentRunnable == this) {
+                        updateLabelExampleNow(formatStd);
+                        currentRunnable = null;
+                    }
+                }
+            };
+            currentRunnable = runnable;
+            // Give a timeout before updating (otherwise when changing the text for the autopep8 integration
+            // it becomes slow).
+            Display.getCurrent().timerExec(400, runnable);
+        }
+    }
+
+    private void updateLabelExampleNow(FormatStd formatStd) {
+
         String str = "class Example(object):             \n" +
                 "                                   \n" +
                 "    def Call(self, param1=None):   \n" +
@@ -296,6 +324,17 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
     @Override
     public void propertyChange(PropertyChangeEvent event) {
         super.propertyChange(event);
+        updateLabelExample(getFormatFromEditorContents());
+    }
+
+    @Override
+    protected void performDefaults() {
+        super.performDefaults();
+        updateLabelExample(getFormatFromEditorContents());
+        updateState();
+    }
+
+    private FormatStd getFormatFromEditorContents() {
         FormatStd formatStd = new FormatStd();
         formatStd.assignWithSpaceInsideParens = this.assignWithSpaceInsideParentesis.getBooleanValue();
         formatStd.operatorsWithSpace = operatorsWithSpace.getBooleanValue();
@@ -307,9 +346,9 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
         formatStd.spacesBeforeComment = Integer.parseInt(spacesBeforeComment.getComboValue());
         formatStd.spacesInStartComment = Integer.parseInt(spacesInStartComment.getComboValue());
         formatStd.formatWithAutopep8 = this.formatWithAutoPep8.getBooleanValue();
-        formatStd.autopep8Parameters = PyCodeFormatterPage.getAutopep8Parameters();
+        formatStd.autopep8Parameters = this.autopep8Parameters.getStringValue();
         formatStd.updateAutopep8();
-        updateLabelExample(formatStd);
+        return formatStd;
     }
 
     /**
@@ -318,71 +357,68 @@ public class PyCodeFormatterPage extends FieldEditorPreferencePage implements IW
     public void init(IWorkbench workbench) {
     }
 
-    public static boolean getFormatWithAutopep8() {
-        return PydevPrefs.getPreferences().getBoolean(FORMAT_WITH_AUTOPEP8);
+    public static boolean getFormatWithAutopep8(IAdaptable projectAdaptable) {
+        return getBoolean(FORMAT_WITH_AUTOPEP8, projectAdaptable);
+    }
+
+    public static boolean getBoolean(String setting, IAdaptable projectAdaptable) {
+        return PyScopedPreferences.getBoolean(setting, projectAdaptable);
     }
 
-    public static String getAutopep8Parameters() {
-        return PydevPrefs.getPreferences().getString(AUTOPEP8_PARAMETERS);
+    protected static String getString(String setting, IAdaptable projectAdaptable) {
+        return PyScopedPreferences.getString(setting, projectAdaptable);
     }
 
-    public static boolean getAutoformatOnlyWorkspaceFiles() {
-        return PydevPrefs.getPreferences().getBoolean(AUTO_FORMAT_ONLY_WORKSPACE_FILES);
+    public static String getAutopep8Parameters(IAdaptable projectAdaptable) {
+        return getString(AUTOPEP8_PARAMETERS, projectAdaptable);
     }
 
-    public static boolean getFormatOnlyChangedLines() {
-        if (getFormatWithAutopep8()) {
+    public static boolean getFormatOnlyChangedLines(IAdaptable projectAdaptable) {
+        if (getFormatWithAutopep8(projectAdaptable)) {
             return false; //i.e.: not available with autopep8.
         }
-        return PydevPrefs.getPreferences().getBoolean(FORMAT_ONLY_CHANGED_LINES);
+        return getBoolean(FORMAT_ONLY_CHANGED_LINES, projectAdaptable);
     }
 
-    public static boolean getAddNewLineAtEndOfFile() {
-        return PydevPrefs.getPreferences().getBoolean(ADD_NEW_LINE_AT_END_OF_FILE);
+    public static boolean getAddNewLineAtEndOfFile(IAdaptable projectAdaptable) {
+        return getBoolean(ADD_NEW_LINE_AT_END_OF_FILE, projectAdaptable);
     }
 
-    public static boolean getTrimLines() {
-        return PydevPrefs.getPreferences().getBoolean(TRIM_LINES);
+    public static boolean getTrimLines(IAdaptable projectAdaptable) {
+        return getBoolean(TRIM_LINES, projectAdaptable);
     }
 
-    public static boolean getTrimMultilineLiterals() {
-        return PydevPrefs.getPreferences().getBoolean(TRIM_MULTILINE_LITERALS);
+    public static boolean getTrimMultilineLiterals(IAdaptable projectAdaptable) {
+        return getBoolean(TRIM_MULTILINE_LITERALS, projectAdaptable);
     }
 
-    public static boolean useSpaceAfterComma() {
-        return PydevPrefs.getPreferences().getBoolean(USE_SPACE_AFTER_COMMA);
+    public static boolean useSpaceAfterComma(IAdaptable projectAdaptable) {
+        return getBoolean(USE_SPACE_AFTER_COMMA, projectAdaptable);
     }
 
-    public static boolean useSpaceForParentesis() {
-        return PydevPrefs.getPreferences().getBoolean(USE_SPACE_FOR_PARENTESIS);
+    public static boolean useSpaceForParentesis(IAdaptable projectAdaptable) {
+        return getBoolean(USE_SPACE_FOR_PARENTESIS, projectAdaptable);
     }
 
-    public static boolean useAssignWithSpacesInsideParenthesis() {
-        return PydevPrefs.getPreferences().getBoolean(USE_ASSIGN_WITH_PACES_INSIDER_PARENTESIS);
+    public static boolean useAssignWithSpacesInsideParenthesis(IAdaptable projectAdaptable) {
+        return getBoolean(USE_ASSIGN_WITH_PACES_INSIDER_PARENTESIS, projectAdaptable);
     }
 
-    public static boolean useOperatorsWithSpace() {
-        return PydevPrefs.getPreferences().getBoolean(USE_OPERATORS_WITH_SPACE);
+    public static boolean useOperatorsWithSpace(IAdaptable projectAdaptable) {
+        return getBoolean(USE_OPERATORS_WITH_SPACE, projectAdaptable);
     }
 
-    public static int getSpacesBeforeComment() {
-        int spaces = PydevPrefs.getPreferences().getInt(SPACES_BEFORE_COMMENT);
-        if (spaces < FormatStd.DONT_HANDLE_SPACES) {
-            spaces = FormatStd.DONT_HANDLE_SPACES;
-        }
-        return spaces;
+    public static int getSpacesBeforeComment(IAdaptable projectAdaptable) {
+        return PyScopedPreferences.getInt(SPACES_BEFORE_COMMENT, projectAdaptable, FormatStd.DONT_HANDLE_SPACES);
     }
 
-    public static int getSpacesInStartComment() {
-        int spaces = PydevPrefs.getPreferences().getInt(SPACES_IN_START_COMMENT);
-        if (spaces < FormatStd.DONT_HANDLE_SPACES) {
-            spaces = FormatStd.DONT_HANDLE_SPACES;
-        }
-        return spaces;
+    public static int getSpacesInStartComment(IAdaptable projectAdaptable) {
+        return PyScopedPreferences.getInt(SPACES_IN_START_COMMENT, projectAdaptable, FormatStd.DONT_HANDLE_SPACES);
     }
 
     @Override
     public void dispose() {
+        disposed = true;
         super.dispose();
         formatAndStyleRangeHelper.dispose();
     }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java
index 67db0a2..8581e5f 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/plugin/preferences/PydevPrefsInitializer.java
@@ -21,6 +21,7 @@ import org.python.pydev.editor.commentblocks.CommentBlocksPreferences;
 import org.python.pydev.editor.correctionassist.docstrings.DocstringsPrefPage;
 import org.python.pydev.editor.hover.PyHoverPreferencesPage;
 import org.python.pydev.editor.preferences.PydevEditorPrefs;
+import org.python.pydev.editor.preferences.PydevTypingPrefs;
 import org.python.pydev.editor.saveactions.PydevSaveActionsPrefPage;
 import org.python.pydev.editorinput.PySourceLocatorPrefs;
 import org.python.pydev.parser.PyParserManager;
@@ -42,17 +43,17 @@ public class PydevPrefsInitializer extends AbstractPreferenceInitializer {
                 IInterpreterManager.IRONPYTHON_DEFAULT_INTERNAL_SHELL_VM_ARGS);
 
         //text
-        node.putBoolean(PydevEditorPrefs.SMART_INDENT_PAR, PydevEditorPrefs.DEFAULT_SMART_INDENT_PAR);
-        node.putBoolean(PydevEditorPrefs.AUTO_PAR, PydevEditorPrefs.DEFAULT_AUTO_PAR);
-        node.putBoolean(PydevEditorPrefs.AUTO_LINK, PydevEditorPrefs.DEFAULT_AUTO_LINK);
-        node.putBoolean(PydevEditorPrefs.AUTO_INDENT_TO_PAR_LEVEL, PydevEditorPrefs.DEFAULT_AUTO_INDENT_TO_PAR_LEVEL);
-        node.putBoolean(PydevEditorPrefs.AUTO_DEDENT_ELSE, PydevEditorPrefs.DEFAULT_AUTO_DEDENT_ELSE);
-        node.putInt(PydevEditorPrefs.AUTO_INDENT_AFTER_PAR_WIDTH, PydevEditorPrefs.DEFAULT_AUTO_INDENT_AFTER_PAR_WIDTH);
-        node.putBoolean(PydevEditorPrefs.AUTO_COLON, PydevEditorPrefs.DEFAULT_AUTO_COLON);
-        node.putBoolean(PydevEditorPrefs.AUTO_BRACES, PydevEditorPrefs.DEFAULT_AUTO_BRACES);
-        node.putBoolean(PydevEditorPrefs.AUTO_WRITE_IMPORT_STR, PydevEditorPrefs.DEFAULT_AUTO_WRITE_IMPORT_STR);
-        node.putBoolean(PydevEditorPrefs.AUTO_LITERALS, PydevEditorPrefs.DEFAULT_AUTO_LITERALS);
-        node.putBoolean(PydevEditorPrefs.SMART_LINE_MOVE, PydevEditorPrefs.DEFAULT_SMART_LINE_MOVE);
+        node.putBoolean(PydevTypingPrefs.SMART_INDENT_PAR, PydevTypingPrefs.DEFAULT_SMART_INDENT_PAR);
+        node.putBoolean(PydevTypingPrefs.AUTO_PAR, PydevTypingPrefs.DEFAULT_AUTO_PAR);
+        node.putBoolean(PydevTypingPrefs.AUTO_LINK, PydevTypingPrefs.DEFAULT_AUTO_LINK);
+        node.putBoolean(PydevTypingPrefs.AUTO_INDENT_TO_PAR_LEVEL, PydevTypingPrefs.DEFAULT_AUTO_INDENT_TO_PAR_LEVEL);
+        node.putBoolean(PydevTypingPrefs.AUTO_DEDENT_ELSE, PydevTypingPrefs.DEFAULT_AUTO_DEDENT_ELSE);
+        node.putInt(PydevTypingPrefs.AUTO_INDENT_AFTER_PAR_WIDTH, PydevTypingPrefs.DEFAULT_AUTO_INDENT_AFTER_PAR_WIDTH);
+        node.putBoolean(PydevTypingPrefs.AUTO_COLON, PydevTypingPrefs.DEFAULT_AUTO_COLON);
+        node.putBoolean(PydevTypingPrefs.AUTO_BRACES, PydevTypingPrefs.DEFAULT_AUTO_BRACES);
+        node.putBoolean(PydevTypingPrefs.AUTO_WRITE_IMPORT_STR, PydevTypingPrefs.DEFAULT_AUTO_WRITE_IMPORT_STR);
+        node.putBoolean(PydevTypingPrefs.AUTO_LITERALS, PydevTypingPrefs.DEFAULT_AUTO_LITERALS);
+        node.putBoolean(PydevTypingPrefs.SMART_LINE_MOVE, PydevTypingPrefs.DEFAULT_SMART_LINE_MOVE);
 
         node.putInt(PydevEditorPrefs.TAB_WIDTH, PydevEditorPrefs.DEFAULT_TAB_WIDTH);
         node.putInt(IWizardNewProjectNameAndLocationPage.PYDEV_NEW_PROJECT_CREATE_PREFERENCES,
@@ -72,7 +73,7 @@ public class PydevPrefsInitializer extends AbstractPreferenceInitializer {
 
         //checkboxes
         node.putBoolean(PydevEditorPrefs.SUBSTITUTE_TABS, PydevEditorPrefs.DEFAULT_SUBSTITUTE_TABS);
-        node.putBoolean(PydevEditorPrefs.AUTO_ADD_SELF, PydevEditorPrefs.DEFAULT_AUTO_ADD_SELF);
+        node.putBoolean(PydevTypingPrefs.AUTO_ADD_SELF, PydevTypingPrefs.DEFAULT_AUTO_ADD_SELF);
         node.putBoolean(PydevEditorPrefs.GUESS_TAB_SUBSTITUTION, PydevEditorPrefs.DEFAULT_GUESS_TAB_SUBSTITUTION);
         node.putBoolean(PydevEditorPrefs.USE_VERTICAL_INDENT_GUIDE, PydevEditorPrefs.DEFAULT_USE_VERTICAL_INDENT_GUIDE);
         node.putBoolean(PydevEditorPrefs.USE_VERTICAL_INDENT_COLOR_EDITOR_FOREGROUND,
@@ -188,8 +189,8 @@ public class PydevPrefsInitializer extends AbstractPreferenceInitializer {
                 PyCodeFormatterPage.DEFAULT_ADD_NEW_LINE_AT_END_OF_FILE);
         node.putBoolean(PydevSaveActionsPrefPage.FORMAT_BEFORE_SAVING,
                 PydevSaveActionsPrefPage.DEFAULT_FORMAT_BEFORE_SAVING);
-        node.putBoolean(PyCodeFormatterPage.AUTO_FORMAT_ONLY_WORKSPACE_FILES,
-                PyCodeFormatterPage.DEFAULT_AUTO_FORMAT_ONLY_WORKSPACE_FILES);
+        node.putBoolean(PydevSaveActionsPrefPage.SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES,
+                PydevSaveActionsPrefPage.DEFAULT_SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES);
         node.putBoolean(PyCodeFormatterPage.FORMAT_WITH_AUTOPEP8, PyCodeFormatterPage.DEFAULT_FORMAT_WITH_AUTOPEP8);
         node.putBoolean(PyCodeFormatterPage.FORMAT_ONLY_CHANGED_LINES,
                 PyCodeFormatterPage.DEFAULT_FORMAT_ONLY_CHANGED_LINES);
diff --git a/plugins/org.python.pydev/src/org/python/pydev/pyunit/preferences/PyUnitPrefsPage2.java b/plugins/org.python.pydev/src/org/python/pydev/pyunit/preferences/PyUnitPrefsPage2.java
index 2b3aa8a..b0d51f4 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/pyunit/preferences/PyUnitPrefsPage2.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/pyunit/preferences/PyUnitPrefsPage2.java
@@ -32,12 +32,12 @@ import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.plugin.preferences.PydevPrefs;
 import org.python.pydev.shared_core.string.FastStringBuffer;
+import org.python.pydev.shared_ui.field_editors.ComboFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
 import org.python.pydev.shared_ui.field_editors.LinkFieldEditor;
 import org.python.pydev.shared_ui.field_editors.MultiStringFieldEditor;
 import org.python.pydev.shared_ui.tooltips.presenter.AbstractTooltipInformationPresenter;
 import org.python.pydev.shared_ui.tooltips.presenter.ToolTipPresenterHandler;
-import org.python.pydev.utils.ComboFieldEditor;
 
 public class PyUnitPrefsPage2 extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
 
diff --git a/plugins/org.python.pydev/src/org/python/pydev/runners/SimpleRunner.java b/plugins/org.python.pydev/src/org/python/pydev/runners/SimpleRunner.java
index 9b443a7..ec80fa9 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/runners/SimpleRunner.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/runners/SimpleRunner.java
@@ -179,6 +179,8 @@ public class SimpleRunner {
 
         //Always remove PYTHONHOME from the default system env, as it doesn't work well with multiple interpreters.
         env.remove("PYTHONHOME");
+        // PyDev-495 Remove VIRTUAL_ENV as it cause IPython to munge the PYTHON_PATH
+        env.remove("VIRTUAL_ENV");
         return env;
     }
 
diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyOrganizeImportsAction.java b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyOrganizeImportsAction.java
index e300ada..114fdb6 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyOrganizeImportsAction.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/ui/actions/container/PyOrganizeImportsAction.java
@@ -7,12 +7,10 @@
  */
 package org.python.pydev.ui.actions.container;
 
-
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.python.pydev.editor.actions.PyOrganizeImports;
 import org.python.pydev.ui.importsconf.ImportsPreferencesPage;
 
-
 /**
  * Action used to organize imports to all the available python files.
  *  
@@ -31,17 +29,18 @@ public class PyOrganizeImportsAction extends PyContainerFormatterAction {
 
     @Override
     protected boolean confirmRun() {
-        return 
-                
-                super.confirmRun()
-                && ( (!ImportsPreferencesPage.getDeleteUnusedImports())
-                        ||
+        return
+
+        super.confirmRun()
+                //Note: ask for the platform, but preferences will follow settings in each project.
+                && ((!ImportsPreferencesPage.getDeleteUnusedImports(null))
+                ||
                 MessageDialog
-                .openConfirm(
-                        null,
-                        "Confirm Deletion of Unused Imports",
-                        "Your preferences show to delete unused imports (PyDev > Editor > Code Style > Imports)\n"
-                                + "\n"
-                                + "This requires that you have run the PyDev Code Analysis recently for correct behavior.") );
+                        .openConfirm(
+                                null,
+                                "Confirm Deletion of Unused Imports",
+                                "Your preferences show to delete unused imports (PyDev > Editor > Code Style > Imports)\n"
+                                        + "\n"
+                                        + "This requires that you have run the PyDev Code Analysis recently for correct behavior."));
     }
 }
diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/PyDialogHelpers.java b/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/PyDialogHelpers.java
index d06b194..25fab7b 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/PyDialogHelpers.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/ui/dialogs/PyDialogHelpers.java
@@ -35,6 +35,10 @@ public class PyDialogHelpers {
         return DialogHelpers.openQuestion(title, message);
     }
 
+    public static Integer openAskInt(String title, String message, int initial) {
+        return DialogHelpers.openAskInt(title, message, initial);
+    }
+
     public static int openWarningWithIgnoreToggle(String title, String message, String key) {
         Shell shell = EditorUtils.getShell();
         IPreferenceStore store = PydevPlugin.getDefault().getPreferenceStore();
diff --git a/plugins/org.python.pydev/src/org/python/pydev/ui/importsconf/ImportsPreferencesPage.java b/plugins/org.python.pydev/src/org/python/pydev/ui/importsconf/ImportsPreferencesPage.java
index d4dd633..06e892d 100644
--- a/plugins/org.python.pydev/src/org/python/pydev/ui/importsconf/ImportsPreferencesPage.java
+++ b/plugins/org.python.pydev/src/org/python/pydev/ui/importsconf/ImportsPreferencesPage.java
@@ -6,17 +6,26 @@
  */
 package org.python.pydev.ui.importsconf;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.preference.BooleanFieldEditor;
-import org.eclipse.jface.preference.FieldEditorPreferencePage;
-import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
 import org.python.pydev.core.docutils.WrapAndCaseUtils;
+import org.python.pydev.editor.preferences.PyScopedPreferences;
 import org.python.pydev.plugin.PydevPlugin;
 import org.python.pydev.plugin.preferences.PydevPrefs;
 import org.python.pydev.shared_core.SharedCorePlugin;
+import org.python.pydev.shared_ui.field_editors.BooleanFieldEditorCustom;
 import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
+import org.python.pydev.shared_ui.field_editors.LinkFieldEditor;
+import org.python.pydev.shared_ui.field_editors.RadioGroupFieldEditor;
+import org.python.pydev.shared_ui.field_editors.ScopedFieldEditorPreferencePage;
+import org.python.pydev.shared_ui.field_editors.ScopedPreferencesFieldEditor;
 
 /**
  * Preferences regarding the way that imports should be managed:
@@ -27,7 +36,10 @@ import org.python.pydev.shared_ui.field_editors.LabelFieldEditor;
  *
  * @author Fabio
  */
-public class ImportsPreferencesPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+public class ImportsPreferencesPage extends ScopedFieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+    private BooleanFieldEditor fromImportsFirstBooleanEditor;
+    private BooleanFieldEditorCustom pep8ImportCompliantFieldEditor;
 
     public ImportsPreferencesPage() {
         super(FLAT);
@@ -68,8 +80,9 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
         addField(new LabelFieldEditor("Label_Info_File_Preferences1", WrapAndCaseUtils.wrap(
                 "These setting are used whenever imports are managed in the application\n\n", 80), p));
 
-        addFieldWithToolTip(new BooleanFieldEditor(PEP8_IMPORTS, WrapAndCaseUtils.wrap(
-                "Use Pep8 compliant import organzier?", 80), p), p,
+        pep8ImportCompliantFieldEditor = new BooleanFieldEditorCustom(PEP8_IMPORTS, WrapAndCaseUtils.wrap(
+                "Use Pep8 compliant import organzier?", 80), p);
+        addFieldWithToolTip(pep8ImportCompliantFieldEditor, p,
                 "System modules are those found on the interpreter's Python path;"
                         + " third party modules are found in site-packages.");
 
@@ -81,7 +94,9 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
 
         addField(new BooleanFieldEditor(GROUP_IMPORTS, "Combine 'from' imports when possible?", p));
 
-        addField(new BooleanFieldEditor(FROM_IMPORTS_FIRST, "Sort 'from' imports before 'import' imports?", p));
+        fromImportsFirstBooleanEditor = new BooleanFieldEditor(FROM_IMPORTS_FIRST,
+                "Sort 'from' imports before 'import' imports?", p);
+        addField(fromImportsFirstBooleanEditor);
 
         addField(new BooleanFieldEditor(MULTILINE_IMPORTS, WrapAndCaseUtils.wrap(
                 "Allow multiline imports when the import size would exceed the print margin?", 80), p));
@@ -92,6 +107,42 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
         addField(new RadioGroupFieldEditor(BREAK_IMPORTS_MODE, "How to break imports in multiline?", 1,
                 new String[][] { { "Use escape char", BREAK_IMPORTS_MODE_ESCAPE },
                         { "Use parenthesis", BREAK_IMPORTS_MODE_PARENTHESIS } }, p));
+
+        updateEnablement(p, PydevPrefs.getPreferences().getBoolean(PEP8_IMPORTS));
+        Button checkBox = pep8ImportCompliantFieldEditor.getCheckBox(p);
+        checkBox.addSelectionListener(new SelectionListener() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                updateEnablement(p, pep8ImportCompliantFieldEditor.getBooleanValue());
+            }
+
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+            }
+        });
+
+        addField(new LinkFieldEditor("link_saveactions",
+                "\nNote: view <a>save actions</a> to automatically sort imports on save.", p,
+                new SelectionListener() {
+
+                    @Override
+                    public void widgetSelected(SelectionEvent e) {
+                        String id = "org.python.pydev.editor.saveactions.PydevSaveActionsPrefPage";
+                        IWorkbenchPreferenceContainer workbenchPreferenceContainer = ((IWorkbenchPreferenceContainer) getContainer());
+                        workbenchPreferenceContainer.openPage(id, null);
+                    }
+
+                    @Override
+                    public void widgetDefaultSelected(SelectionEvent e) {
+                    }
+                }));
+
+        addField(new ScopedPreferencesFieldEditor(p, PydevPlugin.DEFAULT_PYDEV_SCOPE, this));
+    }
+
+    private void updateEnablement(Composite p, boolean enable) {
+        fromImportsFirstBooleanEditor.setEnabled(enable, p);
     }
 
     private void addFieldWithToolTip(BooleanFieldEditor editor, Composite p, String tip) {
@@ -107,11 +158,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
      * @return true if imports should be grouped when possible. E.g.: If from aaa import b and from aaa import c
      * exist, they should be grouped as from aaa import b, c
      */
-    public static boolean getGroupImports() {
+    public static boolean getGroupImports(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return groupImportsForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(GROUP_IMPORTS);
+        return PyScopedPreferences.getBoolean(GROUP_IMPORTS, projectAdaptable);
     }
 
     /**
@@ -127,11 +178,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
      *   import b_module
      *   import d_module   
      */
-    public static boolean getSortFromImportsFirst() {
+    public static boolean getSortFromImportsFirst(IAdaptable projectAdaptable) {
         if (PydevPlugin.getDefault() == null) {
             return sortFromImportsFirstForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(FROM_IMPORTS_FIRST);
+        return PyScopedPreferences.getBoolean(FROM_IMPORTS_FIRST, projectAdaptable);
     }
 
     /**
@@ -142,11 +193,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
     /**
      * @return true if imports should be wrapped when they exceed the print margin.
      */
-    public static boolean getMultilineImports() {
+    public static boolean getMultilineImports(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return multilineImportsForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(MULTILINE_IMPORTS);
+        return PyScopedPreferences.getBoolean(MULTILINE_IMPORTS, projectAdaptable);
     }
 
     /**
@@ -154,11 +205,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
      */
     public static boolean multilineImportsForTests = true;
 
-    public static boolean getSortNamesGrouped() {
+    public static boolean getSortNamesGrouped(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return sortNamesGroupedForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(SORT_NAMES_GROUPED);
+        return PyScopedPreferences.getBoolean(SORT_NAMES_GROUPED, projectAdaptable);
     }
 
     /**
@@ -171,11 +222,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
      * @see #BREAK_IMPORTS_MODE_ESCAPE
      * @see #BREAK_IMPORTS_MODE_PARENTHESIS
      */
-    public static String getBreakIportMode() {
+    public static String getBreakIportMode(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return breakImportModeForTests;
         }
-        return PydevPrefs.getPreferences().getString(BREAK_IMPORTS_MODE);
+        return PyScopedPreferences.getString(BREAK_IMPORTS_MODE, projectAdaptable);
     }
 
     /**
@@ -186,11 +237,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
     /**
      * @return whether to format imports according to pep8
      */
-    public static boolean getPep8Imports() {
+    public static boolean getPep8Imports(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return pep8ImportsForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(PEP8_IMPORTS);
+        return PyScopedPreferences.getBoolean(PEP8_IMPORTS, projectAdaptable);
     }
 
     /**
@@ -201,11 +252,11 @@ public class ImportsPreferencesPage extends FieldEditorPreferencePage implements
     /**
      * @return whether to delete unused imports
      */
-    public static boolean getDeleteUnusedImports() {
+    public static boolean getDeleteUnusedImports(IAdaptable projectAdaptable) {
         if (SharedCorePlugin.inTestMode()) {
             return deleteUnusedImportsForTests;
         }
-        return PydevPrefs.getPreferences().getBoolean(DELETE_UNUSED_IMPORTS);
+        return PyScopedPreferences.getBoolean(DELETE_UNUSED_IMPORTS, projectAdaptable);
     }
 
     /**
diff --git a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/OverrideMethodCompletionProposal.java b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/OverrideMethodCompletionProposal.java
index 642aec9..8862680 100644
--- a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/OverrideMethodCompletionProposal.java
+++ b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/OverrideMethodCompletionProposal.java
@@ -137,7 +137,7 @@ public class OverrideMethodCompletionProposal extends AbstractPyCompletionPropos
             if (edit != null) {
                 indentPrefs = edit.getIndentPrefs();
             } else {
-                indentPrefs = DefaultIndentPrefs.get();
+                indentPrefs = DefaultIndentPrefs.get(null);
             }
 
             PrettyPrinterPrefsV2 prefsV2 = PrettyPrinterV2.createDefaultPrefs(edit, indentPrefs, lineDelimiter);
diff --git a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/revisited/PythonPathHelper.java b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/revisited/PythonPathHelper.java
index 4e1edf4..b8e07b2 100644
--- a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/revisited/PythonPathHelper.java
+++ b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/revisited/PythonPathHelper.java
@@ -506,6 +506,25 @@ public final class PythonPathHelper implements IPythonPathHelper {
     }
 
     /**
+     * @param root this is the folder we're checking
+     * @return true if it is a folder with an __init__ python file
+     */
+    public static IFile getFolderInit(IContainer root) {
+        // Checking for existence of a specific file is much faster than listing a directory!
+        String[] validInitFiles = FileTypesPreferencesPage.getValidInitFiles();
+        int len = validInitFiles.length;
+        for (int i = 0; i < len; i++) {
+            String init = validInitFiles[i];
+            IFile f = root.getFile(new Path(init));
+            if (f.exists()) {
+                return f;
+            }
+        }
+
+        return null;
+    }
+
+    /**
      * @param item the file we want to check
      * @return true if the file is a valid __init__ file
      */
diff --git a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/templates/PyDocumentTemplateContext.java b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/templates/PyDocumentTemplateContext.java
index 5032b8e..e199f24 100644
--- a/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/templates/PyDocumentTemplateContext.java
+++ b/plugins/org.python.pydev/src_completions/org/python/pydev/editor/codecompletion/templates/PyDocumentTemplateContext.java
@@ -140,7 +140,7 @@ public final class PyDocumentTemplateContext extends DocumentTemplateContextWith
             PySourceViewer pyViewer = (PySourceViewer) viewer;
             return pyViewer.getEdit().getIndentPrefs();
         } else {
-            return DefaultIndentPrefs.get();
+            return DefaultIndentPrefs.get(null);
         }
     }
 
diff --git a/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/PyRenameResourceAction.java b/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/PyRenameResourceAction.java
index b310873..7ab8dc5 100644
--- a/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/PyRenameResourceAction.java
+++ b/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/PyRenameResourceAction.java
@@ -6,12 +6,12 @@
  */
 package org.python.pydev.navigator.actions;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
@@ -68,7 +68,7 @@ public class PyRenameResourceAction extends RenameResourceAction {
      *
      * @return java.lang.String
      * @param resource the resource to query status on
-     * 
+     *
      * Fix from platform: was not checking return from dialog.open
      */
     @Override
@@ -103,7 +103,7 @@ public class PyRenameResourceAction extends RenameResourceAction {
 
     /*
      * (non-Javadoc)
-     * 
+     *
      * @see org.eclipse.jface.action.Action#isEnabled()
      */
     @Override
@@ -136,7 +136,7 @@ public class PyRenameResourceAction extends RenameResourceAction {
 
     /**
      * Update the PYTHONPATH of the project containing a renamed folder by replacing the folder's
-     * old path with its new one (if the folder itself is in the PYTHONPATH), and updating the 
+     * old path with its new one (if the folder itself is in the PYTHONPATH), and updating the
      * paths of any of its children that are in the PYTHONPATH.
      */
     private void updatePyPath() {
@@ -280,24 +280,30 @@ public class PyRenameResourceAction extends RenameResourceAction {
                 try {
                     String resolveModule = n.resolveModule(r);
                     if (resolveModule != null &&
-                            // When it's an __init__, don't rename the package, only the file (regular rename operation 
+                            // When it's an __init__, don't rename the package, only the file (regular rename operation
                             // -- the folder has to be selected to do a package rename
                             !resolveModule.endsWith(".__init__"))
                     {
-                        File file = r.getLocation().toFile();
-                        boolean isDir = file.isDirectory();
-                        File initFile = null;
-                        if (isDir) {
-                            initFile = PythonPathHelper.getFolderInit(file);
+                        IFile file = null;
+                        boolean foundAsInit = false;
+                        if (r instanceof IContainer) {
+                            file = PythonPathHelper.getFolderInit((IContainer) r);
+                            foundAsInit = true;
+                        } else if (r instanceof IFile) {
+                            file = (IFile) r;
                         }
-                        if (isDir && initFile == null) {
+
+                        if (file != null && file.exists()) {
                             //It's a directory without an __init__.py file, just keep going...
-                        } else {
-                            if (isDir) {
-                                //If it's a directory, use the __init__.py instead.
-                                file = initFile;
+                            RefactoringRequest request = new ModuleRenameRefactoringRequest(
+                                    file.getLocation().toFile(), n, null);
+                            if (!foundAsInit) {
+                                // If we have found it as an __init__ when renaming a module, we won't
+                                // set the related IFile (because we don't want to provide a 'simple rename'
+                                // in this case -- as if he did actually select the __init__, only the simple
+                                // rename would be provided in the first place).
+                                request.setFileResource(file);
                             }
-                            RefactoringRequest request = new ModuleRenameRefactoringRequest(file, n, null);
                             AbstractPyRefactoring.getPyRefactoring().rename(new PyRefactoringRequest(request));
                             //i.e.: if it was a module inside the pythonpath (as we resolved the name), don't go the default
                             //route and do a refactoring request to rename it)!
diff --git a/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/copied/PasteAction.java b/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/copied/PasteAction.java
index f9ddfa7..d9d9491 100644
--- a/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/copied/PasteAction.java
+++ b/plugins/org.python.pydev/src_navigator/org/python/pydev/navigator/actions/copied/PasteAction.java
@@ -178,7 +178,7 @@ public abstract class PasteAction extends SelectionListenerAction {
             }
             String delimiter = PyAction.getDelimiter(new Document());
             if (delimiter != null) {
-                StringUtils.replaceNewLines(contents, delimiter);
+                contents = StringUtils.replaceNewLines(contents, delimiter);
             }
 
             IFile file = container.getFile(new Path(name));
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/eclipseresourcestubs/FileResourceStub.java b/plugins/org.python.pydev/tests/org/python/pydev/eclipseresourcestubs/FileResourceStub.java
index 949f0c9..21521f0 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/eclipseresourcestubs/FileResourceStub.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/eclipseresourcestubs/FileResourceStub.java
@@ -16,8 +16,8 @@ import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
-import org.python.pydev.core.resource_stubs.AbstractIFileStub;
 import org.python.pydev.shared_core.io.FileUtils;
+import org.python.pydev.shared_core.resource_stubs.AbstractIFileStub;
 
 /**
  * A stub for a file that implements the IFile interface required by Eclipse.
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/editor/PyAutoIndentStrategyTest.java b/plugins/org.python.pydev/tests/org/python/pydev/editor/PyAutoIndentStrategyTest.java
index be6e78f..cbab92c 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/editor/PyAutoIndentStrategyTest.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/editor/PyAutoIndentStrategyTest.java
@@ -13,6 +13,7 @@ package org.python.pydev.editor;
 
 import junit.framework.TestCase;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.jface.text.Document;
 import org.python.pydev.editor.autoedit.PyAutoIndentStrategy;
 import org.python.pydev.editor.autoedit.TestIndentPrefs;
@@ -43,6 +44,7 @@ public class PyAutoIndentStrategyTest extends TestCase {
     /*
      * @see TestCase#setUp()
      */
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
     }
@@ -50,6 +52,7 @@ public class PyAutoIndentStrategyTest extends TestCase {
     /*
      * @see TestCase#tearDown()
      */
+    @Override
     protected void tearDown() throws Exception {
         super.tearDown();
     }
@@ -60,7 +63,13 @@ public class PyAutoIndentStrategyTest extends TestCase {
      */
     public PyAutoIndentStrategyTest(String arg0) {
         super(arg0);
-        strategy = new PyAutoIndentStrategy();
+        strategy = new PyAutoIndentStrategy(new IAdaptable() {
+
+            @Override
+            public Object getAdapter(Class adapter) {
+                return null;
+            }
+        });
     }
 
     public void testNewLineWithNewWithConstruct() {
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/editor/actions/PyOrganizeImportsTest.java b/plugins/org.python.pydev/tests/org/python/pydev/editor/actions/PyOrganizeImportsTest.java
index dfaee01..ba2d0f7 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/editor/actions/PyOrganizeImportsTest.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/editor/actions/PyOrganizeImportsTest.java
@@ -62,6 +62,11 @@ public class PyOrganizeImportsTest extends TestCase {
         public Object getFormatStd() {
             return formatStd;
         }
+
+        @Override
+        public Object getAdapter(Class adapter) {
+            return null;
+        }
     };
 
     /*
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWithTest.java b/plugins/org.python.pydev/tests/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWithTest.java
index c8c56e7..fc60355 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWithTest.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/editor/correctionassist/heuristics/AssistSurroundWithTest.java
@@ -37,6 +37,60 @@ public class AssistSurroundWithTest extends TestCase {
 
     }
 
+    public void testSurround2() throws Exception {
+        AssistSurroundWith assistSurroundWith = new AssistSurroundWith();
+        IDocument doc = new Document("" +
+                "def m1():\n" +
+                "\n" +
+                "#c\n" +
+                "    a = 10\n" +
+                "\n" +
+                "\n");
+        PySelection ps = new PySelection(doc, 1, 0, 13);
+        int offset = ps.getAbsoluteCursorOffset();
+        List<ICompletionProposal> props = assistSurroundWith.getProps(ps, null, null, null, null, offset);
+        props.get(0).apply(doc);
+        TestCaseUtils.assertContentsEqual("" +
+                "def m1():\n" +
+                "    try:\n" +
+                "    \n" +
+                "    #c\n" +
+                "        a = 10\n"
+                +
+                "    except${cursor}:\n" +
+                "        raise\n" +
+                "\n" +
+                "\n" +
+                "", doc.get());
+    }
+
+    public void testSurround3() throws Exception {
+        AssistSurroundWith assistSurroundWith = new AssistSurroundWith();
+        IDocument doc = new Document("" +
+                "def m1():\n" +
+                "\n" +
+                "#c\n" +
+                "#    a = 10\n" +
+                "\n" +
+                "\n");
+        PySelection ps = new PySelection(doc, 1, 0, 14);
+        int offset = ps.getAbsoluteCursorOffset();
+        List<ICompletionProposal> props = assistSurroundWith.getProps(ps, null, null, null, null, offset);
+        props.get(0).apply(doc);
+        TestCaseUtils.assertContentsEqual("" +
+                "def m1():\n" +
+                "try:\n" +
+                "    \n" +
+                "    #c\n" +
+                "    #    a = 10\n"
+                +
+                "except${cursor}:\n" +
+                "    raise\n" +
+                "\n" +
+                "\n" +
+                "", doc.get());
+    }
+
     public void testSurround() throws Exception {
         AssistSurroundWith assistSurroundWith = new AssistSurroundWith();
         int offset = 0;
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/ironpythontests/IronpythonTest.java b/plugins/org.python.pydev/tests/org/python/pydev/ironpythontests/IronpythonTest.java
index 7d332c1..f1f541e 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/ironpythontests/IronpythonTest.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/ironpythontests/IronpythonTest.java
@@ -47,7 +47,7 @@ public class IronpythonTest extends AbstractBasicRunTestCase {
     /**
      * Runs the python tests available in this plugin and in the debug plugin.
      */
-    public void testPythonTests() throws Exception {
+    public void testIronPythonTests() throws Exception {
         final Set<String> skip = new HashSet<>();
         skip.add("test_pydev_ipython_010.py");
         skip.add("test_pydev_ipython_011.py");
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/FileStub2.java b/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/FileStub2.java
index dcf9344..ba12c4e 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/FileStub2.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/FileStub2.java
@@ -17,7 +17,7 @@ import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.python.pydev.core.resource_stubs.AbstractIFileStub;
+import org.python.pydev.shared_core.resource_stubs.AbstractIFileStub;
 
 public class FileStub2 extends AbstractIFileStub implements IFile {
 
diff --git a/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/ProjectStub2.java b/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/ProjectStub2.java
index e9bf1bb..3e5b2bd 100644
--- a/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/ProjectStub2.java
+++ b/plugins/org.python.pydev/tests/org/python/pydev/plugin/nature/ProjectStub2.java
@@ -14,7 +14,7 @@ import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.QualifiedName;
 import org.python.pydev.core.IPythonNature;
-import org.python.pydev.core.resource_stubs.AbstractIProjectStub;
+import org.python.pydev.shared_core.resource_stubs.AbstractIProjectStub;
 
 public class ProjectStub2 extends AbstractIProjectStub implements IProject {
 
diff --git a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/PythonCompletionWithoutBuiltinsTest.java b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/PythonCompletionWithoutBuiltinsTest.java
index 7a50b19..bd63355 100644
--- a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/PythonCompletionWithoutBuiltinsTest.java
+++ b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/PythonCompletionWithoutBuiltinsTest.java
@@ -1888,4 +1888,16 @@ public class PythonCompletionWithoutBuiltinsTest extends CodeCompletionTestsBase
         ICompletionProposal[] comps = requestCompl(s, s.length(), -1, new String[] { "bar()" });
         assertEquals(1, comps.length);
     }
+
+    public void testTypeOnLocalVar2() throws Exception {
+        String s;
+        s = ""
+                + "class F:\n"
+                + "  def bar():\n"
+                + "    self.n #: :type self.n: F\n"
+                + "    self.n."
+                + "";
+        ICompletionProposal[] comps = requestCompl(s, s.length(), -1, new String[] { "bar()" });
+        assertEquals(1, comps.length);
+    }
 }
diff --git a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/ProjectStub.java b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/ProjectStub.java
index 8a467fd..e78aabb 100644
--- a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/ProjectStub.java
+++ b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/ProjectStub.java
@@ -19,9 +19,9 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.QualifiedName;
 import org.python.pydev.core.IPythonNature;
-import org.python.pydev.core.resource_stubs.AbstractIProjectStub;
 import org.python.pydev.plugin.nature.FileStub2;
 import org.python.pydev.plugin.nature.PythonNature;
+import org.python.pydev.shared_core.resource_stubs.AbstractIProjectStub;
 import org.python.pydev.shared_core.string.StringUtils;
 
 public class ProjectStub extends AbstractIProjectStub implements IProject {
diff --git a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/PyCodeCompletionVisitorTest.java b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/PyCodeCompletionVisitorTest.java
index b0085d3..4d72d4f 100644
--- a/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/PyCodeCompletionVisitorTest.java
+++ b/plugins/org.python.pydev/tests_completions/org/python/pydev/editor/codecompletion/revisited/PyCodeCompletionVisitorTest.java
@@ -21,11 +21,11 @@ import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.text.IDocument;
 import org.python.pydev.builder.VisitorMemo;
-import org.python.pydev.core.resource_stubs.FileMock;
-import org.python.pydev.core.resource_stubs.FolderMock;
-import org.python.pydev.core.resource_stubs.ProjectMock;
 import org.python.pydev.parser.PythonNatureStub;
 import org.python.pydev.shared_core.callbacks.ICallback0;
+import org.python.pydev.shared_core.resource_stubs.FileMock;
+import org.python.pydev.shared_core.resource_stubs.FolderMock;
+import org.python.pydev.shared_core.resource_stubs.ProjectMock;
 
 public class PyCodeCompletionVisitorTest extends TestCase {
 
diff --git a/plugins/org.python.pydev/tests_dltk_console/org/python/pydev/dltk/console/ui/internal/ScriptConsoleDocumentListenerTest.java b/plugins/org.python.pydev/tests_dltk_console/org/python/pydev/dltk/console/ui/internal/ScriptConsoleDocumentListenerTest.java
index 25e7d01..d486211 100644
--- a/plugins/org.python.pydev/tests_dltk_console/org/python/pydev/dltk/console/ui/internal/ScriptConsoleDocumentListenerTest.java
+++ b/plugins/org.python.pydev/tests_dltk_console/org/python/pydev/dltk/console/ui/internal/ScriptConsoleDocumentListenerTest.java
@@ -11,6 +11,7 @@ import java.util.List;
 
 import junit.framework.TestCase;
 
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.debug.ui.console.IConsoleLineTracker;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
@@ -31,22 +32,17 @@ import org.python.pydev.shared_interactive_console.console.ui.internal.ScriptCon
 
 public class ScriptConsoleDocumentListenerTest extends TestCase {
 
+    private IDocument doc;
+    private ScriptConsoleDocumentListener listener;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    public void testConsoleListener() throws Exception {
-        final Document doc = new Document();
+        this.doc = new Document();
         final List<String> commandsHandled = new ArrayList<String>();
 
         ScriptConsolePrompt prompt = new ScriptConsolePrompt(">>> ", "... ");
-        ScriptConsoleDocumentListener listener = new ScriptConsoleDocumentListener(
+        listener = new ScriptConsoleDocumentListener(
                 new IScriptConsoleViewer2ForDocumentListener() {
 
                     public IDocument getDocument() {
@@ -85,10 +81,19 @@ public class ScriptConsoleDocumentListenerTest extends TestCase {
 
                 new ICommandHandler() {
 
-                    public void handleCommand(String userInput,
+                    @Override
+                    public void beforeHandleCommand(String userInput,
                             ICallback<Object, InterpreterResponse> onResponseReceived) {
                         commandsHandled.add(userInput);
-                        onResponseReceived.call(new InterpreterResponse(false, false));
+                    }
+
+                    public void handleCommand(String userInput,
+                            ICallback<Object, InterpreterResponse> onResponseReceived) {
+                        boolean more = false;
+                        if (userInput.endsWith(":") || userInput.endsWith("\\")) {
+                            more = true;
+                        }
+                        onResponseReceived.call(new InterpreterResponse(more, false));
                     }
 
                     public ICompletionProposal[] getTabCompletions(String commandLine, int cursorPosition) {
@@ -99,15 +104,29 @@ public class ScriptConsoleDocumentListenerTest extends TestCase {
                     public void setOnContentsReceivedCallback(
                             ICallback<Object, Tuple<String, String>> onContentsReceived) {
                     }
+
                 },
 
                 prompt, new ScriptConsoleHistory(), new ArrayList<IConsoleLineTracker>(), "",
-                new PyAutoIndentStrategy());
+                new PyAutoIndentStrategy(new IAdaptable() {
+
+                    @Override
+                    public Object getAdapter(Class adapter) {
+                        return null;
+                    }
+                }));
 
         PyAutoIndentStrategy strategy = (PyAutoIndentStrategy) listener.getIndentStrategy();
         strategy.setIndentPrefs(new TestIndentPrefs(true, 4));
         listener.setDocument(doc);
+    }
 
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testConsoleListener() throws Exception {
         doc.replace(0, 0, ">>> class A:");
         doc.replace(doc.getLength(), 0, "\n");
         //Things happen in a thread now, so, we have to wait for it to happen...
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FileStub.java b/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FileStub.java
deleted file mode 100644
index cdacb26..0000000
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/FileStub.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved.
- * Licensed under the terms of the Eclipse Public License (EPL).
- * Please see the license.txt included with this distribution for details.
- * Any modifications to this file must keep this entire header intact.
- */
-package org.python.pydev.navigator;
-
-import java.io.File;
-
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.Assert;
-import org.python.pydev.core.resource_stubs.AbstractIFileStub;
-
-public class FileStub extends AbstractIFileStub implements IFile {
-
-    private ProjectStub project;
-    protected File file;
-
-    public FileStub(ProjectStub project, File file) {
-        Assert.isTrue(file.exists() && file.isFile());
-        this.project = project;
-        this.file = file;
-    }
-
-    @Override
-    public String getName() {
-        return this.file.getName();
-    }
-
-    @Override
-    public IContainer getParent() {
-        return project.getFolder(this.file.getParentFile());
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((file == null) ? 0 : file.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final FileStub other = (FileStub) obj;
-        if (file == null) {
-            if (other.file != null) {
-                return false;
-            }
-        } else if (!file.equals(other.file)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return "FileStub:" + this.file;
-    }
-
-    @Override
-    public IProject getProject() {
-        return this.project;
-
-    }
-
-}
diff --git a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/PythonModelProviderTest.java b/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/PythonModelProviderTest.java
index 9c4d6b1..252e413 100644
--- a/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/PythonModelProviderTest.java
+++ b/plugins/org.python.pydev/tests_navigator/org/python/pydev/navigator/PythonModelProviderTest.java
@@ -32,6 +32,11 @@ import org.python.pydev.navigator.elements.PythonProjectSourceFolder;
 import org.python.pydev.navigator.elements.PythonSourceFolder;
 import org.python.pydev.plugin.nature.PythonNature;
 import org.python.pydev.shared_core.callbacks.ICallback;
+import org.python.pydev.shared_core.resource_stubs.FileStub;
+import org.python.pydev.shared_core.resource_stubs.FolderStub;
+import org.python.pydev.shared_core.resource_stubs.ProjectStub;
+import org.python.pydev.shared_core.resource_stubs.WorkingSetStub;
+import org.python.pydev.shared_core.resource_stubs.WorkspaceRootStub;
 
 @SuppressWarnings("unchecked")
 public class PythonModelProviderTest extends TestCase {
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 65786a2..b9b6d84 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.python.pydev</groupId>
     <artifactId>parent</artifactId>
-    <version>3.9.0-SNAPSHOT</version>
+    <version>3.9.2-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>plugins</artifactId>
diff --git a/pom.xml b/pom.xml
index 569f5bc..6ef14d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,16 +124,16 @@
 <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <properties>
-    <tycho-version>0.19.0</tycho-version>
-    <tycho-extras-version>0.19.0</tycho-extras-version>
+    <tycho-version>0.22.0</tycho-version>
+    <tycho-extras-version>0.22.0</tycho-extras-version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <repository.id>eclipse-juno</repository.id>
-    <repository.url>http://download.eclipse.org/releases/juno</repository.url>
+    <repository.id>eclipse-luna</repository.id>
+    <repository.url>http://download.eclipse.org/releases/luna</repository.url>
   </properties>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.python.pydev</groupId>
   <artifactId>parent</artifactId>
-  <version>3.9.0-SNAPSHOT</version>
+  <version>3.9.2-SNAPSHOT</version>
   <name>Pydev Build Parent</name>
   <packaging>pom</packaging>
   <modules>
@@ -153,18 +153,6 @@
         <artifactId>tycho-surefire-plugin</artifactId>
         <version>${tycho-version}</version>
         <configuration>
-          <dependencies>
-            <dependency>
-              <type>eclipse-feature</type>
-              <artifactId>org.python.pydev.feature</artifactId>
-              <version>0.0.0</version>
-            </dependency>
-            <dependency>
-              <type>eclipse-feature</type>
-              <artifactId>org.eclipse.jdt</artifactId>
-              <version>0.0.0</version>
-            </dependency>
-          </dependencies>
           <explodedBundles>
             <!-- pysrc is in org.python.pydev, so explode it -->
             <explodedBundle>org.python.pydev</explodedBundle>
@@ -210,6 +198,20 @@
         <artifactId>target-platform-configuration</artifactId>
         <version>${tycho-version}</version>
         <configuration>
+          <target>
+	    <extraRequirements>
+	    <requirement>
+              <type>eclipse-feature</type>
+              <artifactId>org.python.pydev.feature</artifactId>
+              <version>0.0.0</version>
+            </requirement>
+            <requirement>
+              <type>eclipse-feature</type>
+              <artifactId>org.eclipse.jdt</artifactId>
+              <version>0.0.0</version>
+            </requirement>
+	    </extraRequirements>
+	  </target>
           <environments>
             <environment>
               <os>linux</os>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/eclipse-pydev.git



More information about the pkg-java-commits mailing list