Browse Source

fix XML code completion weirdnesses and adjust unit tests

pull/18/head
Siegfried Pammer 14 years ago
parent
commit
cbb8cbbff6
  1. 75
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCodeCompletionBinding.cs
  2. 4
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItem.cs
  3. 2
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItemCollection.cs
  4. 21
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlParser.cs
  5. 3
      src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlSchemaCompletionCollection.cs
  6. 8
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/AttributeCompletionWindowTestFixture.cs
  7. 7
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/CtrlSpaceAttributeValueCompletionTestFixture.cs
  8. 2
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/ElementCompletionWindowTests.cs
  9. 57
      src/AddIns/DisplayBindings/XmlEditor/Test/Completion/NamespaceCompletionWindowTestFixture.cs
  10. 8
      src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockDocument.cs
  11. 2
      src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockTextEditor.cs
  12. 1
      src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj

75
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCodeCompletionBinding.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion; using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
@ -12,7 +12,7 @@ using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.XmlEditor namespace ICSharpCode.XmlEditor
{ {
public class XmlCodeCompletionBinding : ICodeCompletionBinding public class XmlCodeCompletionBinding : ICodeCompletionBinding
{ {
XmlSchemaFileAssociations schemaFileAssociations; XmlSchemaFileAssociations schemaFileAssociations;
XmlSchemaCompletionCollection schemas; XmlSchemaCompletionCollection schemas;
@ -27,42 +27,37 @@ namespace ICSharpCode.XmlEditor
this.schemas = schemaFileAssociations.Schemas; this.schemas = schemaFileAssociations.Schemas;
} }
char[] ignoredChars = new[] { '\\', '/', '"', '\'', '=', '>' };
public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{ {
XmlSchemaCompletion defaultSchema = schemaFileAssociations.GetSchemaCompletion(editor.FileName); if (char.IsWhiteSpace(ch) || editor.SelectionLength > 0)
XmlCompletionItemCollection completionItems = GetCompletionItems(editor, ch, defaultSchema); return CodeCompletionKeyPressResult.None;
if (completionItems.HasItems) { if (ignoredChars.Contains(ch))
completionItems.Sort(); return CodeCompletionKeyPressResult.None;
ICompletionListWindow completionWindow = editor.ShowCompletionWindow(completionItems); if (XmlParser.GetXmlIdentifierBeforeIndex(editor.Document, editor.Caret.Offset).Length > 0)
if (completionWindow != null) { return CodeCompletionKeyPressResult.None;
SetCompletionWindowWidth(completionWindow, completionItems); editor.Document.Insert(editor.Caret.Offset, ch.ToString());
} CtrlSpace(editor);
} return CodeCompletionKeyPressResult.EatKey;
if ((ch == '<') || (ch == ' ') || (ch == '=')) {
return CodeCompletionKeyPressResult.Completed;
}
return CodeCompletionKeyPressResult.None;
} }
XmlCompletionItemCollection GetCompletionItems(ITextEditor editor, char characterTyped, XmlSchemaCompletion defaultSchema) XmlCompletionItemCollection GetCompletionItems(ITextEditor editor, XmlSchemaCompletion defaultSchema)
{ {
string textUpToCursor = GetTextUpToCursor(editor, characterTyped); int offset = editor.Caret.Offset;
string textUpToCursor = editor.Document.GetText(0, offset);
switch (characterTyped) { XmlCompletionItemCollection items = new XmlCompletionItemCollection();
case '=': if (XmlParser.IsInsideAttributeValue(textUpToCursor, offset)) {
return schemas.GetNamespaceCompletion(textUpToCursor); items = schemas.GetNamespaceCompletion(textUpToCursor);
case '<': if (items.Count == 0)
return schemas.GetElementCompletion(textUpToCursor, defaultSchema); items = schemas.GetAttributeValueCompletion(textUpToCursor, editor.Caret.Offset, defaultSchema);
case ' ': } else {
return schemas.GetAttributeCompletion(textUpToCursor, defaultSchema); items = schemas.GetAttributeCompletion(textUpToCursor, defaultSchema);
} if (items.Count == 0)
return schemas.GetAttributeValueCompletion(characterTyped, textUpToCursor, defaultSchema); items = schemas.GetElementCompletion(textUpToCursor, defaultSchema);
} }
return items;
string GetTextUpToCursor(ITextEditor editor, char characterTyped)
{
return editor.Document.GetText(0, editor.Caret.Offset) + characterTyped;
} }
void SetCompletionWindowWidth(ICompletionListWindow completionWindow, XmlCompletionItemCollection completionItems) void SetCompletionWindowWidth(ICompletionListWindow completionWindow, XmlCompletionItemCollection completionItems)
@ -74,14 +69,18 @@ namespace ICSharpCode.XmlEditor
} }
public bool CtrlSpace(ITextEditor editor) public bool CtrlSpace(ITextEditor editor)
{ {
string text = editor.Document.Text;
int offset = editor.Caret.Offset;
XmlSchemaCompletion defaultSchema = schemaFileAssociations.GetSchemaCompletion(editor.FileName); XmlSchemaCompletion defaultSchema = schemaFileAssociations.GetSchemaCompletion(editor.FileName);
XmlCompletionItemCollection completionItems = schemas.GetAttributeValueCompletion(text, offset, defaultSchema);
XmlCompletionItemCollection completionItems = GetCompletionItems(editor, defaultSchema);
if (completionItems.HasItems) { if (completionItems.HasItems) {
editor.ShowCompletionWindow(completionItems); completionItems.Sort();
string identifier = XmlParser.GetXmlIdentifierBeforeIndex(editor.Document, editor.Caret.Offset);
completionItems.PreselectionLength = identifier.Length;
ICompletionListWindow completionWindow = editor.ShowCompletionWindow(completionItems);
if (completionWindow != null) {
SetCompletionWindowWidth(completionWindow, completionItems);
}
return true; return true;
} }
return false; return false;

4
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItem.cs

@ -65,10 +65,6 @@ namespace ICSharpCode.XmlEditor
base.Complete(context); base.Complete(context);
switch (dataType) { switch (dataType) {
case XmlCompletionItemType.NamespaceUri:
context.Editor.Document.Insert(context.StartOffset, "\"");
context.Editor.Document.Insert(context.EndOffset + 1, "\"");
break;
case XmlCompletionItemType.XmlAttribute: case XmlCompletionItemType.XmlAttribute:
context.Editor.Document.Insert(context.EndOffset, "=\"\""); context.Editor.Document.Insert(context.EndOffset, "=\"\"");
context.Editor.Caret.Offset--; context.Editor.Caret.Offset--;

2
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlCompletionItemCollection.cs

@ -134,7 +134,7 @@ namespace ICSharpCode.XmlEditor
public ICompletionItem SuggestedItem { public ICompletionItem SuggestedItem {
get { get {
if (HasItems) { if (HasItems && PreselectionLength == 0) {
return this[0]; return this[0];
} }
return null; return null;

21
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlParser.cs

@ -7,6 +7,7 @@ using System.IO;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml; using System.Xml;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.XmlEditor namespace ICSharpCode.XmlEditor
{ {
@ -19,14 +20,10 @@ namespace ICSharpCode.XmlEditor
/// since we are interested in the complete path or tree to the /// since we are interested in the complete path or tree to the
/// currently active element. /// currently active element.
/// </remarks> /// </remarks>
public sealed class XmlParser public static class XmlParser
{ {
static readonly char[] whitespaceCharacters = new char[] {' ', '\n', '\t', '\r'}; static readonly char[] whitespaceCharacters = new char[] {' ', '\n', '\t', '\r'};
XmlParser()
{
}
/// <summary> /// <summary>
/// Gets path of the xml element start tag that the specified /// Gets path of the xml element start tag that the specified
/// <paramref name="index"/> is currently inside. /// <paramref name="index"/> is currently inside.
@ -687,9 +684,21 @@ namespace ICSharpCode.XmlEditor
return path; return path;
} }
static bool IsQuoteChar(char ch) public static bool IsQuoteChar(char ch)
{ {
return (ch == '\"') || (ch == '\''); return (ch == '\"') || (ch == '\'');
} }
public static string GetXmlIdentifierBeforeIndex(ITextBuffer document, int index)
{
if (document == null)
throw new ArgumentNullException("document");
if (index < 0 || index > document.TextLength)
throw new ArgumentOutOfRangeException("index", index, "Value must be between 0 and " + document.TextLength);
int i = index - 1;
while (i >= 0 && IsXmlNameChar(document.GetCharAt(i)) && document.GetCharAt(i) != '/')
i--;
return document.GetText(i + 1, index - i - 1);
}
} }
} }

3
src/AddIns/DisplayBindings/XmlEditor/Project/Src/XmlSchemaCompletionCollection.cs

@ -26,7 +26,8 @@ namespace ICSharpCode.XmlEditor
public XmlCompletionItemCollection GetNamespaceCompletion(string textUpToCursor) public XmlCompletionItemCollection GetNamespaceCompletion(string textUpToCursor)
{ {
if (XmlParser.IsNamespaceDeclaration(textUpToCursor, textUpToCursor.Length)) { string attrName = XmlParser.GetAttributeNameAtIndex(textUpToCursor, textUpToCursor.Length);
if (attrName == "xmlns" || attrName.StartsWith("xmlns:")) {
return GetNamespaceCompletion(); return GetNamespaceCompletion();
} }
return new XmlCompletionItemCollection(); return new XmlCompletionItemCollection();

8
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/AttributeCompletionWindowTestFixture.cs

@ -40,15 +40,15 @@ namespace XmlEditor.Tests.Completion
} }
[Test] [Test]
public void KeyPressResultIsCompletedAfterPressingSpaceBar() public void KeyPressResultIsNotCompletedAfterPressingSpaceBar()
{ {
Assert.AreEqual(CodeCompletionKeyPressResult.Completed, keyPressResult); Assert.AreEqual(CodeCompletionKeyPressResult.None, keyPressResult);
} }
[Test] [Test]
public void CompletionListUsedInShowCompletionWindowHasItems() public void CompletionListUsedInShowCompletionWindowHasNoItems()
{ {
Assert.IsTrue(textEditor.CompletionItemsDisplayedToArray().Length > 0); Assert.IsTrue(textEditor.CompletionItemsDisplayedToArray().Length == 0);
} }
} }
} }

7
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/CtrlSpaceAttributeValueCompletionTestFixture.cs

@ -46,13 +46,6 @@ namespace XmlEditor.Tests.Completion
Assert.IsTrue(result); Assert.IsTrue(result);
} }
[Test]
public void CtrlSpaceMethodResultIsFalseWhenCursorIsOutsideAttributeValue()
{
textEditor.Caret.Offset = 0;
Assert.IsFalse(completionBinding.CtrlSpace(textEditor));
}
[Test] [Test]
public void ShowCompletionWindowCalledWithCompletionItems() public void ShowCompletionWindowCalledWithCompletionItems()
{ {

2
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/ElementCompletionWindowTests.cs

@ -42,7 +42,7 @@ namespace XmlEditor.Tests.Completion
public void HandleKeyPress_LessThanKeyPressed_KeyPressResultIsCompletedAfterPressingLessThanSign() public void HandleKeyPress_LessThanKeyPressed_KeyPressResultIsCompletedAfterPressingLessThanSign()
{ {
keyPressResult = completionBinding.HandleKeyPress(textEditor, '<'); keyPressResult = completionBinding.HandleKeyPress(textEditor, '<');
Assert.AreEqual(CodeCompletionKeyPressResult.Completed, keyPressResult); Assert.AreEqual(CodeCompletionKeyPressResult.EatKey, keyPressResult);
} }
[Test] [Test]

57
src/AddIns/DisplayBindings/XmlEditor/Test/Completion/NamespaceCompletionWindowTestFixture.cs

@ -1,57 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using ICSharpCode.XmlEditor;
using NUnit.Framework;
using XmlEditor.Tests.Utils;
namespace XmlEditor.Tests.Completion
{
[TestFixture]
public class NamespaceCompletionWindowTestFixture : NamespaceCompletionWindowTestFixtureBase
{
[SetUp]
public void Init()
{
base.InitBase();
XmlCodeCompletionBinding completionBinding = new XmlCodeCompletionBinding(associations);
keyPressResult = completionBinding.HandleKeyPress(textEditor, '=');
}
[Test]
public void KeyPressResultIsCompletedAfterPressingEqualsSign()
{
Assert.AreEqual(CodeCompletionKeyPressResult.Completed, keyPressResult);
}
[Test]
public void CompletionWindowWidthSetToMatchLongestNamespaceTextWidth()
{
Assert.AreEqual(double.NaN, textEditor.CompletionWindowDisplayed.Width);
}
[Test]
public void ExpectedCompletionDataItems()
{
XmlCompletionItemCollection expectedItems = new XmlCompletionItemCollection();
expectedItems.Add(new XmlCompletionItem("a", XmlCompletionItemType.NamespaceUri));
expectedItems.Add(new XmlCompletionItem("b", XmlCompletionItemType.NamespaceUri));
expectedItems.Add(new XmlCompletionItem("c", XmlCompletionItemType.NamespaceUri));
Assert.AreEqual(expectedItems.ToArray(), textEditor.CompletionItemsDisplayedToArray());
}
[Test]
public void TextEditorDocumentGetTextCalledWithOffsetAndLength()
{
TextSection expectedTextSection = new TextSection(0, 8);
Assert.AreEqual(expectedTextSection, textEditor.MockDocument.GetTextSectionUsedWithGetTextMethod());
}
}
}

8
src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockDocument.cs

@ -49,9 +49,7 @@ namespace XmlEditor.Tests.Utils
} }
public int TextLength { public int TextLength {
get { get { return text.Length; }
throw new NotImplementedException();
}
} }
public IDocumentLine GetLine(int lineNumber) public IDocumentLine GetLine(int lineNumber)
@ -78,7 +76,7 @@ namespace XmlEditor.Tests.Utils
public void Insert(int offset, string text) public void Insert(int offset, string text)
{ {
throw new NotImplementedException(); this.text = this.text.Insert(offset, text);
} }
public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType) public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
@ -138,7 +136,7 @@ namespace XmlEditor.Tests.Utils
public char GetCharAt(int offset) public char GetCharAt(int offset)
{ {
throw new NotImplementedException(); return text[offset];
} }
public string GetText(int offset, int length) public string GetText(int offset, int length)

2
src/AddIns/DisplayBindings/XmlEditor/Test/Utils/MockTextEditor.cs

@ -156,6 +156,8 @@ namespace XmlEditor.Tests.Utils
public ICompletionItem[] CompletionItemsDisplayedToArray() public ICompletionItem[] CompletionItemsDisplayedToArray()
{ {
List<ICompletionItem> items = new List<ICompletionItem>(); List<ICompletionItem> items = new List<ICompletionItem>();
if (completionItemsDisplayed == null)
return items.ToArray();
foreach (ICompletionItem item in completionItemsDisplayed.Items) { foreach (ICompletionItem item in completionItemsDisplayed.Items) {
items.Add(item); items.Add(item);
} }

1
src/AddIns/DisplayBindings/XmlEditor/Test/XmlEditor.Tests.csproj

@ -82,7 +82,6 @@
<Compile Include="Completion\CtrlSpaceNoAttributeValuesForCompletionTestFixture.cs" /> <Compile Include="Completion\CtrlSpaceNoAttributeValuesForCompletionTestFixture.cs" />
<Compile Include="Completion\ElementCompletionWindowTests.cs" /> <Compile Include="Completion\ElementCompletionWindowTests.cs" />
<Compile Include="Completion\FirstCompletionListItemSelectedTestFixture.cs" /> <Compile Include="Completion\FirstCompletionListItemSelectedTestFixture.cs" />
<Compile Include="Completion\NamespaceCompletionWindowTestFixture.cs" />
<Compile Include="Completion\NamespaceCompletionWindowTestFixtureBase.cs" /> <Compile Include="Completion\NamespaceCompletionWindowTestFixtureBase.cs" />
<Compile Include="Completion\NoCompletionItemsTestFixture.cs" /> <Compile Include="Completion\NoCompletionItemsTestFixture.cs" />
<Compile Include="Completion\NullCompletionItemsReturnedTestFixture.cs" /> <Compile Include="Completion\NullCompletionItemsReturnedTestFixture.cs" />

Loading…
Cancel
Save