@@ -19,6 +19,8 @@
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.IToken;
import org.python.pydev.core.OrderedSet;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.CompletionRecursionException;
import org.python.pydev.core.structure.FastStack;
import org.python.pydev.editor.codecompletion.revisited.CompletionStateFactory;
@@ -131,47 +133,61 @@ private int isStaticOrClassMethod(FunctionDef functionDefinitionReferenced) {
@SuppressWarnings("unchecked")
/*default*/ void checkAttrFound(Call callNode, TokenFoundStructure found) throws Exception, CompletionRecursionException {
FunctionDef functionDefinitionReferenced;
IToken nameToken;
SourceToken nameToken;
boolean callingBoundMethod;
if (found != null && found.defined && found.token instanceof SourceToken) {
nameToken = found.token;
nameToken = (SourceToken) found.token;
String rep = nameToken.getRepresentation();

ArrayList<IDefinition> definition = new ArrayList<IDefinition>();
PyRefactoringFindDefinition.findActualDefinition(null, this.current, rep, definition, -1, -1,
this.nature, this.completionCache);
SimpleNode ast = nameToken.getAst();
try {
PyRefactoringFindDefinition.findActualDefinition(null, this.current, rep, definition, ast.beginLine, ast.beginColumn,
this.nature, this.completionCache);
} catch (Exception e) {
Log.log(e);
return;
}

for (IDefinition iDefinition : definition) {
Definition d = (Definition) iDefinition;
if (d.ast instanceof FunctionDef) {
functionDefinitionReferenced = (FunctionDef) d.ast;

if(rep.startsWith("self.")){
FastStack<SimpleNode> scopeStack = d.scope.getScopeStack();
if (scopeStack.size() > 0 && scopeStack.peek() instanceof ClassDef) {
callingBoundMethod = true;
}else{
callingBoundMethod = false;
}


String withoutLastPart = FullRepIterable.getWithoutLastPart(rep);
Boolean b = valToBounded.get(withoutLastPart);
if(b != null){
callingBoundMethod = b;
}else{
FastStack<SimpleNode> scopeStack = d.scope.getScopeStack();
if (scopeStack.size() > 1 && scopeStack.peek(1) instanceof ClassDef) {
callingBoundMethod = true;
String withoutLast = FullRepIterable.getWithoutLastPart(rep);
ArrayList<IDefinition> definition2 = new ArrayList<IDefinition>();
PyRefactoringFindDefinition.findActualDefinition(null, this.current, withoutLast, definition2,
-1, -1, this.nature, this.completionCache);
int count = StringUtils.count(rep, '.');

if(count == 1 && rep.startsWith("self.")){
FastStack<SimpleNode> scopeStack = d.scope.getScopeStack();
if (scopeStack.size() > 0 && scopeStack.peek() instanceof ClassDef) {
callingBoundMethod = true;
}else{
callingBoundMethod = false;
}

for (IDefinition iDefinition2 : definition2) {
Definition d2 = (Definition) iDefinition2;
if (d2.ast instanceof ClassDef) {
callingBoundMethod = false;
break;
}else{
FastStack<SimpleNode> scopeStack = d.scope.getScopeStack();
if (scopeStack.size() > 1 && scopeStack.peek(1) instanceof ClassDef) {
callingBoundMethod = true;
String withoutLast = FullRepIterable.getWithoutLastPart(rep);
ArrayList<IDefinition> definition2 = new ArrayList<IDefinition>();
PyRefactoringFindDefinition.findActualDefinition(null, this.current, withoutLast, definition2,
-1, -1, this.nature, this.completionCache);

for (IDefinition iDefinition2 : definition2) {
Definition d2 = (Definition) iDefinition2;
if (d2.ast instanceof ClassDef) {
callingBoundMethod = false;
break;
}
}
} else {
callingBoundMethod = false;
}
} else {
callingBoundMethod = false;
}
}
analyzeCallAndFunctionMatch(callNode, functionDefinitionReferenced, nameToken, callingBoundMethod);
@@ -350,4 +366,26 @@ private void onArgumentsMismatch(IToken node, Call callNode) {
this.messagesManager.onArgumentsMismatch(node, callNode);
}


private Map<String, Boolean> valToBounded = new HashMap<String, Boolean>();

public void visitAssign(Assign node) {
boolean bounded = false;
exprType[] targets = node.targets;
if(node.value != null){
if(node.value instanceof Call){
bounded = true;
}
}

if(targets != null){
int len = targets.length;
for(int i=0;i<len;i++){
exprType expr = targets[i];
valToBounded.put(NodeUtils.getFullRepresentationString(expr), bounded);
}
}

}

}
@@ -200,6 +200,10 @@ public Object visitAssign(Assign node) throws Exception {
isInTestScope+=1;
Object r = super.visitAssign(node);
isInTestScope-=1;

if(analyzeArgumentsMismatch){
argumentsChecker.visitAssign(node);
}
return r;
}

@@ -461,7 +465,7 @@ public Object call(Found f) {
}


public static class TokenFoundStructure{
public static final class TokenFoundStructure{

public final IToken token;
public final boolean defined;
@@ -39,7 +39,7 @@ public static void main(String[] args) {
try {
OccurrencesAnalyzer2Test analyzer2 = new OccurrencesAnalyzer2Test();
analyzer2.setUp();
analyzer2.testErrorNotShownOnDynamicClass4();
analyzer2.testParameterAnalysis27a();
analyzer2.tearDown();
System.out.println("finished");

@@ -784,7 +784,26 @@ public void testParameterAnalysis27() throws IOException{
" self.bounds.Method()\n" +
"\n"
);
checkError("self.Method: arguments don't match");
checkNoError();
}

public void testParameterAnalysis27a() throws IOException{
doc = new Document(
"class Bounds(object):\n" +
"\n" +
" def Method(self):\n" +
" pass\n" +
"\n" +
"class Bar(object):\n" +
"\n" +
" def __init__(self):\n" +
" self.Bounds = Bounds\n" +
"\n" +
" def testGetDiagonalLength(self):\n" +
" self.Bounds.Method()\n" +
"\n"
);
checkError("self.Bounds.Method: arguments don't match");
}


@@ -884,7 +903,7 @@ public void testParameterAnalysisOptimization5a() throws IOException{
);
checkNoError();
} finally {
unregisterFindDefinitionListener("Foo", "foo.Method", "foo", "foo"); //TODO: This must be improved!
unregisterFindDefinitionListener("Foo", "foo.Method", "foo"); //TODO: This must be improved!
}
}

@@ -913,7 +932,7 @@ public void testParameterAnalysisOptimization6() throws IOException{
);
checkError("foo.Method: arguments don't match");
} finally {
unregisterFindDefinitionListener("", "check.Foo", "foo.Method", "foo", "foo");
unregisterFindDefinitionListener("", "check.Foo", "foo.Method","foo");
}
}

@@ -38,7 +38,7 @@ public static void main(String[] args) {
try {
OccurrencesAnalyzerTest analyzer2 = new OccurrencesAnalyzerTest();
analyzer2.setUp();
analyzer2.testRelativeOnPy3();
analyzer2.testBuiltInAssignment7();
analyzer2.tearDown();
System.out.println("finished");

@@ -2880,7 +2880,7 @@ public void testBuiltInAssignment() {
GRAMMAR_TO_USE_FOR_PARSING = IPythonNature.GRAMMAR_PYTHON_VERSION_3_0;
doc = new Document(
"import os as list \n" +
"class Foo:\n" +
"def Foo():\n" +
" id = 10 \n" +
" for tuple in range(3): \n" +
" val = tuple \n" +
@@ -2944,6 +2944,45 @@ public void testBuiltInAssignment4() {
}


public void testBuiltInAssignment5() {
doc = new Document(
"class A:\n" +
" def open(self):\n" +
" pass" +
""
);
analyzer = new OccurrencesAnalyzer();
msgs = analyzeDoc();

printMessages(msgs, 0);
}

public void testBuiltInAssignment6() {
doc = new Document(
"class A:\n" +
" id = 10\n" +
""
);
analyzer = new OccurrencesAnalyzer();
msgs = analyzeDoc();

printMessages(msgs, 0);
}

public void testBuiltInAssignment7() {
doc = new Document(
"def call(**kwargs):\n" +
" pass\n" +
"call(id=10)\n" +
""
);
analyzer = new OccurrencesAnalyzer();
msgs = analyzeDoc();

printMessages(msgs, 0);
}


public void testRelativeOnPy3() throws IOException, MisconfigurationException {
int initial = GRAMMAR_TO_USE_FOR_PARSING;
try {
@@ -23,6 +23,7 @@
import org.python.pydev.core.TestDependent;
import org.python.pydev.core.callbacks.ICallback;
import org.python.pydev.core.structure.FastStringBuffer;
import org.python.pydev.editor.codecompletion.revisited.ProjectModulesManager;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.plugin.PydevTestUtils;
import org.python.pydev.ui.interpreters.PythonInterpreterManager;
@@ -59,11 +60,13 @@ protected void setUp() throws Exception {

PydevTestUtils.setTestPlatformStateLocation();
REF.IN_TESTS = true;
ProjectModulesManager.IN_TESTS = true;
}

@Override
protected void tearDown() throws Exception {
REF.deleteDirectoryTree(baseDir);
ProjectModulesManager.IN_TESTS = false;
}

public void testInterpreterInfoBuilder() throws Exception {
@@ -79,7 +79,7 @@ public void launchRemoved(ILaunch launch) {

public void processCommand(String sCmdCode, String sSeqCode, String payload) {
if(Integer.parseInt(sCmdCode) == AbstractDebuggerCommand.CMD_WRITE_TO_CONSOLE){
ProcessServer serverProcess = ((RemoteDebuggerServer)debugger).getServerProcess();
ProcessServer serverProcess = getDebugger().getServerProcess();

//payload = <xml><io s="%s" ctx="%s"/></xml>
Tuple<String,Integer> message = XMLMessage.getMessage(payload);
@@ -93,8 +93,13 @@ public void processCommand(String sCmdCode, String sSeqCode, String payload) {
}
}

public RemoteDebuggerServer getDebugger()
{
return (RemoteDebuggerServer)super.getDebugger();
}

public IProcess getProcess() {
return ((RemoteDebuggerServer)debugger).getIProcess();
return getDebugger().getIProcess();
}


@@ -11,7 +11,7 @@
version = arg[len('--version='):]
LAST_VERSION_TAG = version
else:
LAST_VERSION_TAG = '2.4.0' #Not specified (let's leave one there)
LAST_VERSION_TAG = '2.5.0' #Not specified (let's leave one there)


import build_python_code_block
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -2,6 +2,27 @@ History For PyDev
~~~~~~~~~~~~~~~~~


Release 2.3.0
===============

* **Pep8.py** integrated (must be enabled in PyDev > Editor > Code Analysis > pep8.py).

* **Faster PyDev startup** (internal Jython upgraded to version 2.2.1 -- and also optimized for PyDev).

* Action to select/deselect scope (**Shift+Alt+Up/Down**).

* Fix: cache issue where the PYTHONPATH in memory became different from the PYTHONPATH configured for a project.

* Fix: OutOfMemoryError when dealing with PyOpenGL.

* Fix: deadlock (could occur in a race condition when importing a project with an existing Python configuration).

* Fix: code-completion integration issue with IPython 011 (patch from jonahkichwacoders).

* Fix: annotation could remain in editor after removing a marker.

* Fix: BadLocationException on extract local refactoring.


Release 2.2.4
===============
@@ -110,6 +110,42 @@ Important
First time users are strongly advised to read the `Getting started guide`_ which explains how to properly configure PyDev


Release 2.5.0
===============


* **Django**:

* Project wizard now properly supports Django 1.4.

* **Django with auto-reload**:

* pydevd.patch_django_autoreload() now properly patches Django 1.4 for the remote debugger.
* pydevd.patch_django_autoreload() now patches the Django reload to show a console out of Eclipse so that Ctrl+C can be used.
* Created code template to pydevd.patch_django_autoreload().

* **Interactive Console**:

* The interactive console may be attached to the variables view (patch from Jonah Graham).
See: `Interactive console`_ for details.
* Drag and Drop may be used to drag code from the editor to the interactive console (patch from Jonah Graham).
* When starting an interactive console, a link to configure the preferences is shown in the dialog.

* **Code formatter**:

* Multi-lines may be right-trimmed (patch from Haw-Bin Chai) -- option must be enabled in the code-formatting settings.
* Fixed issue where the auto code-formatting would end up formatting strings as regular code when the "format only changed lines" setting was on.

* **Others**:

* pydevd.settrace() template now adds the debugger to the PYTHONPATH before actually doing the settrace().
* ${pydevd_file_location} and ${pydevd_dir_location} variables were added to the templates.
* The style of generated docstrings (EpyDoc or Sphinx) may be chosen in the preferences (patch from Paul Collins).
* Some performance improvements were done on the parser.

Aside from the features above, **lots** of bugs were fixed in this release (including a deadlock in a race condition).



Release 2.4.0
===============
@@ -140,31 +176,6 @@ The contents of the homepage are now migrated to a wiki at https://wiki.appceler



Release 2.3.0
===============

* **Pep8.py** integrated (must be enabled in PyDev > Editor > Code Analysis > pep8.py).

* **Faster PyDev startup** (internal Jython upgraded to version 2.2.1 -- and also optimized for PyDev).

* Action to select/deselect scope (**Shift+Alt+Up/Down**).

* Fix: cache issue where the PYTHONPATH in memory became different from the PYTHONPATH configured for a project.

* Fix: OutOfMemoryError when dealing with PyOpenGL.

* Fix: deadlock (could occur in a race condition when importing a project with an existing Python configuration).

* Fix: code-completion integration issue with IPython 011 (patch from jonahkichwacoders).

* Fix: annotation could remain in editor after removing a marker.

* Fix: BadLocationException on extract local refactoring.





Development Info
====================================

@@ -52,9 +52,11 @@
<p><b>Code:</b></p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="theme: Default; brush: python; gutter: false"><![CDATA[import sys
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">sys</span>

<span style="color: #008000; font-weight: bold">print</span> sys<span style="color: #666666">.</span>cachedir
</pre></div>

print sys.cachedir]]></script>
</div></div>

</div>
@@ -124,26 +124,28 @@ <h1><a name="PyDevInterpreterConfiguration-PredefinedCompletions"></a><a name="P
<p> Example for a <b>my.source.module</b> (must be declared in a <b>my.source.module.pypredef</b> file):</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="theme: Default; brush: python; gutter: false"><![CDATA[MyConstantA = int
MyConstantB = int
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%">MyConstantA <span style="color: #666666">=</span> <span style="color: #008000">int</span>
MyConstantB <span style="color: #666666">=</span> <span style="color: #008000">int</span>

class MyClass:
<span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">MyClass</span>:

instanceAttribute = QObject
instanceAttribute <span style="color: #666666">=</span> QObject

def __init__(self, parent=None):
'''
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__init__</span>(<span style="color: #008000">self</span>, parent<span style="color: #666666">=</span><span style="color: #008000">None</span>):
<span style="color: #BA2121; font-style: italic">&#39;&#39;&#39;</span>
<span style="color: #BA2121; font-style: italic"> </span>
<span style="color: #BA2121; font-style: italic"> @type parent: QObject</span>
<span style="color: #BA2121; font-style: italic"> &#39;&#39;&#39;</span>

@type parent: QObject
'''
def registerTimer(interval, object):
'''
@type interval: int
@type object: QObject
'''
return int]]></script>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">registerTimer</span>(interval, <span style="color: #008000">object</span>):
<span style="color: #BA2121; font-style: italic">&#39;&#39;&#39;</span>
<span style="color: #BA2121; font-style: italic"> </span>
<span style="color: #BA2121; font-style: italic"> @type interval: int</span>
<span style="color: #BA2121; font-style: italic"> @type object: QObject</span>
<span style="color: #BA2121; font-style: italic"> &#39;&#39;&#39;</span>
<span style="color: #008000; font-weight: bold">return</span> <span style="color: #008000">int</span>
</pre></div>

</div></div>
<p> <b>Note 1</b>: the name of the file is the exact name of the module</p>

@@ -6,8 +6,10 @@
<p>For that, we will extend the module we created in the previous chapter with the following program:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="theme: Default; brush: python; gutter: false"><![CDATA[if __name__ == '__main__':
print 'Hello World']]></script>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">if</span> __name__ <span style="color: #666666">==</span> <span style="color: #BA2121">&#39;__main__&#39;</span>:
<span style="color: #008000; font-weight: bold">print</span> <span style="color: #BA2121">&#39;Hello World&#39;</span>
</pre></div>

</div></div>
<p>Then, to run the file you can:</p>

@@ -79,12 +79,14 @@ <h1><a name="PyDevCodeAnalysis-Passinginfotocodeanalysis"></a>Passing info to co
<p> <b>Example:</b></p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="theme: Default; brush: python; gutter: false"><![CDATA[class Struct:
'''Attributes passed in constructor.
*@DynamicAttrs*
'''
def __init__(self, *entries):
self.__dict__.update(entries)]]></script>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">class</span> <span style="color: #0000FF; font-weight: bold">Struct</span>:
<span style="color: #BA2121; font-style: italic">&#39;&#39;&#39;Attributes passed in constructor.</span>
<span style="color: #BA2121; font-style: italic"> *@DynamicAttrs*</span>
<span style="color: #BA2121; font-style: italic"> &#39;&#39;&#39;</span>
<span style="color: #008000; font-weight: bold">def</span> <span style="color: #0000FF">__init__</span>(<span style="color: #008000">self</span>, <span style="color: #666666">*</span>entries):
<span style="color: #008000">self</span><span style="color: #666666">.</span>__dict__<span style="color: #666666">.</span>update(entries)
</pre></div>

</div></div>
</div>
<br/><br/><a href="https://wiki.appcelerator.org/display/tis/PyDev+Code+Analysis">See wiki page</a>
@@ -6,11 +6,11 @@ <h1><a name="PyDevDjango-Django"></a>Django</h1>

<h1><a name="PyDevDjango-Prerequisites"></a>Pre-requisites</h1>

<p>To get started with Django in PyDev, the pre-requisite is that Django is installed in the Python/Jython/IronPython interpreter you want to use (so, "import django" must properly work).</p>
<p>To get started with Django in PyDev, the pre-requisite is that Django is installed in the Python / Jython / IronPython interpreter you want to use (so, "import django" must properly work &#8211; if you're certain that Django is there and PyDev wasn't able to find it during the install process, you must go to the interpreter configuration and reconfigure your interpreter so that PyDev can detect the change you did after adding Django).</p>

<p>If you don't have Django installed, follow the steps from <a href="http://www.djangoproject.com/" class="external-link" rel="nofollow">http://www.djangoproject.com/</a>.</p>

<p>Note that this tutorial won't teach you Django, only how the Django integration is available in PyDev, so, if you're not familiar with Django, it's useful to learn a bit about how it works and then use this help to know how the PyDev Django integration can help you. </p>
<p>Note that this tutorial won't teach you Django. It'll only show how the Django integration is available in PyDev, so, if you're not familiar with Django, it's useful to learn a bit about how it works and then use this help to know how the PyDev Django integration can help you. </p>


<h1><a name="PyDevDjango-Abitoninternals"></a>A bit on internals</h1>
@@ -19,11 +19,11 @@ <h1><a name="PyDevDjango-Abitoninternals"></a>A bit on internals</h1>

<p>1. The project must be marked as a Django project inside of PyDev.</p>

<p>2. A 'DJANGO_MANAGE_LOCATION' string substitution variable must point to the project-relative location of manage.py.</p>
<p>2. A <b>DJANGO_MANAGE_LOCATION</b> string substitution variable must point to the project-relative location of manage.py.</p>

<p>3. A 'DJANGO_SETTINGS_MODULE' string substitution variable must contain the name of the settings module in that project.</p>
<p>3. A <b>DJANGO_SETTINGS_MODULE</b> string substitution variable must contain the name of the settings module in that project.</p>

<p>And that's it, with those properly configured, all the Django-related actions should work (and the steps below will explain how those can be configured).</p>
<p>And that's it, with those properly configured, all the Django-related actions should work (provided the project is already configured as a Django project, there's an UI to configure those settings in the project properties: right-click your <b>project &gt; properties &gt; PyDev - Django</b>)</p>


<h1><a name="PyDevDjango-Creatinganewproject"></a>Creating a new project</h1>
@@ -76,13 +76,43 @@ <h1><a name="PyDevDjango-Run%2FDebugasDjango"></a>Run/Debug as Django</h1>

<p>This will create a default Run configuration, so, you may edit it later through run &gt; run configurations (or debug &gt; debug configurations) if you want to change a parameter.</p>

<p>Note: to know how to rerun the last launch see: Rerun Last Launch on Launching_</p>
<p>Note: to know how to rerun the last launch see: the <b>Rerun Last Launch</b> topic on <a href="manual_adv_launch.html" title="PyDev Launching">PyDev Launching</a></p>

<p>Note 2: if the --noreload is not passed, only the parent process will be killed from Eclipse and the others will only be killed when they'd be reloaded (i.e.: on a code-change). </p>

<h1><a name="PyDevDjango-Run%2FDebugasDjangowithautoreload"></a>Run/Debug as Django with autoreload</h1>
<h1><a name="PyDevDjango-RunDjangowithautoreload"></a>Run Django with autoreload</h1>

<p>If you don't want to se the --noreload flag, please take a look at the <a href="manual_adv_remote_debugger.html" title="PyDev Remote Debugger">Remote Debugger</a> for instructions on how to make the debugging work properly with the auto reload feature.</p>
<p>It's possible to run Django using it's auto-reload feature, but as stated above, doing so by default will have a bad side effect in which it'll actually leave spawned processes alive in the auto-reload. A workaround is provided by doing:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pydevd</span>
pydevd<span style="color: #666666">.</span>patch_django_autoreload(
patch_remote_debugger<span style="color: #666666">=</span><span style="color: #008000">False</span>, <span style="color: #408080; font-style: italic">#Note that the remote debugger patch setting should be False on a regular run</span>
patch_show_console<span style="color: #666666">=</span><span style="color: #008000">True</span>
)
</pre></div>

</div></div>

<p>just <b>before</b> the <b>if _<em>name</em>_ == "_<em>main</em>_":</b> in your manage.py module.</p>

<p>This will make the spawned children processes have their own console outside of Eclipse, where Ctrl+C may be properly used to kill the Django process (don't forget to remove the --noreload that PyDev added automatically to the launch configuration).</p>

<h1><a name="PyDevDjango-DebugDjangowithautoreload"></a>Debug Django with autoreload</h1>

<p>To debug Django with the autoreload feature, the <a href="manual_adv_remote_debugger.html" title="PyDev Remote Debugger">Remote Debugger</a> must be used and a patch must be applied to your code (just <b>before</b> the <b>if _<em>name</em>_ == "_<em>main</em>_":</b> in your manage.py module):</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pydevd</span>
pydevd<span style="color: #666666">.</span>patch_django_autoreload(
patch_remote_debugger<span style="color: #666666">=</span><span style="color: #008000">True</span>, <span style="color: #408080; font-style: italic">#Connect to the remote debugger.</span>
patch_show_console<span style="color: #666666">=</span><span style="color: #008000">True</span>
)
</pre></div>

</div></div>

<p>So, doing that, starting the remote debugger and making a regular run should enable all the regular breakpoints that are put inside Eclipse to work in the Django process with the Remote Debugger (don't forget to remove the --noreload that PyDev added automatically to the launch configuration).</p>
</div>
<br/><br/><a href="https://wiki.appcelerator.org/display/tis/PyDev+Django">See wiki page</a>
</contents_area>
@@ -3,6 +3,20 @@
<div id="Content" style="padding: 5px;">
<h1><a name="PyDevInteractiveConsole-InteractiveConsole"></a>Interactive Console</h1>

<h2><a name="PyDevInteractiveConsole-NewonPyDev2.5.0%3AInteractionwithVariablesView"></a>New on PyDev 2.5.0: Interaction with Variables View</h2>

<p>From PyDev 2.5.0 onwards, the interactive console may be connected to the variables/expressions view (as if it was a debug process... but without breakpoints).</p>

<p>To enable that feature, go to window &gt; preferences &gt; PyDev &gt; Interactive Console and check 'Connect console to Variables Debug View?'.</p>

<p><span class="image-wrap" style=""><img src="http://pydev.org/images/interactiveconsole/interactive_console_variables_view_preference.png" style="border: 1px solid black" /></span></p>

<p>With that setting in place, when a new interactive console is created and the debug perspective is shown, it's possible to see the variables available in the console through the variables view and even add expressions to be resolved in the expressions view.</p>

<p><span class="image-wrap" style=""><img src="http://pydev.org/images/interactiveconsole/interactive_console_variables_view.png" style="border: 1px solid black" /></span></p>


<h2><a name="PyDevInteractiveConsole-UsingtheInteractiveConsole"></a>Using the Interactive Console</h2>

<p><b>Note</b>: From PyDev 2.2.2 onwards, if IPython (0.10 or 0.11) is found in the PYTHONPATH, <br/>
PyDev will use it as the backend for the console.</p>
@@ -58,11 +58,13 @@ <h1><a name="PyDevRemoteDebugger-Djangoremotedebuggingwithautoreload"></a>Django
<p>To do that, edit the launch that PyDev created (run &gt; run configurations &gt; PyDev Django) and remove the noreload flag and edit your manage.py so that the lines:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="theme: Default; brush: python; gutter: false"><![CDATA[#Add pydevd to the PYTHONPATH (may be skipped if that path is already added in the PyDev configurations)
import sys;sys.path.append(r'path_to\pydev\plugins\org.python.pydev.debug\pysrc')
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%"><span style="color: #408080; font-style: italic">#Add pydevd to the PYTHONPATH (may be skipped if that path is already added in the PyDev configurations)</span>
<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">sys</span>;sys<span style="color: #666666">.</span>path<span style="color: #666666">.</span>append(<span style="color: #BA2121">r&#39;path_to\pydev\plugins\org.python.pydev.debug\pysrc&#39;</span>)

<span style="color: #008000; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">pydevd</span>
pydevd<span style="color: #666666">.</span>patch_django_autoreload()
</pre></div>

import pydevd
pydevd.patch_django_autoreload()]]></script>
</div></div>

<p>are added <b>BEFORE</b> the <b>if _<em>name</em>_ == "_<em>main</em>_"</b>. Note: this was added in PyDev 2.1.1.</p>
@@ -12,10 +12,16 @@ d:\bin\Python265\python.exe W:\git_deploy_dir\pydev_uploader.py -s W:\git_deploy

Update homepage
- index.rst
- history_pydev.contents.html if needed
- history_pydev.rst (move contents from index.rst if needed)

Run:
- W:\ConfluenceWikiAndRST\src\pydev_wiki_to_rst.py to update the contents from the homepage from the wiki.
- Update version at W:\pydev\plugins\com.python.pydev.docs\build_both.py
- W:\pydev\plugins\com.python.pydev.docs\build_both.py

Update the versions on org.python.pydev.build/build_local.properties
Commit everything
Merge with release
Merge with master_pydev

Execute the build_cmd.txt in cmd.exe
@@ -40,7 +46,7 @@ del W:\git_update_site_dir\updates\content.jar
Update artifacts.jar and content.jar


D:\bin\eclipse_36_final_clean\eclipse.exe -application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator -updateSite W:\git_update_site_dir\updates\ -site file:W:\git_update_site_dir\updates\site.xml -metadataRepository file:W:\git_update_site_dir\updates -metadataRepositoryName "PyDev Update Site" -artifactRepository file:W:\git_update_site_dir\updates -artifactRepositoryName "PyDev Artifacts" -publishArtifacts -publishArtifactRepository -compress -reusePack200Files -noDefaultIUs -vmargs -Xmx256m
D:\bin\eclipse_371_final_clean\eclipse.exe -application org.eclipse.equinox.p2.publisher.EclipseGenerator -updateSite W:\git_update_site_dir\updates\ -site file:W:\git_update_site_dir\updates\site.xml -metadataRepository file:W:\git_update_site_dir\updates -metadataRepositoryName "PyDev Update Site" -artifactRepository file:W:\git_update_site_dir\updates -artifactRepositoryName "PyDev Artifacts" -publishArtifacts -publishArtifactRepository -compress -reusePack200Files -noDefaultIUs -vmargs -Xmx256m


** Copy site.xml, artifacts.jar and content.jar to W:\git_deploy_dir\Pydev
@@ -78,7 +84,9 @@ d:\bin\Python265\python.exe W:\git_deploy_dir\pydev_uploader.py -s W:\git_deploy
W:\pydev\plugins\com.python.pydev.docs\merged_homepage\final to 173.45.225.54 (/var/www)


** Tag repository: git tag pydev_2_4_0 -a&git push --tags
** Tag repository:
git tag pydev_2_5_0 -a
git push --tags

** Add news in forum (same as e-mail)

@@ -88,4 +96,4 @@ W:\pydev\plugins\com.python.pydev.docs\merged_homepage\final to 173.45.225.54 (/

** Add blog post / twitter


** Update the versions on org.python.pydev.build/build_local.properties to the next build

Large diffs are not rendered by default.

@@ -51,6 +51,7 @@ protected boolean getCompiledModulesEnabled() {

public void tearDown() throws Exception {
CompiledModule.COMPILED_MODULES_ENABLED = true;
AbstractPyRefactoring.setPyRefactoring(null);
super.tearDown();
}

@@ -0,0 +1,131 @@
/**
* Copyright (c) 2005-2011 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 com.python.pydev.refactoring.tdd;

import java.util.List;

import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.python.pydev.core.TestDependent;
import org.python.pydev.core.callbacks.ICallback;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.CompletionRecursionException;
import org.python.pydev.editor.codecompletion.PyCodeCompletion;
import org.python.pydev.editor.codecompletion.revisited.CodeCompletionTestsBase;
import org.python.pydev.editor.codecompletion.revisited.modules.CompiledModule;
import org.python.pydev.editor.refactoring.AbstractPyRefactoring;

import com.python.pydev.refactoring.refactorer.Refactorer;

/**
* @author Fabio
*
*/
public class TddCodeGenerationQuickFixParticipantTest extends CodeCompletionTestsBase {

public static void main(String[] args) {

try {
//DEBUG_TESTS_BASE = true;
TddCodeGenerationQuickFixParticipantTest test = new TddCodeGenerationQuickFixParticipantTest();
test.setUp();
test.testDontCreate();
test.tearDown();
System.out.println("Finished");

junit.textui.TestRunner.run(TddCodeGenerationQuickFixParticipantTest.class);
} catch(Throwable e){
e.printStackTrace();
}
}

/*
* @see TestCase#setUp()
*/
public void setUp() throws Exception {
super.setUp();
AbstractPyRefactoring.setPyRefactoring(new Refactorer());
CompiledModule.COMPILED_MODULES_ENABLED = false;
this.restorePythonPath(
TestDependent.GetCompletePythonLib(true)+"|"+
TestDependent.PYTHON_PIL_PACKAGES+"|"+
TestDependent.TEST_PYSRC_LOC+"configobj-4.6.0-py2.6.egg",
false
);

this.restorePythonPath(false);
codeCompletion = new PyCodeCompletion();
TddCodeGenerationQuickFixParticipant.onGetTddPropsError = new ICallback<Boolean, Exception>() {

public Boolean call(Exception e) {
throw new RuntimeException("Error:"+Log.getExceptionStr(e));
}
};
PyCodeCompletion.onCompletionRecursionException = new ICallback<Object, CompletionRecursionException>(){

public Object call(CompletionRecursionException e) {
throw new RuntimeException("Recursion error:"+Log.getExceptionStr(e));
}

};
}

/*
* @see TestCase#tearDown()
*/
public void tearDown() throws Exception {
CompiledModule.COMPILED_MODULES_ENABLED = true;
super.tearDown();
AbstractPyRefactoring.setPyRefactoring(null);
PyCodeCompletion.onCompletionRecursionException = null;
}

public void testCreate() throws Exception {
String s = "" +
"class MyClass(object):\n" +
" pass\n" +
"\n" +
"def makeTestObj():\n" +
" return MyClass()\n" +
"\n" +
"def makeTestObj2():\n" +
" return makeTestObj()\n" +
"\n" +
"def testName():\n" +
" obj = makeTestObj2()\n" +
" obj.unimplementedFunction()\n" +
"";
TddCodeGenerationQuickFixParticipant participant = new TddCodeGenerationQuickFixParticipant();
Document doc = new Document(s);
List<ICompletionProposal> props = participant.getTddProps(new PySelection(doc, s.length()-1), null, null, nature, null, s.length()-1, null);
assertContains("Create unimplementedFunction method at MyClass (__module_not_in_the_pythonpath__)", props.toArray(new ICompletionProposal[0]));
}

public void testDontCreate() throws Exception {
String s = "" +
"class MyClass(object):\n" +
"\n" +
" def unimplementedFunction(self):\n" +
" pass\n" +
"\n" +
"def makeTestObj():\n" +
" return MyClass()\n" +
"\n" +
"def makeTestObj2():\n" +
" return makeTestObj()\n" +
"\n" +
"def testName():\n" +
" obj = makeTestObj2()\n" +
" obj.unimplementedFunction()\n" +
"";
TddCodeGenerationQuickFixParticipant participant = new TddCodeGenerationQuickFixParticipant();
Document doc = new Document(s);
List<ICompletionProposal> props = participant.getTddProps(new PySelection(doc, s.length()-1), null, null, nature, null, s.length()-1, null);
assertNotContains("Create unimplementedFunction method at MyClass (__module_not_in_the_pythonpath__)", props.toArray(new ICompletionProposal[0]));
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -16,6 +16,7 @@
import org.python.pydev.debug.ui.DebuggerTestWorkbench;
import org.python.pydev.debug.ui.SourceLocatorTestWorkbench;
import org.python.pydev.debug.ui.launching.PythonRunnerConfigTestWorkbench;
import org.python.pydev.dltk.console.codegen.StructuredSelectionGeneratorTestWorkbench;
import org.python.pydev.editor.PyEditTitleTestWorkbench;
import org.python.pydev.editor.codecompletion.revisited.javaintegration.JavaClassModuleTestWorkbench;
import org.python.pydev.editor.codecompletion.revisited.jython.JythonCompletionWithBuiltinsTestWorkbench;
@@ -30,36 +31,39 @@

public class AllWorkbenchTests {



public static Test suite() {
TestSuite suite = new TestSuite(AllWorkbenchTests.class.getName());


//Must be 1st (no nature or interpreter configured)
suite.addTestSuite(SaveFileWithoutNatureTestWorkbench.class);
suite.addTestSuite(ProjectImportedHasAstManagerTestWorkbench.class);
addTestSuite(suite, SaveFileWithoutNatureTestWorkbench.class);
addTestSuite(suite, ProjectImportedHasAstManagerTestWorkbench.class);
//End the ones that must be 1st (no nature or interpreter configured)


suite.addTestSuite(AnalysisRequestsTestWorkbench.class);
suite.addTestSuite(PyEditTitleTestWorkbench.class);
suite.addTestSuite(TddTestWorkbench.class);
addTestSuite(suite, AnalysisRequestsTestWorkbench.class);
addTestSuite(suite, PyEditTitleTestWorkbench.class);
addTestSuite(suite, TddTestWorkbench.class);


suite.addTestSuite(JythonCompletionWithBuiltinsTestWorkbench.class);
suite.addTestSuite(JythonFindDefinitionTestWorkbench.class);
suite.addTestSuite(JavaClassModuleTestWorkbench.class);
suite.addTestSuite(JavaIntegrationPydevComTestWorkbench.class);
suite.addTestSuite(PythonRunnerConfigTestWorkbench.class);
suite.addTestSuite(SourceLocatorTestWorkbench.class);
suite.addTestSuite(AppEngineConfigWizardPageTestWorkbench.class);
addTestSuite(suite, JythonCompletionWithBuiltinsTestWorkbench.class);
addTestSuite(suite, JythonFindDefinitionTestWorkbench.class);
addTestSuite(suite, JavaClassModuleTestWorkbench.class);
addTestSuite(suite, JavaIntegrationPydevComTestWorkbench.class);
addTestSuite(suite, PythonRunnerConfigTestWorkbench.class);
addTestSuite(suite, SourceLocatorTestWorkbench.class);
addTestSuite(suite, AppEngineConfigWizardPageTestWorkbench.class);

suite.addTestSuite(PydevRemoteDebuggerServerTestWorkbench.class);
suite.addTestSuite(DebuggerTestWorkbench.class);
addTestSuite(suite, PydevRemoteDebuggerServerTestWorkbench.class);
addTestSuite(suite, DebuggerTestWorkbench.class);

suite.addTestSuite(PyUnitViewTestTestWorkbench.class);
suite.addTestSuite(PyUnitView2TestTestWorkbench.class);
addTestSuite(suite, PyUnitViewTestTestWorkbench.class);
addTestSuite(suite, PyUnitView2TestTestWorkbench.class);

suite.addTestSuite(PyCodeCoverageTestWorkbench.class);
addTestSuite(suite, PyCodeCoverageTestWorkbench.class);
addTestSuite(suite, StructuredSelectionGeneratorTestWorkbench.class);

if (suite.countTestCases() == 0) {
throw new Error("There are no test cases to run");
@@ -68,4 +72,12 @@ public static Test suite() {
}
}

private static void addTestSuite(TestSuite suite, Class<?> testClass) {
//Uncomment to filter which tests should actually be run.
// if(!testClass.getName().contains("AppEngineConfigWizardPageTestWorkbench")){
// return;
// }
suite.addTestSuite(testClass);
}

}
@@ -29,19 +29,17 @@
import org.eclipse.ui.console.IConsoleConstants;
import org.eclipse.ui.console.IConsoleView;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.FastStringBuffer;
import org.python.pydev.debug.newconsole.PydevConsole;
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.dltk.console.codegen.PythonSnippetUtils;
import org.python.pydev.dltk.console.ui.ScriptConsole;
import org.python.pydev.dltk.console.ui.internal.ScriptConsoleViewer;
import org.python.pydev.dltk.console.ui.internal.actions.IInteractiveConsoleConstants;
import org.python.pydev.editor.IPyEditListener;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.runners.SimpleRunner;

/**
* This class will setup the editor so that we can create interactive consoles, send code to it or make an execfile.
@@ -76,13 +74,10 @@ public void run(){
cmd = "\n"+cmd;
}
}
console = factory.createConsole(cmd);
factory.createConsole(cmd);


}else{
//Note: we can't use the return of the console from the createConsole() at this point
//because the viewer is still not properly set up (i.e.: console.getViewer() == null)
//So, if we had something to send to the user, it would be sent in the initial commands.
if(console instanceof PydevConsole){
//ok, console available
sendCommandToConsole(selection, console, this.edit);
@@ -133,29 +128,12 @@ private static String getCommandToSend(PyEdit edit, PySelection selection) {
File editorFile = edit.getEditorFile();

if(editorFile != null){
String fileStr = SimpleRunner.getArgumentsAsStr(new String[]{editorFile.toString()});

char[] characters = fileStr.trim().toCharArray();
FastStringBuffer buf = new FastStringBuffer(characters.length+characters.length/2);
for (int i = 0; i < characters.length; i++) {
char character= characters[i];
if (character == '\\') {
buf.append("\\");
}
buf.append(character);
}
if(buf.startsWith('"')){
buf.deleteFirst();
}
if(buf.endsWith('"')){
buf.deleteLast();
}
cmd = StringUtils.format("execfile('%s')\n", buf.toString());
cmd = PythonSnippetUtils.getExecfileCommand(editorFile);
}
}
return cmd;
}

/**
* @param consoleType the console type we're searching for
* @return the currently active console.
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="lib/jpathwatch-0-94.jar"/>
<classpathentry exported="true" kind="lib" path="commons-codec.jar"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="tests"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="lib/jpathwatch-0-94.jar"/>
<classpathentry exported="true" kind="lib" path="commons-codec.jar"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="src" path="tests"/>
<classpathentry kind="output" path="bin"/>
</classpath>
@@ -81,50 +81,49 @@ public static IExtension[] getExtensions(String type) {
return extensions;
}

@SuppressWarnings("unchecked")
public static Object getParticipant(String type) {
//only one participant may be used for this
/**
* @param type the name of the extension
* @param allowOverride if true, the last registered participant will be
* returned, thus "overriding" any previously
* registered participants. If false, an exception
* is thrown if more than one participant is
* registered.
* @return the participant for the given extension type, or null if none
* is registered.
*/
public static Object getParticipant(String type, boolean allowOverride) {
List<Object> participants = getParticipants(type);
if(participants.size() == 1){
return participants.get(0);
}

if(participants.size() == 0){
if (participants.isEmpty()){
return null;
}

if(participants.size() > 1){
if (!allowOverride && participants.size() > 1) {
// only one participant may be used for this
throw new RuntimeException("More than one participant is registered for type:"+type);
}

throw new RuntimeException("Should never get here!");

return participants.get(participants.size() - 1);
}

/**
* @param type the extension we want to get
* @return a list of classes created from those extensions
*/
@SuppressWarnings("unchecked")
public static List getParticipants(String type) {
if(testingParticipants != null){
List<Object> list = testingParticipants.get(type);
if(list == null){
list = new ArrayList();
List<Object> list = null;
if (testingParticipants != null) {
list = testingParticipants.get(type);
if (list == null) {
list = new ArrayList<Object>();
}
return list;
return list;
}

ArrayList list = new ArrayList();
IExtension[] extensions = getExtensions(type);

list = new ArrayList<Object>();
// For each extension ...
for (int i = 0; i < extensions.length; i++) {
IExtension extension = extensions[i];
IConfigurationElement[] elements = extension.getConfigurationElements();
for (IExtension extension : getExtensions(type)) {
IConfigurationElement[] elements = extension
.getConfigurationElements();
// For each member of the extension ...
for (int j = 0; j < elements.length; j++) {
IConfigurationElement element = elements[j];

for (IConfigurationElement element : elements) {
try {
list.add(element.createExecutableExtension("class"));
} catch (Exception e) {
@@ -134,6 +133,4 @@ public static List getParticipants(String type) {
}
return list;
}


}
@@ -13,6 +13,7 @@
import java.util.List;

import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.structure.FastStringBuffer;

/**
* iterates through a string so that parts of it are gotten each time in a progressive way based on dots
@@ -236,7 +237,7 @@ public static String getWithoutFirstPart(String currentModuleName) {


public static String joinParts(List<String> actToks, int parts) {
StringBuffer buffer = new StringBuffer();
FastStringBuffer buffer = new FastStringBuffer();
for (int i = 0; i < parts; i++) {
if(i > 0){
buffer.append('.');
@@ -11,6 +11,8 @@

import java.io.Serializable;

import org.python.pydev.core.structure.FastStringBuffer;

/**
* Defines a tuple of some object, adding equals and hashCode operations
*
@@ -80,11 +82,11 @@ public int hashCode() {

@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
FastStringBuffer buffer = new FastStringBuffer();
buffer.append("Tuple [");
buffer.append(o1);
buffer.appendObject(o1);
buffer.append(" -- ");
buffer.append(o2);
buffer.appendObject(o2);
buffer.append("]");
return buffer.toString();
}
@@ -16,6 +16,7 @@

import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.docutils.StringUtils.ICallbackOnSplit;
import org.python.pydev.core.structure.FastStringBuffer;

/**
* This class defines the key to use for some module. All its operations are based on its name.
@@ -85,9 +86,9 @@ public int hashCode() {
@Override
public String toString() {
if(file != null){
StringBuffer ret = new StringBuffer(name);
FastStringBuffer ret = new FastStringBuffer(name, 40);
ret.append(" - ");
ret.append(file);
ret.appendObject(file);
return ret.toString();
}
return name;
@@ -8,6 +8,8 @@

import java.io.File;

import org.python.pydev.core.structure.FastStringBuffer;

/**
* This is the modules key that should be used if we have an entry in a zip file.
*
@@ -49,10 +51,10 @@ public ModulesKeyForZip(String name, File f, String zipModulePath, boolean isFil

@Override
public String toString() {
StringBuffer ret = new StringBuffer(name);
FastStringBuffer ret = new FastStringBuffer(name, 40);
if(file != null){
ret.append(" - ");
ret.append(file);
ret.appendObject(file);
}
if(zipModulePath != null){
ret.append(" - zip path:");
@@ -100,7 +100,7 @@ public static String internUnsynched(String o){
/**
* Class used to store items interned locally in a map (without weak references)
*/
public static class ObjectsPoolMap extends HashMap<String, String>{
public static final class ObjectsPoolMap extends HashMap<String, String>{

private static final long serialVersionUID = 1L;

@@ -161,11 +161,15 @@ public static String getFileContents(File file) {
return (String) getFileContentsCustom(file, String.class);
}

public static Object getFileContentsCustom(File file, Class<? extends Object> returnType) {
return getFileContentsCustom(file, null, returnType);
}

/**
* @param file the file we want to read
* @return the contents of the file as a string
*/
public static Object getFileContentsCustom(File file, Class<? extends Object> returnType) {
public static Object getFileContentsCustom(File file, String encoding, Class<? extends Object> returnType) {
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
@@ -1340,5 +1344,16 @@ private static String getOpenDirectoryExecutable() {
public static boolean getSupportsOpenDirectory() {
return getOpenDirectoryExecutable() != null;
}


public static File createFileFromParts(String ... parts) {
String part0 = parts[0];
File f = new File(part0);
for(int i=1;i<parts.length;i++){
String part = parts[i];
f = new File(f, part);
}
return f;
}
}

@@ -13,6 +13,8 @@

import java.util.Vector;

import org.python.pydev.core.structure.FastStringBuffer;

/**
* A string pattern matcher suppporting &#39;*&#39; and &#39;&#63;&#39; wildcards.
*/
@@ -285,7 +287,7 @@ private void parseWildCards() {
Vector<String> temp = new Vector<String>();

int pos = 0;
StringBuffer buf = new StringBuffer();
FastStringBuffer buf = new FastStringBuffer();
while (pos < fLength) {
char c = fPattern.charAt(pos++);
switch (c) {
@@ -11,6 +11,8 @@

import java.io.Serializable;

import org.python.pydev.core.structure.FastStringBuffer;

/**
* Defines a tuple of some object, adding equals and hashCode operations
*
@@ -78,11 +80,11 @@ public int hashCode() {

@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
FastStringBuffer buffer = new FastStringBuffer();
buffer.append("Tuple [");
buffer.append(o1);
buffer.appendObject(o1);
buffer.append(" -- ");
buffer.append(o2);
buffer.appendObject(o2);
buffer.append("]");
return buffer.toString();
}
@@ -11,6 +11,8 @@

import java.io.Serializable;

import org.python.pydev.core.structure.FastStringBuffer;

/**
* Defines a tuple of some object, adding equals and hashCode operations
*
@@ -65,15 +67,15 @@ public int hashCode() {

@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
FastStringBuffer buffer = new FastStringBuffer();
buffer.append("Tuple [");
buffer.append(o1);
buffer.appendObject(o1);
buffer.append(" -- ");
buffer.append(o2);
buffer.appendObject(o2);
buffer.append(" -- ");
buffer.append(o3);
buffer.appendObject(o3);
buffer.append(" -- ");
buffer.append(o4);
buffer.appendObject(o4);
buffer.append("]");
return buffer.toString();
}
@@ -88,6 +88,9 @@ public ImportHandleInfo(String importFound, int lineStart, int lineEnd, boolean
this.startedInMiddleOfLine = startedInMiddleOfLine;

importFound=importFound.trim();
if(importFound.length() == 0){
throw new ImportNotRecognizedException("Could not recognize empty string as import");
}
char firstChar = importFound.charAt(0);


@@ -310,8 +313,12 @@ public ImportHandle(IDocument doc, String importFound, int startFoundLine, int e
}else if(c == ';'){
String impStr = imp.toString();
int endLine = line+StringUtils.countLineBreaks(impStr);
found = new ImportHandleInfo(impStr, line, endLine, startedInMiddle);
this.importInfo.add(found);
try {
found = new ImportHandleInfo(impStr, line, endLine, startedInMiddle);
this.importInfo.add(found);
} catch (ImportNotRecognizedException e) {
//ignore
}
line = endLine;
imp = imp.clear();
startedInMiddle = true;
@@ -324,7 +331,11 @@ public ImportHandle(IDocument doc, String importFound, int startFoundLine, int e

}
String impStr = imp.toString();
this.importInfo.add(new ImportHandleInfo(impStr, line, line+StringUtils.countLineBreaks(impStr), startedInMiddle));
try {
this.importInfo.add(new ImportHandleInfo(impStr, line, line+StringUtils.countLineBreaks(impStr), startedInMiddle));
} catch (ImportNotRecognizedException e) {
//ignore
}

}

@@ -38,14 +38,16 @@ public ParsingUtils(boolean throwSyntaxError){
*
* @author Fabio
*/
private static final class CharArrayParsingUtils extends ParsingUtils{
private char[] cs;
public CharArrayParsingUtils(char[] cs, boolean throwSyntaxError) {
private static final class FixedLenCharArrayParsingUtils extends ParsingUtils{
private final char[] cs;
private final int len;
public FixedLenCharArrayParsingUtils(char[] cs, boolean throwSyntaxError, int len) {
super(throwSyntaxError);
this.cs = cs;
this.len = len;
}
public int len() {
return cs.length;
return len;
}
public char charAt(int i) {
return cs[i];
@@ -58,14 +60,16 @@ public char charAt(int i) {
*
* @author Fabio
*/
private static final class FastStringBufferParsingUtils extends ParsingUtils{
private FastStringBuffer cs;
public FastStringBufferParsingUtils(FastStringBuffer cs, boolean throwSyntaxError) {
private static final class FixedLenFastStringBufferParsingUtils extends ParsingUtils{
private final FastStringBuffer cs;
private final int len;
public FixedLenFastStringBufferParsingUtils(FastStringBuffer cs, boolean throwSyntaxError, int len) {
super(throwSyntaxError);
this.cs = cs;
this.len = len;
}
public int len() {
return cs.length();
return len;
}
public char charAt(int i) {
return cs.charAt(i);
@@ -77,14 +81,16 @@ public char charAt(int i) {
*
* @author Fabio
*/
private static final class StringBufferParsingUtils extends ParsingUtils{
private StringBuffer cs;
public StringBufferParsingUtils(StringBuffer cs, boolean throwSyntaxError) {
private static final class FixedLenStringBufferParsingUtils extends ParsingUtils{
private final StringBuffer cs;
private final int len;
public FixedLenStringBufferParsingUtils(StringBuffer cs, boolean throwSyntaxError, int len) {
super(throwSyntaxError);
this.cs = cs;
this.len = len;
}
public int len() {
return cs.length();
return len;
}
public char charAt(int i) {
return cs.charAt(i);
@@ -96,9 +102,76 @@ public char charAt(int i) {
*
* @author Fabio
*/
private static final class StringParsingUtils extends ParsingUtils{
private String cs;
public StringParsingUtils(String cs, boolean throwSyntaxError) {
private static final class FixedLenStringParsingUtils extends ParsingUtils{
private final String cs;
private final int len;
public FixedLenStringParsingUtils(String cs, boolean throwSyntaxError, int len) {
super(throwSyntaxError);
this.cs = cs;
this.len = len;
}
public int len() {
return len;
}
public char charAt(int i) {
return cs.charAt(i);
}
}

/**
* Class that handles String
*
* @author Fabio
*/
private static final class FixedLenIDocumentParsingUtils extends ParsingUtils{
private final IDocument cs;
private final int len;
public FixedLenIDocumentParsingUtils(IDocument cs, boolean throwSyntaxError, int len) {
super(throwSyntaxError);
this.cs = cs;
this.len = len;
}
public int len() {
return len;
}
public char charAt(int i) {
try {
return cs.getChar(i);
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}
}



/**
* Class that handles FastStringBuffer
*
* @author Fabio
*/
private static final class FastStringBufferParsingUtils extends ParsingUtils{
private final FastStringBuffer cs;
public FastStringBufferParsingUtils(FastStringBuffer cs, boolean throwSyntaxError) {
super(throwSyntaxError);
this.cs = cs;
}
public int len() {
return cs.length();
}
public char charAt(int i) {
return cs.charAt(i);
}
}

/**
* Class that handles StringBuffer
*
* @author Fabio
*/
private static final class StringBufferParsingUtils extends ParsingUtils{
private final StringBuffer cs;
public StringBufferParsingUtils(StringBuffer cs, boolean throwSyntaxError) {
super(throwSyntaxError);
this.cs = cs;
}
@@ -116,7 +189,7 @@ public char charAt(int i) {
* @author Fabio
*/
private static final class IDocumentParsingUtils extends ParsingUtils{
private IDocument cs;
private final IDocument cs;
public IDocumentParsingUtils(IDocument cs, boolean throwSyntaxError) {
super(throwSyntaxError);
this.cs = cs;
@@ -140,24 +213,57 @@ public static ParsingUtils create(Object cs) {
return create(cs, false);
}

/**
* Factory method to create it. Object len may not be changed afterwards.
*/
public static ParsingUtils create(Object cs, boolean throwSyntaxError, int len) {
if(cs instanceof char[]){
char[] cs2 = (char[])cs;
return new FixedLenCharArrayParsingUtils(cs2, throwSyntaxError, len);
}
if(cs instanceof FastStringBuffer){
FastStringBuffer cs2 = (FastStringBuffer)cs;
return new FixedLenFastStringBufferParsingUtils(cs2, throwSyntaxError, len);
}
if(cs instanceof StringBuffer){
StringBuffer cs2 = (StringBuffer)cs;
return new FixedLenStringBufferParsingUtils(cs2, throwSyntaxError, len);
}
if(cs instanceof String){
String cs2 = (String)cs;
return new FixedLenStringParsingUtils(cs2, throwSyntaxError, len);
}
if(cs instanceof IDocument){
IDocument cs2 = (IDocument)cs;
return new FixedLenIDocumentParsingUtils(cs2, throwSyntaxError, len);
}
throw new RuntimeException("Don't know how to create instance for: "+cs.getClass());
}


/**
* Factory method to create it.
*/
public static ParsingUtils create(Object cs, boolean throwSyntaxError) {
if(cs instanceof char[]){
return new CharArrayParsingUtils((char[])cs, throwSyntaxError);
char[] cs2 = (char[])cs;
return new FixedLenCharArrayParsingUtils(cs2, throwSyntaxError, cs2.length);
}
if(cs instanceof FastStringBuffer){
return new FastStringBufferParsingUtils((FastStringBuffer)cs, throwSyntaxError);
FastStringBuffer cs2 = (FastStringBuffer)cs;
return new FastStringBufferParsingUtils(cs2, throwSyntaxError);
}
if(cs instanceof StringBuffer){
return new StringBufferParsingUtils((StringBuffer)cs, throwSyntaxError);
StringBuffer cs2 = (StringBuffer)cs;
return new StringBufferParsingUtils(cs2, throwSyntaxError);
}
if(cs instanceof String){
return new StringParsingUtils((String)cs, throwSyntaxError);
String cs2 = (String)cs;
return new FixedLenStringParsingUtils(cs2, throwSyntaxError, cs2.length());
}
if(cs instanceof IDocument){
return new IDocumentParsingUtils((IDocument)cs, throwSyntaxError);
IDocument cs2 = (IDocument)cs;
return new IDocumentParsingUtils(cs2, throwSyntaxError);
}
throw new RuntimeException("Don't know how to create instance for: "+cs.getClass());
}
@@ -182,7 +288,6 @@ public static ParsingUtils create(Object cs, boolean throwSyntaxError) {


/**
* @param cs the char array we are parsing
* @param buf used to add the comments contents (out) -- if it's null, it'll simply advance to the position and
* return it.
* @param i the # position
@@ -213,7 +318,6 @@ public int eatComments(FastStringBuffer buf, int i) {


/**
* @param cs the char array we are parsing
* @param buf used to add the spaces (out) -- if it's null, it'll simply advance to the position and
* return it.
* @param i the first ' ' position
@@ -261,34 +365,64 @@ public int eatLiteralsBackwards(FastStringBuffer buf, int i) throws SyntaxErrorE
}

/**
* @param cs the char array we are parsing
* @param buf used to add the literal contents (out)
* @param i the ' or " position
* @return the end of the literal position (or end of document) -- so, the final char is the ' or " position
* Equivalent to eatLiterals(buf, startPos, false) .
*
* @param buf
* @param startPos
* @return
* @throws SyntaxErrorException
*/
public int eatLiterals(FastStringBuffer buf, int i) throws SyntaxErrorException{
//ok, current pos is ' or "
//check if we're starting a single or multiline comment...
char curr = charAt(i);

if(curr != '"' && curr != '\''){
throw new RuntimeException("Wrong location to eat literals. Expecting ' or \" ");
}

int j = getLiteralEnd(i, curr);

if(buf != null){
int len = len();
for (int k = i; k < len && k <= j; k++) {
buf.append(charAt(k));
public int eatLiterals(FastStringBuffer buf, int startPos)
throws SyntaxErrorException {
return eatLiterals(buf, startPos, false);
}

/**
* Returns the index of the last character of the current string literal
* beginning at startPos, optionally copying the contents of the literal to
* an output buffer.
*
* @param buf
* If non-null, the contents of the literal are appended to this
* object.
* @param startPos
* The position of the initial ' or "
* @param rightTrimMultiline
* Whether to right trim the whitespace of each line in multi-
* line literals when appending to buf .
* @return The position of the last ' or " character of the literal (or the
* end of the document).
*/
public int eatLiterals(FastStringBuffer buf, int startPos,
boolean rightTrimMultiline)
throws SyntaxErrorException {
char startChar = charAt(startPos);

if (startChar != '"' && startChar != '\'') {
throw new RuntimeException(
"Wrong location to eat literals. Expecting ' or \" ");
}

// Retrieves the correct end position for single- and multi-line
// string literals.
int endPos = getLiteralEnd(startPos, startChar);
boolean rightTrim = rightTrimMultiline
&& isMultiLiteral(startPos, startChar);

if (buf != null) {
int lastPos = Math.min(endPos, len() - 1);
for (int i = startPos; i <= lastPos; i++) {
char ch = charAt(i);
if (rightTrim && (ch == '\r' || ch == '\n')) {
buf.rightTrim();
}
buf.append(ch);
}
}
return j;

return endPos;
}

/**
* @param cs object whith len and charAt
* @param i index we are analyzing it
* @param curr current char
* @return the end of the multiline literal
@@ -307,7 +441,6 @@ public int getLiteralStart(int i, char curr) throws SyntaxErrorException {
}

/**
* @param cs object whith len and charAt
* @param i index we are analyzing it
* @param curr current char
* @return the end of the multiline literal
@@ -326,9 +459,8 @@ public int getLiteralEnd(int i, char curr) throws SyntaxErrorException {
}

/**
* @param cs the char array we are parsing
* @param buf used to add the comments contents (out)
* @param i the ' or " position
* @param buf used to add the comments contents (out)
* @return the end of the literal position (or end of document)
* @throws SyntaxErrorException
*/
@@ -556,7 +688,6 @@ public int findPreviousMulti(int i, char curr) throws SyntaxErrorException {


/**
* @param cs may be a string, a string buffer or a char array
* @param i current position (should have a ' or ")
* @param curr the current char (' or ")
* @return whether we are at the end of a multi line literal or not.
@@ -573,8 +704,6 @@ public boolean isMultiLiteralBackwards(int i, char curr){


/**
*
* @param cs may be a string, a string buffer or a char array
* @param i current position (should have a ' or ")
* @param curr the current char (' or ")
* @return whether we are at the start of a multi line literal or not.
@@ -1133,52 +1133,65 @@ public Tuple<List<String>, Integer> getInsideParentesisToks(boolean addSelf, int
* b
* c
*
* @return a Tuple so that the first param is the list and
* the second the offset of the end of the parenthesis it may return null if no starting parenthesis was found at the current line
* @return a Tuple so that the first param is the list and the second the offset of the end of the parenthesis.
* It may return null if no starting parenthesis was found at the current line
*/
public Tuple<List<String>, Integer> getInsideParentesisToks(boolean addSelf, int offset, boolean isCall) {
List<String> l = new ArrayList<String>();
List<String> params = new ArrayList<String>();
String docContents = doc.get();
int j;
ParsingUtils parsingUtils = ParsingUtils.create(docContents);
try{
j = parsingUtils.eatPar(offset, null);
String insideParentesisTok = docContents.substring(offset + 1, j);
ParsingUtils insideParensParsingUtils = ParsingUtils.create(insideParentesisTok);

if(isCall){
int len = insideParentesisTok.length();
FastStringBuffer buf = new FastStringBuffer(len);
ParsingUtils parsingUtils = ParsingUtils.create(docContents);
j = parsingUtils.eatPar(offset, null);
final String insideParentesisTok = docContents.substring(offset + 1, j);
final ParsingUtils insideParensParsingUtils = ParsingUtils.create(insideParentesisTok);
final int len = insideParentesisTok.length();
final FastStringBuffer buf = new FastStringBuffer(len);

for(int i=0;i<len;i++){
char c = insideParentesisTok.charAt(i);
if(c == ','){
String trim = buf.toString().trim();
if(trim.length() > 0){
l.add(trim);
params.add(trim);
}
buf.clear();
}else{
if(c == '\'' || c == '"'){
j = insideParensParsingUtils.eatLiterals(null, i);
buf.append(insideParentesisTok.substring(i, j+1));
i = j;
}else if(c == '{' || c == '(' || c == '['){
j = insideParensParsingUtils.eatPar(i, null, c);
buf.append(insideParentesisTok.substring(i, j+1));
i = j;
}else{
buf.append(c);
switch(c){
case '\'':
case '"':
j = insideParensParsingUtils.eatLiterals(null, i);
buf.append(insideParentesisTok.substring(i, j+1));
i = j;
break;

case '{':
case '(':
case '[':
j = insideParensParsingUtils.eatPar(i, null, c);
buf.append(insideParentesisTok.substring(i, j+1));
i = j;
break;

default:
buf.append(c);
}
}
}
String trim = buf.toString().trim();
if(trim.length() > 0){
l.add(trim);
params.add(trim);
}


}else{
ParsingUtils parsingUtils = ParsingUtils.create(docContents);
final FastStringBuffer buf = new FastStringBuffer();
j = parsingUtils.eatPar(offset, buf);

final String insideParentesisTok = buf.toString();

StringTokenizer tokenizer = new StringTokenizer(insideParentesisTok, ",");
while (tokenizer.hasMoreTokens()) {
String tok = tokenizer.nextToken();
@@ -1194,7 +1207,7 @@ public Tuple<List<String>, Integer> getInsideParentesisToks(boolean addSelf, int
trimmed = trimmed.trim();
}
if(trimmed.length() > 0){
l.add(trimmed);
params.add(trimmed);
}
}
}
@@ -1203,7 +1216,7 @@ public Tuple<List<String>, Integer> getInsideParentesisToks(boolean addSelf, int
throw new RuntimeException(e);

}
return new Tuple<List<String>, Integer>(l, j);
return new Tuple<List<String>, Integer>(params, j);
}


@@ -2140,9 +2153,10 @@ public Tuple<Integer, Integer> getLineAndCol(int offset) {
* @return the contents from the document starting at the cursor line until a colon is reached.
*/
public String getToColon() {
StringBuffer buffer = new StringBuffer();
FastStringBuffer buffer = new FastStringBuffer();

for(int i = getLineOffset(); i < doc.getLength();i++){
int docLen = doc.getLength();
for(int i = getLineOffset(); i < docLen;i++){
try {
char c = doc.getChar(i);
buffer.append(c);
@@ -19,6 +19,8 @@
import java.util.Map;
import java.util.TreeMap;

import org.python.pydev.core.structure.FastStringBuffer;

public class StringEscapeUtils {

/**
@@ -648,11 +650,12 @@ public int entityValue(String name) {
* @param str The <code>String</code> to escape.
* @return A new escaped <code>String</code>.
*/
public String escape(String str) {
public String escape(final String str) {
//todo: rewrite to use a Writer
StringBuffer buf = new StringBuffer(str.length() * 2);
int length = str.length();
FastStringBuffer buf = new FastStringBuffer(length * 2);
int i;
for (i = 0; i < str.length(); ++i) {
for (i = 0; i < length; ++i) {
char ch = str.charAt(i);
String entityName = this.entityName(ch);
if (entityName == null) {
@@ -682,10 +685,11 @@ public String escape(String str) {
* @param str The <code>String</code> to escape.
* @return A new escaped <code>String</code>.
*/
public String unescape(String str) {
StringBuffer buf = new StringBuffer(str.length());
public String unescape(final String str) {
int len = str.length();
FastStringBuffer buf = new FastStringBuffer(len);
int i;
for (i = 0; i < str.length(); ++i) {
for (i = 0; i < len; ++i) {
char ch = str.charAt(i);
if (ch == '&') {
int semi = str.indexOf(';', i + 1);
@@ -113,7 +113,7 @@ private StringUtils(){

}

public static final Object EMPTY = "";
public static final String EMPTY = "";

/**
* Formats a string, replacing %s with the arguments passed.
@@ -848,57 +848,134 @@ public static String join(String delimiter, Object ... splitted) {
return join(delimiter, newSplitted);
}

public static String join(String delimiter, String[] splitted) {
return (String)join(delimiter, splitted, null);
}

/**
* Same as Python join: Go through all the paths in the string and join them with the passed delimiter.
*
* Note: optimized to have less allocations/method calls
* (i.e.: not using FastStringBuffer, pre-allocating proper size and doing string.getChars directly).
*
* Having a return type != from String (i.e.: char[].class or FastStringBuffer.class) is a bit faster
* as it won't do an additional array/copy for the final result.
*/
public static String join(String delimiter, String[] splitted) {
FastStringBuffer buf = new FastStringBuffer(splitted.length*100);
boolean first = true;
for (String string : splitted) {
if(!first){
buf.append(delimiter);
}else{
first = false;
public static Object join(String delimiter, String[] splitted, Class<? extends Object> returnType) {
//A bit faster than if..elif?
final int len = splitted.length;
switch(len){
case 0:
return EMPTY;
case 1:
return splitted[0];
}

final int delimiterLen = delimiter.length();
int totalSize = delimiterLen * (len-1);
for(int i=0; i< len; i++){
totalSize += splitted[i].length();
}

final char[]buf = new char[totalSize];
int count = 0;

//Copy the first item
String string = splitted[0];
int strLen = string.length();
string.getChars(0, strLen, buf, count);
count += strLen;

switch(delimiterLen){
case 0:
//Special case when the delimiter is empty (i.e.: doesn't need to be copied).
for(int i=1; i< len; i++){
string = splitted[i];
strLen = string.length();
string.getChars(0, strLen, buf, count);
count += strLen;
}
break;

case 1:
//Special case with single-char delimiter (as it's pretty common)
final char delimiterChar = delimiter.charAt(0);
for(int i=1; i< len; i++){
buf[count] = delimiterChar;
count++;

string = splitted[i];
strLen = string.length();
string.getChars(0, strLen, buf, count);
count += strLen;
}
break;

case 2:
//Special case with double-char delimiter (usually: \r\n)
final char delimiterChar0 = delimiter.charAt(0);
final char delimiterChar1 = delimiter.charAt(1);
for(int i=1; i< len; i++){
buf[count] = delimiterChar0;
buf[count+1] = delimiterChar1;
count += 2;

string = splitted[i];
strLen = string.length();
string.getChars(0, strLen, buf, count);
count += strLen;
}
break;

default:
//Copy the remaining ones with the delimiter in place.
for(int i=1; i< len; i++){
strLen = delimiterLen;
delimiter.getChars(0, strLen, buf, count);
count += strLen;

string = splitted[i];
strLen = string.length();
string.getChars(0, strLen, buf, count);
count += strLen;
}
buf.append(string);
break;

}
return buf.toString();

if(returnType == null || returnType == String.class){
return new String(buf);

}else if(returnType == FastStringBuffer.class){
return new FastStringBuffer(buf);

}else if(returnType == char[].class){
return buf;

}else{
throw new RuntimeException("Don't know how to handle return type: "+returnType);
}

}

/**
* Same as Python join: Go through all the paths in the string and join them with the passed delimiter,
* but start at the passed initial location in the splitted array.
*/
public static String join(String delimiter, String[] splitted, int startAtSegment, int endAtSegment) {
FastStringBuffer buf = new FastStringBuffer(splitted.length*100);
boolean first = true;
for (int i=startAtSegment;i<splitted.length && i < endAtSegment;i++) {
if(!first){
buf.append(delimiter);
}else{
first = false;
}
buf.append(splitted[i]);
String[] s = new String[endAtSegment-startAtSegment];
for (int i=startAtSegment, j=0;i<splitted.length && i < endAtSegment;i++, j++) {
s[j] = splitted[i];
}
return buf.toString();
return join(delimiter, s);
}


/**
* Same as Python join: Go through all the paths in the string and join them with the passed delimiter.
*/
public static String join(String delimiter, List<String> splitted) {
FastStringBuffer buf = new FastStringBuffer(splitted.size()*100);
boolean first = true;
for (String string : splitted) {
if(!first){
buf.append(delimiter);
}else{
first = false;
}
buf.append(string);
}
return buf.toString();
return (String)join(delimiter, splitted.toArray(new String[splitted.size()]), null);
}

/**
@@ -1,5 +1,7 @@
package org.python.pydev.core.docutils;

import org.python.pydev.core.structure.FastStringBuffer;




@@ -175,7 +177,7 @@ public static String wrap(String str, int wrapLength, String newLineStr, boolean
}
int inputLineLength = str.length();
int offset = 0;
StringBuffer wrappedLine = new StringBuffer(inputLineLength + 32);
FastStringBuffer wrappedLine = new FastStringBuffer(inputLineLength + 32);

while ((inputLineLength - offset) > wrapLength) {
if (str.charAt(offset) == ' ') {