Browse Source

Added smart indenting for Python.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@5007 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 16 years ago
parent
commit
1e22646923
  1. 4
      src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.addin
  2. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
  3. 76
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormattingStrategy.cs
  4. 8
      src/AddIns/BackendBindings/Python/PythonBinding/Test/AddInFileTestFixture.cs
  5. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
  6. 205
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonIndentationTests.cs
  7. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockTextEditorProperties.cs

4
src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.addin

@ -24,6 +24,10 @@ @@ -24,6 +24,10 @@
resource="ICSharpCode.PythonBinding.Resources.Python.xshd"/>
</Path>
<Path name="/AddIns/DefaultTextEditor/Formatter/Python">
<Class id="PythonFormatter" class="ICSharpCode.PythonBinding.PythonFormattingStrategy"/>
</Path>
<!-- Add the "Python" entry to the Open File Dialog -->
<Path name="/SharpDevelop/Workbench/FileFilter">
<FileFilter id="Python"

1
src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj

@ -93,6 +93,7 @@ @@ -93,6 +93,7 @@
<Compile Include="Src\PythonDesignerLoader.cs" />
<Compile Include="Src\PythonDesignerLoaderProvider.cs" />
<Compile Include="Src\PythonExpressionFinder.cs" />
<Compile Include="Src\PythonFormattingStrategy.cs" />
<Compile Include="Src\PythonFormsDesignerDisplayBinding.cs" />
<Compile Include="Src\PythonComponentWalker.cs" />
<Compile Include="Src\PythonComponentWalkerException.cs" />

76
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormattingStrategy.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.PythonBinding
{
public class PythonFormattingStrategy : DefaultFormattingStrategy
{
public PythonFormattingStrategy()
{
}
protected override int SmartIndentLine(TextArea textArea, int line)
{
IDocument document = textArea.Document;
LineSegment previousLine = document.GetLineSegment(line - 1);
string previousLineText = document.GetText(previousLine).Trim();
if (previousLineText.EndsWith(":")) {
return IncreaseLineIndent(textArea, line);
} else if (previousLineText == "pass") {
return DecreaseLineIndent(textArea, line);
} else if ((previousLineText == "return") || (previousLineText.StartsWith("return "))) {
return DecreaseLineIndent(textArea, line);
} else if ((previousLineText == "raise") || (previousLineText.StartsWith("raise "))) {
return DecreaseLineIndent(textArea, line);
} else if (previousLineText == "break") {
return DecreaseLineIndent(textArea, line);
}
return base.SmartIndentLine(textArea, line);
}
int IncreaseLineIndent(TextArea textArea, int line)
{
return ModifyLineIndent(textArea, line, true);
}
int DecreaseLineIndent(TextArea textArea, int line)
{
return ModifyLineIndent(textArea, line, false);
}
int ModifyLineIndent(TextArea textArea, int line, bool increaseIndent)
{
IDocument document = textArea.Document;
LineSegment currentLine = document.GetLineSegment(line);
string indentation = GetIndentation(textArea, line - 1);
indentation = GetNewLineIndentation(indentation, Tab.GetIndentationString(document), increaseIndent);
string newIndentedText = indentation + document.GetText(currentLine);
SmartReplaceLine(document, currentLine, newIndentedText);
return indentation.Length;
}
string GetNewLineIndentation(string previousLineIndentation, string singleIndent, bool increaseIndent)
{
if (increaseIndent) {
return previousLineIndentation + singleIndent;
}
// Decrease the new line indentation.
int decreaselength = previousLineIndentation.Length - singleIndent.Length;
if (decreaselength < 0) {
decreaselength = 0;
}
return previousLineIndentation.Substring(0, decreaselength);
}
}
}

8
src/AddIns/BackendBindings/Python/PythonBinding/Test/AddInFileTestFixture.cs

@ -51,6 +51,7 @@ namespace PythonBinding.Tests @@ -51,6 +51,7 @@ namespace PythonBinding.Tests
Codon pythonProjectIconCodon;
Codon convertCSharpProjectCodon;
Codon convertVBNetProjectCodon;
Codon formattingStrategyCodon;
[TestFixtureSetUp]
public void SetupFixture()
@ -83,6 +84,7 @@ namespace PythonBinding.Tests @@ -83,6 +84,7 @@ namespace PythonBinding.Tests
pythonProjectIconCodon = GetCodon("/Workspace/Icons", "PythonProjectIcon");
convertCSharpProjectCodon = GetCodon("/SharpDevelop/Pads/ProjectBrowser/ContextMenu/ProjectActions/Convert", "CSharpProjectToPythonProjectConverter");
convertVBNetProjectCodon = GetCodon("/SharpDevelop/Pads/ProjectBrowser/ContextMenu/ProjectActions/Convert", "VBNetProjectToPythonProjectConverter");
formattingStrategyCodon = GetCodon("/AddIns/DefaultTextEditor/Formatter/Python", "PythonFormatter");
// Get the PythonBinding runtime.
foreach (Runtime runtime in addin.Runtimes) {
@ -749,6 +751,12 @@ namespace PythonBinding.Tests @@ -749,6 +751,12 @@ namespace PythonBinding.Tests
{
Assert.AreEqual(pythonWithoutDebuggerRunMenuItemCodon.Conditions[0], pythonRunMenuItemCodon.Conditions[0]);
}
[Test]
public void PythonFormatterClass()
{
Assert.AreEqual("ICSharpCode.PythonBinding.PythonFormattingStrategy", formattingStrategyCodon["class"]);
}
Codon GetCodon(string name, string extensionPath)
{

1
src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

@ -306,6 +306,7 @@ @@ -306,6 +306,7 @@
<Compile Include="Parsing\ParseSingleClassTestFixture.cs" />
<Compile Include="Parsing\InvalidClassTestFixture.cs" />
<Compile Include="PythonBindingAddInFile.cs" />
<Compile Include="PythonIndentationTests.cs" />
<Compile Include="PythonLanguagePropertiesTests.cs" />
<Compile Include="PythonOptionsPanelTestFixture.cs" />
<Compile Include="CreateNewPythonProjectTestFixture.cs" />

205
src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonIndentationTests.cs

@ -0,0 +1,205 @@ @@ -0,0 +1,205 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.PythonBinding;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Actions;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Indentation
{
/// <summary>
/// Tests that the PythonFormattingStrategy indents the new line added after pressing the ':' character.
/// </summary>
[TestFixture]
public class PythonNewMethodIndentationTestFixture
{
TextEditorControl textEditor;
PythonFormattingStrategy formattingStrategy;
[SetUp]
public void Init()
{
MockTextEditorProperties textEditorProperties = new MockTextEditorProperties();
textEditorProperties.IndentStyle = IndentStyle.Smart;
textEditorProperties.TabIndent = 4;
textEditor = new TextEditorControl();
textEditor.TextEditorProperties = textEditorProperties;
formattingStrategy = new PythonFormattingStrategy();
}
[TearDown]
public void TearDown()
{
textEditor.Dispose();
}
[Test]
public void NewMethodDefinition()
{
textEditor.Text = "def newMethod:\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 1);
string expectedText = "def newMethod:\r\n" +
"\t";
Assert.AreEqual(expectedText, textEditor.Text);
Assert.AreEqual(1, indentResult);
}
[Test]
public void NoExtraIndentationRequired()
{
textEditor.Text = "\tprint 'abc'\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 1);
string expectedText = "\tprint 'abc'\r\n" +
"\t";
Assert.AreEqual(expectedText, textEditor.Text);
Assert.AreEqual(1, indentResult);
}
[Test]
public void PassStatementDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\tpass\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\tpass\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void ReturnValueStatementDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\treturn 0\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\treturn 0\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void ReturnStatementDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\treturn\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\treturn\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void ReturnStatementWithNoIndentOnPreviousLine()
{
textEditor.Text = "return\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 1);
string expectedText = "return\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void StatementIsNotAReturnOnPreviousLine()
{
textEditor.Text = "\treturnValue\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 1);
string expectedText = "\treturnValue\r\n" +
"\t";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void RaiseStatementWithObjectDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\traise 'a'\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\traise 'a'\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void RaiseStatementDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\traise\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\traise\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void StatementIsNotARaiseStatementOnPreviousLine()
{
textEditor.Text = "def method1:\r\n" +
"\traiseThis\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\traiseThis\r\n" +
"\t";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void BreakStatementDecreasesIndentOnThirdLine()
{
textEditor.Text = "def method1:\r\n" +
"\tbreak\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\tbreak\r\n" +
"";
Assert.AreEqual(expectedText, textEditor.Text);
}
[Test]
public void StatementIsNotABreakStatementOnPreviousLine()
{
textEditor.Text = "def method1:\r\n" +
"\tbreakThis\r\n" +
"";
int indentResult = formattingStrategy.IndentLine(textEditor.ActiveTextAreaControl.TextArea, 2);
string expectedText = "def method1:\r\n" +
"\tbreakThis\r\n" +
"\t";
Assert.AreEqual(expectedText, textEditor.Text);
}
}
}

1
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockTextEditorProperties.cs

@ -17,6 +17,7 @@ namespace PythonBinding.Tests.Utils @@ -17,6 +17,7 @@ namespace PythonBinding.Tests.Utils
{
public MockTextEditorProperties()
{
FontContainer = new FontContainer(SystemFonts.MenuFont);
}
public bool CaretLine { get; set; }

Loading…
Cancel
Save