Browse Source

Added snippet support to SharpDevelop (replaces 'code templates').

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5069 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
4a85fa660c
  1. 26
      AddIns/ICSharpCode.SharpDevelop.addin
  2. 20
      samples/AvalonEdit.Sample/AvalonEdit.Sample.sln
  3. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
  4. 6
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.addin
  5. 11
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj
  6. 19
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  7. 14
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
  8. 61
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
  9. 17
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs
  10. 192
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs
  11. 47
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippetGroup.cs
  12. 94
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs
  13. 153
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetManager.cs
  14. 110
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetOptionPanel.cs
  15. 122
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetOptionPanel.xaml
  16. 36
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
  17. 51
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs
  18. 32
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
  19. 47
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs
  20. 48
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs
  21. 14
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
  22. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/InsertionContext.cs
  23. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/Snippet.cs
  24. 13
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetBoundElement.cs
  25. 15
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetContainerElement.cs
  26. 10
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetElement.cs
  27. 34
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetInputHandler.cs
  28. 9
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetReplaceableTextElement.cs
  29. 7
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetTextElement.cs
  30. 10
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  31. 108
      src/Main/Base/Project/Resources/CodeTemplatePanel.xfrm
  32. 2
      src/Main/Base/Project/Src/Commands/CustomStringTagProvider.cs
  33. 9
      src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
  34. 45
      src/Main/Base/Project/Src/Editor/CodeCompletion/CtrlSpaceCompletionItemProvider.cs
  35. 8
      src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionItemList.cs
  36. 69
      src/Main/Base/Project/Src/Editor/CodeCompletion/TemplateCompletionItemProvider.cs
  37. 5
      src/Main/Base/Project/Src/Editor/ITextEditor.cs
  38. 22
      src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/EditTemplateDialog.cs
  39. 91
      src/Main/Base/Project/Src/Internal/Templates/CodeTemplate.cs
  40. 87
      src/Main/Base/Project/Src/Internal/Templates/CodeTemplateGroup.cs
  41. 119
      src/Main/Base/Project/Src/Internal/Templates/CodeTemplateLoader.cs
  42. 11
      src/Main/Base/Project/Src/TextEditor/Actions.cs
  43. 51
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
  44. 262
      src/Main/Base/Project/Src/TextEditor/Gui/OptionPanels/CodeTemplatePanel.cs
  45. 5
      src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
  46. 8
      src/Main/Core/Project/Src/Services/StringParser/StringParser.cs
  47. 15
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs
  48. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/VBNetCodeGenerator.cs

26
AddIns/ICSharpCode.SharpDevelop.addin

@ -167,16 +167,6 @@
class = "ICSharpCode.SharpDevelop.Project.LoadSolution" class = "ICSharpCode.SharpDevelop.Project.LoadSolution"
extensions = "*.sln"/> extensions = "*.sln"/>
<FileFilter id = "Combine"
name = "${res:SharpDevelop.FileFilter.CombineFiles}"
class = "ICSharpCode.SharpDevelop.Project.LoadSolution"
extensions = "*.cmbx"/>
<FileFilter id = "Prjx"
name = "${res:SharpDevelop.FileFilter.PrjxFiles}"
class = "ICSharpCode.SharpDevelop.Project.LoadSolution"
extensions = "*.prjx"/>
<FileFilter id = "AllFiles" <FileFilter id = "AllFiles"
name = "${res:SharpDevelop.FileFilter.AllFiles}" name = "${res:SharpDevelop.FileFilter.AllFiles}"
extensions = "*.*"/> extensions = "*.*"/>
@ -1718,12 +1708,6 @@
<!-- TEXT EDITOR --> <!-- TEXT EDITOR -->
<Path name = "/SharpDevelop/Dialogs/OptionsDialog/CodingOptions">
<OptionPanel id = "CodeTemplates"
label = "${res:Dialog.Options.CodeTemplatesText}"
class = "ICSharpCode.SharpDevelop.Gui.OptionPanels.CodeTemplatePanel"/>
</Path>
<Path name = "/SharpDevelop/Workbench/DisplayBindings"> <Path name = "/SharpDevelop/Workbench/DisplayBindings">
<DisplayBinding id = "OldText" <DisplayBinding id = "OldText"
insertafter = "Text" insertafter = "Text"
@ -1962,16 +1946,6 @@
</OptionPanel> </OptionPanel>
</Path> </Path>
<!-- Note : Most actions are put directly into the control, because
they're used for the standalone version too, only put keys in the
tree that are sharpdevelop specific, general keys put into TextAreaControl.GenerateDefaultActions -->
<Path name = "/AddIns/DefaultTextEditor/EditActions">
<EditAction id = "TemplateCompletion" class = "ICSharpCode.SharpDevelop.DefaultEditor.Actions.TemplateCompletion" keys = "Control|J"/>
<EditAction id = "CodeCompletionPopup" class = "ICSharpCode.SharpDevelop.DefaultEditor.Actions.CodeCompletionPopup" keys = "Control|Space"/>
<EditAction id = "GoToDefinition" class = "ICSharpCode.SharpDevelop.DefaultEditor.Actions.GoToDefinition" keys = "Control|Enter"/>
<EditAction id = "ExpandTemplateAction" class = "ICSharpCode.SharpDevelop.DefaultEditor.Actions.ExpandTemplateAction" keys = "Tab"/>
</Path>
<Path name = "/SharpDevelop/Pads/BookmarkPad/Toolbar"> <Path name = "/SharpDevelop/Pads/BookmarkPad/Toolbar">
<ToolbarItem id = "GotoPrev" <ToolbarItem id = "GotoPrev"
icon = "Bookmarks.GotoPrev" icon = "Bookmarks.GotoPrev"

20
samples/AvalonEdit.Sample/AvalonEdit.Sample.sln

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
# SharpDevelop 4.0.0.5064
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvalonEdit.Sample", "AvalonEdit.Sample.csproj", "{13A5B497-BA12-45AE-9033-22620C3153FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{13A5B497-BA12-45AE-9033-22620C3153FB}.Debug|x86.Build.0 = Debug|x86
{13A5B497-BA12-45AE-9033-22620C3153FB}.Debug|x86.ActiveCfg = Debug|x86
{13A5B497-BA12-45AE-9033-22620C3153FB}.Release|x86.Build.0 = Release|x86
{13A5B497-BA12-45AE-9033-22620C3153FB}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection
EndGlobal

8
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs

@ -94,13 +94,15 @@ namespace CSharpBinding
if (char.IsLetter(ch) && CodeCompletionOptions.CompleteWhenTyping) { if (char.IsLetter(ch) && CodeCompletionOptions.CompleteWhenTyping) {
if (editor.SelectionLength > 0) { if (editor.SelectionLength > 0) {
// allow code completion when overwriting an identifier // allow code completion when overwriting an identifier
cursor = editor.SelectionStart; int endOffset = editor.SelectionStart + editor.SelectionLength;
int endOffset = cursor + editor.SelectionLength;
// but block code completion when overwriting only part of an identifier // but block code completion when overwriting only part of an identifier
if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset))) if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset)))
return CodeCompletionKeyPressResult.None; return CodeCompletionKeyPressResult.None;
editor.Document.Remove(editor.SelectionStart, editor.SelectionLength); editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
editor.Caret.Offset = cursor; // Read caret position again after removal - this is required because the document might change in other
// locations, too (e.g. bound elements in snippets).
cursor = editor.Caret.Offset;
} }
char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' '; char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' ';
bool afterUnderscore = prevChar == '_'; bool afterUnderscore = prevChar == '_';

6
src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.addin

@ -75,4 +75,10 @@
command = "ICSharpCode.AvalonEdit.AvalonEditCommands.ConvertLeadingSpacesToTabs"/> command = "ICSharpCode.AvalonEdit.AvalonEditCommands.ConvertLeadingSpacesToTabs"/>
</Condition> </Condition>
</Path> </Path>
<Path name = "/SharpDevelop/Dialogs/OptionsDialog/CodingOptions">
<OptionPanel id = "CodeTemplates"
label = "${res:Dialog.Options.CodeTemplatesText}"
class = "ICSharpCode.AvalonEdit.AddIn.Snippets.SnippetOptionPanel"/>
</Path>
</AddIn> </AddIn>

11
src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj

@ -78,6 +78,13 @@
<Compile Include="Src\CustomCommands.cs" /> <Compile Include="Src\CustomCommands.cs" />
<Compile Include="Src\IconBarManager.cs" /> <Compile Include="Src\IconBarManager.cs" />
<Compile Include="Src\IconBarMargin.cs" /> <Compile Include="Src\IconBarMargin.cs" />
<Compile Include="Src\Snippets\CodeSnippet.cs" />
<Compile Include="Src\Snippets\CodeSnippetGroup.cs" />
<Compile Include="Src\Snippets\SnippetCompletionItem.cs" />
<Compile Include="Src\Snippets\SnippetManager.cs" />
<Compile Include="Src\Snippets\SnippetOptionPanel.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Src\ParserFoldingStrategy.cs" /> <Compile Include="Src\ParserFoldingStrategy.cs" />
<Compile Include="Src\QuickClassBrowser.cs"> <Compile Include="Src\QuickClassBrowser.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
@ -90,6 +97,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Src" /> <Folder Include="Src" />
<Folder Include="Src\Commands" /> <Folder Include="Src\Commands" />
<Folder Include="Src\Snippets" />
<ProjectReference Include="..\..\..\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj"> <ProjectReference Include="..\..\..\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project> <Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
<Name>ICSharpCode.AvalonEdit</Name> <Name>ICSharpCode.AvalonEdit</Name>
@ -121,6 +129,9 @@
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<Page Include="Src\Commands\SortOptionsDialog.xaml" /> <Page Include="Src\Commands\SortOptionsDialog.xaml" />
<Page Include="Src\Snippets\SnippetOptionPanel.xaml">
<DependentUpon>SnippetOptionPanel.cs</DependentUpon>
</Page>
<Page Include="Src\QuickClassBrowser.xaml"> <Page Include="Src\QuickClassBrowser.xaml">
<DependentUpon>QuickClassBrowser.cs</DependentUpon> <DependentUpon>QuickClassBrowser.cs</DependentUpon>
</Page> </Page>

19
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -73,14 +73,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
} }
private set { private set {
if (document != value) { if (document != value) {
if (document != null)
document.UpdateFinished -= DocumentUpdateFinished;
document = value; document = value;
if (document != null)
document.UpdateFinished += DocumentUpdateFinished;
if (DocumentChanged != null) { if (DocumentChanged != null) {
DocumentChanged(this, EventArgs.Empty); DocumentChanged(this, EventArgs.Empty);
} }
@ -287,23 +281,12 @@ namespace ICSharpCode.AvalonEdit.AddIn
} }
public event EventHandler CaretPositionChanged; public event EventHandler CaretPositionChanged;
bool caretPositionWasChanged;
void TextAreaCaretPositionChanged(object sender, EventArgs e) void TextAreaCaretPositionChanged(object sender, EventArgs e)
{ {
Debug.Assert(sender is Caret); Debug.Assert(sender is Caret);
Debug.Assert(!document.IsInUpdate);
if (sender == this.ActiveTextEditor.TextArea.Caret) { if (sender == this.ActiveTextEditor.TextArea.Caret) {
if (document.IsInUpdate)
caretPositionWasChanged = true;
else
HandleCaretPositionChange();
}
}
void DocumentUpdateFinished(object sender, EventArgs e)
{
if (caretPositionWasChanged) {
caretPositionWasChanged = false;
HandleCaretPositionChange(); HandleCaretPositionChange();
} }
} }

14
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs

@ -7,8 +7,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using ICSharpCode.AvalonEdit.AddIn.Snippets;
using ICSharpCode.AvalonEdit.Indentation; using ICSharpCode.AvalonEdit.Indentation;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
@ -25,7 +27,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
{ {
readonly CodeEditor codeEditor; readonly CodeEditor codeEditor;
public CodeEditorAdapter(CodeEditor codeEditor, TextEditor textEditor) : base(textEditor) public CodeEditorAdapter(CodeEditor codeEditor, CodeEditorView textEditor) : base(textEditor)
{ {
if (codeEditor == null) if (codeEditor == null)
throw new ArgumentNullException("codeEditor"); throw new ArgumentNullException("codeEditor");
@ -94,5 +96,15 @@ namespace ICSharpCode.AvalonEdit.AddIn
public override ITextEditor PrimaryView { public override ITextEditor PrimaryView {
get { return codeEditor.PrimaryTextEditorAdapter; } get { return codeEditor.PrimaryTextEditorAdapter; }
} }
public override IEnumerable<ICompletionItem> GetSnippets()
{
CodeSnippetGroup g = SnippetManager.Instance.FindGroup(Path.GetExtension(this.FileName));
if (g != null) {
return g.Snippets.Select(s => s.CreateCompletionItem(this));
} else {
return base.GetSnippets();
}
}
} }
} }

61
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs

@ -1,19 +1,20 @@
/* // <file>
* Created by SharpDevelop. // <copyright see="prj:///doc/copyright.txt"/>
* User: daniel // <license see="prj:///doc/license.txt"/>
* Date: 31.08.2009 // <owner name="Daniel Grunwald"/>
* Time: 14:55 // <version>$Revision$</version>
* // </file>
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using ICSharpCode.AvalonEdit.AddIn.Snippets;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
@ -41,6 +42,50 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.MouseHoverStopped += TextEditorMouseHoverStopped; this.MouseHoverStopped += TextEditorMouseHoverStopped;
this.MouseLeave += TextEditorMouseLeave; this.MouseLeave += TextEditorMouseLeave;
this.TextArea.TextView.MouseDown += TextViewMouseDown; this.TextArea.TextView.MouseDown += TextViewMouseDown;
var editingKeyBindings = this.TextArea.DefaultInputHandler.Editing.InputBindings.OfType<KeyBinding>();
var tabBinding = editingKeyBindings.Single(b => b.Key == Key.Tab && b.Modifiers == ModifierKeys.None);
tabBinding.Command = new CustomTabCommand(this, tabBinding.Command);
}
sealed class CustomTabCommand : ICommand
{
CodeEditorView editor;
ICommand baseCommand;
public CustomTabCommand(CodeEditorView editor, ICommand baseCommand)
{
this.editor = editor;
this.baseCommand = baseCommand;
}
public event EventHandler CanExecuteChanged {
add {}
remove {}
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (editor.SelectionLength == 0) {
int wordStart = DocumentUtilitites.FindPrevWordStart(editor.Adapter.Document, editor.CaretOffset);
if (wordStart > 0) {
string word = editor.Adapter.Document.GetText(wordStart, editor.CaretOffset - wordStart);
CodeSnippet snippet = SnippetManager.Instance.FindSnippet(Path.GetExtension(editor.Adapter.FileName),
word);
if (snippet != null) {
editor.Adapter.Document.Remove(wordStart, editor.CaretOffset - wordStart);
snippet.CreateAvalonEditSnippet(editor.Adapter).Insert(editor.TextArea);
return;
}
}
}
baseCommand.Execute(parameter);
}
} }
#region Help #region Help

17
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SharpDevelopCompletionWindow.cs

@ -114,10 +114,20 @@ namespace ICSharpCode.AvalonEdit.AddIn
} }
} }
/// <summary>
/// Completion item that supports complex content and description.
/// </summary>
public interface IFancyCompletionItem : ICompletionItem
{
object Content { get; }
new object Description { get; }
}
sealed class CodeCompletionDataAdapter : ICompletionData sealed class CodeCompletionDataAdapter : ICompletionData
{ {
readonly SharpDevelopCompletionWindow window; readonly SharpDevelopCompletionWindow window;
readonly ICompletionItem item; readonly ICompletionItem item;
readonly IFancyCompletionItem fancyCompletionItem;
public CodeCompletionDataAdapter(SharpDevelopCompletionWindow window, ICompletionItem item) public CodeCompletionDataAdapter(SharpDevelopCompletionWindow window, ICompletionItem item)
{ {
@ -127,6 +137,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
throw new ArgumentNullException("item"); throw new ArgumentNullException("item");
this.window = window; this.window = window;
this.item = item; this.item = item;
this.fancyCompletionItem = item as IFancyCompletionItem;
} }
public ICompletionItem Item { public ICompletionItem Item {
@ -138,12 +149,14 @@ namespace ICSharpCode.AvalonEdit.AddIn
} }
public object Content { public object Content {
get { return item.Text; } get {
return (fancyCompletionItem != null) ? fancyCompletionItem.Content : item.Text;
}
} }
public object Description { public object Description {
get { get {
return item.Description; return (fancyCompletionItem != null) ? fancyCompletionItem.Description : item.Description;
} }
} }

192
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippet.cs

@ -0,0 +1,192 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.AvalonEdit.AddIn.Snippets
{
/// <summary>
/// A code snippet.
/// </summary>
public class CodeSnippet : INotifyPropertyChanged
{
string name, description, text;
public string Name {
get { return name; }
set {
if (name != value) {
name = value;
OnPropertyChanged("Name");
}
}
}
public string Text {
get { return text; }
set {
if (text != value) {
text = value;
OnPropertyChanged("Text");
}
}
}
public string Description {
get { return description; }
set {
if (description != value) {
description = value;
OnPropertyChanged("Description");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public Snippet CreateAvalonEditSnippet(ITextEditor context)
{
return CreateAvalonEditSnippet(context, this.Text);
}
public ICompletionItem CreateCompletionItem(ITextEditor context)
{
return new SnippetCompletionItem(context, this);
}
readonly static Regex pattern = new Regex(@"\$\{([^\}]*)\}", RegexOptions.CultureInvariant);
public static Snippet CreateAvalonEditSnippet(ITextEditor context, string snippetText)
{
if (snippetText == null)
throw new ArgumentNullException("text");
var replaceableElements = new Dictionary<string, SnippetReplaceableTextElement>(StringComparer.OrdinalIgnoreCase);
foreach (Match m in pattern.Matches(snippetText)) {
string val = m.Groups[1].Value;
int equalsSign = val.IndexOf('=');
if (equalsSign > 0) {
string name = val.Substring(0, equalsSign);
replaceableElements[name] = new SnippetReplaceableTextElement();
}
}
Snippet snippet = new Snippet();
int pos = 0;
foreach (Match m in pattern.Matches(snippetText)) {
if (pos < m.Index) {
snippet.Elements.Add(new SnippetTextElement { Text = snippetText.Substring(pos, m.Index - pos) });
pos = m.Index;
}
snippet.Elements.Add(CreateElementForValue(context, replaceableElements, m.Groups[1].Value));
pos = m.Index + m.Length;
}
if (pos < snippetText.Length) {
snippet.Elements.Add(new SnippetTextElement { Text = snippetText.Substring(pos) });
}
return snippet;
}
readonly static Regex functionPattern = new Regex(@"^([a-zA-Z]+)\(([^\)]*)\)$", RegexOptions.CultureInvariant);
static SnippetElement CreateElementForValue(ITextEditor context, Dictionary<string, SnippetReplaceableTextElement> replaceableElements, string val)
{
SnippetReplaceableTextElement srte;
int equalsSign = val.IndexOf('=');
if (equalsSign > 0) {
string name = val.Substring(0, equalsSign);
if (replaceableElements.TryGetValue(name, out srte)) {
if (srte.Text == null)
srte.Text = val.Substring(equalsSign + 1);
return srte;
}
}
if ("Selection".Equals(val, StringComparison.OrdinalIgnoreCase))
return new SnippetCaretElement();
if (replaceableElements.TryGetValue(val, out srte))
return new SnippetBoundElement { TargetElement = srte };
Match m = functionPattern.Match(val);
if (m.Success) {
Func<string, string> f = GetFunction(context, m.Groups[1].Value);
if (f != null) {
string innerVal = m.Groups[2].Value;
if (replaceableElements.TryGetValue(innerVal, out srte))
return new FunctionBoundElement { TargetElement = srte, function = f };
string result2 = GetValue(context, innerVal);
if (result2 != null)
return new SnippetTextElement { Text = f(result2) };
else
return new SnippetTextElement { Text = f(innerVal) };
}
}
string result = GetValue(context, val);
if (result != null)
return new SnippetTextElement { Text = result };
else
return new SnippetReplaceableTextElement { Text = val }; // ${unknown} -> replaceable element
}
static string GetValue(ITextEditor editor, string propertyName)
{
if ("ClassName".Equals(propertyName, StringComparison.OrdinalIgnoreCase)) {
IClass c = GetCurrentClass(editor);
if (c != null)
return c.Name;
}
return Core.StringParser.GetValue(propertyName);
}
static IClass GetCurrentClass(ITextEditor editor)
{
var parseInfo = ParserService.GetExistingParseInformation(editor.FileName);
if (parseInfo != null) {
return parseInfo.CompilationUnit.GetInnermostClass(editor.Caret.Line, editor.Caret.Column);
}
return null;
}
static Func<string, string> GetFunction(ITextEditor context, string name)
{
if ("toLower".Equals(name, StringComparison.OrdinalIgnoreCase))
return s => s.ToLower();
if ("toUpper".Equals(name, StringComparison.OrdinalIgnoreCase))
return s => s.ToUpper();
if ("toFieldName".Equals(name, StringComparison.OrdinalIgnoreCase))
return s => context.Language.Properties.CodeGenerator.GetFieldName(s);
if ("toPropertyName".Equals(name, StringComparison.OrdinalIgnoreCase))
return s => context.Language.Properties.CodeGenerator.GetPropertyName(s);
if ("toParameterName".Equals(name, StringComparison.OrdinalIgnoreCase))
return s => context.Language.Properties.CodeGenerator.GetParameterName(s);
return null;
}
sealed class FunctionBoundElement : SnippetBoundElement
{
internal Func<string, string> function;
public override string ConvertText(string input)
{
return function(input);
}
}
}
}

47
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/CodeSnippetGroup.cs

@ -0,0 +1,47 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ICSharpCode.AvalonEdit.AddIn.Snippets
{
/// <summary>
/// A group of snippets (for a specific file extension).
/// </summary>
public class CodeSnippetGroup : INotifyPropertyChanged
{
string extensions = "";
ObservableCollection<CodeSnippet> snippets = new ObservableCollection<CodeSnippet>();
public ObservableCollection<CodeSnippet> Snippets {
get { return snippets; }
}
public string Extensions {
get { return extensions; }
set {
if (value == null)
throw new ArgumentNullException();
if (extensions != value) {
extensions = value;
OnPropertyChanged("Extensions");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

94
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetCompletionItem.cs

@ -0,0 +1,94 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows.Controls;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Snippets;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.AvalonEdit.AddIn.Snippets
{
/// <summary>
/// Code completion item for snippets.
/// </summary>
public class SnippetCompletionItem : IFancyCompletionItem
{
readonly CodeSnippet codeSnippet;
readonly ITextEditor textEditor;
readonly TextArea textArea;
public SnippetCompletionItem(ITextEditor textEditor, CodeSnippet codeSnippet)
{
if (textEditor == null)
throw new ArgumentNullException("textEditor");
if (codeSnippet == null)
throw new ArgumentNullException("codeSnippet");
this.textEditor = textEditor;
this.textArea = textEditor.GetService(typeof(TextArea)) as TextArea;
if (textArea == null)
throw new ArgumentException("textEditor must be an AvalonEdit text editor");
this.codeSnippet = codeSnippet;
}
public string Text {
get { return codeSnippet.Name; }
}
public string Description {
get {
return codeSnippet.Description + Environment.NewLine +
ResourceService.GetString("Dialog.Options.CodeTemplate.PressTabToInsertTemplate");
}
}
public ICSharpCode.SharpDevelop.IImage Image {
get {
return ClassBrowserIconService.CodeTemplate;
}
}
public void Complete(CompletionContext context)
{
if (context.Editor != this.textEditor)
throw new ArgumentException("wrong editor");
context.Editor.Document.Remove(context.StartOffset, context.Length);
CreateSnippet().Insert(textArea);
}
Snippet CreateSnippet()
{
return codeSnippet.CreateAvalonEditSnippet(textEditor);
}
object IFancyCompletionItem.Content {
get {
return Text;
}
}
TextBlock fancyDescription;
object IFancyCompletionItem.Description {
get {
if (fancyDescription == null) {
fancyDescription = new TextBlock();
fancyDescription.Inlines.Add(new Run(this.Description + Environment.NewLine + Environment.NewLine));
Inline r = CreateSnippet().ToTextRun();
r.FontFamily = textArea.FontFamily;
fancyDescription.Inlines.Add(r);
}
return fancyDescription;
}
}
}
}

153
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetManager.cs

@ -0,0 +1,153 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.Core;
namespace ICSharpCode.AvalonEdit.AddIn.Snippets
{
/// <summary>
/// SnippetManager singleton.
/// </summary>
public sealed class SnippetManager
{
public static readonly SnippetManager Instance = new SnippetManager();
readonly object lockObj = new object();
static readonly List<CodeSnippetGroup> defaultSnippets = new List<CodeSnippetGroup> {
new CodeSnippetGroup {
Extensions = ".cs",
Snippets = {
new CodeSnippet {
Name = "for",
Description = "for loop",
Text = "for (int ${counter=i} = 0; ${counter} < ${end}; ${counter}++) {\n\t${Selection}\n}"
},
new CodeSnippet {
Name = "foreach",
Description = "foreach loop",
Text = "foreach (${var} ${element} in ${collection}) {\n\t${Selection}\n}"
},
new CodeSnippet {
Name = "if",
Description = "if statement",
Text = "if (${condition}) {\n\t${Selection}\n}"
},
new CodeSnippet {
Name = "ifelse",
Description = "if-else statement",
Text = "if (${condition}) {\n\t${Selection}\n} else {\n\t\n}"
},
new CodeSnippet {
Name = "while",
Description = "while loop",
Text = "while (${condition}) {\n\t${Selection}\n}"
},
new CodeSnippet {
Name = "prop",
Description = "Property",
Text = "${type} ${toFieldName(name)};\n\npublic ${type=int} ${name=Property} {\n\tget { return ${toFieldName(name)}; }\n\tset { ${toFieldName(name)} = value; }\n}"
},
new CodeSnippet {
Name = "propdp",
Description = "Dependency Property",
Text = "public static readonly DependencyProperty ${name}Property =" + Environment.NewLine
+ "\tDependencyProperty.Register(\"${name}\", typeof(${type}), typeof(${ClassName})," + Environment.NewLine
+ "\t new FrameworkPropertyMetadata());" + Environment.NewLine
+ "" + Environment.NewLine
+ "public ${type=int} ${name=Property} {" + Environment.NewLine
+ "\tget { return (${type})GetValue(${name}Property); }" + Environment.NewLine
+ "\tset { SetValue(${name}Property, value); }"
+ Environment.NewLine + "}"
},
new CodeSnippet {
Name = "ctor",
Description = "Constructor",
Text = "public ${ClassName}()\n{\t\n${Selection}\n}"
},
new CodeSnippet {
Name = "switch",
Description = "Switch statement",
Text = "switch (${condition}) {\n\tcase ${firstcase=0}:\n\t\tbreak;\n\tdefault:\n\t\t${Selection}\n\t\tbreak;\n}"
},
new CodeSnippet {
Name = "try",
Description = "Try-catch statement",
Text = "try {\n\t${Selection}\n} catch (Exception) {\n\t\n\tthrow;\n}"
},
new CodeSnippet {
Name = "trycf",
Description = "Try-catch-finally statement",
Text = "try {\n\t${Selection}\n} catch (Exception) {\n\t\n\tthrow;\n} finally {\n\t\n}"
},
new CodeSnippet {
Name = "tryf",
Description = "Try-finally statement",
Text = "try {\n\t${Selection}\n} finally {\n\t\n}"
},
}
}
};
private SnippetManager() {}
/// <summary>
/// Loads copies of all code snippet groups.
/// </summary>
public List<CodeSnippetGroup> LoadGroups()
{
return PropertyService.Get("CodeSnippets", defaultSnippets);
}
/// <summary>
/// Saves the set of groups.
/// </summary>
public void SaveGroups(IEnumerable<CodeSnippetGroup> groups)
{
lock (lockObj) {
activeGroups = null;
PropertyService.Set("CodeSnippets", groups.ToList());
}
}
ReadOnlyCollection<CodeSnippetGroup> activeGroups;
public ReadOnlyCollection<CodeSnippetGroup> ActiveGroups {
get {
lock (lockObj) {
if (activeGroups == null)
activeGroups = LoadGroups().AsReadOnly();
return activeGroups;
}
}
}
public CodeSnippetGroup FindGroup(string extension)
{
foreach (CodeSnippetGroup g in ActiveGroups) {
string[] extensions = g.Extensions.Split(';');
foreach (string gext in extensions) {
if (gext.Equals(extension, StringComparison.OrdinalIgnoreCase))
return g;
}
}
return null;
}
public CodeSnippet FindSnippet(string extension, string name)
{
CodeSnippetGroup g = FindGroup(extension);
if (g != null) {
return g.Snippets.FirstOrDefault(s => s.Name == name);
}
return null;
}
}
}

110
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetOptionPanel.cs

@ -0,0 +1,110 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
namespace ICSharpCode.AvalonEdit.AddIn.Snippets
{
/// <summary>
/// Interaction logic for Snippets.xaml
/// </summary>
public partial class SnippetOptionPanel : UserControl, IOptionPanel
{
ObservableCollection<CodeSnippetGroup> groups;
public SnippetOptionPanel()
{
InitializeComponent();
}
public object Owner { get; set; }
public object Control {
get { return this; }
}
public void LoadOptions()
{
groups = new ObservableCollection<CodeSnippetGroup>(SnippetManager.Instance.LoadGroups().OrderBy(g => g.Extensions));
extensionComboBox.ItemsSource = groups;
extensionComboBox.SelectedItem = groups.FirstOrDefault();
}
public bool SaveOptions()
{
SnippetManager.Instance.SaveGroups(groups);
return true;
}
void AddGroupButton_Click(object sender, RoutedEventArgs e)
{
string result = MessageService.ShowInputBox(
"${res:Dialog.Options.CodeTemplate.AddGroupLabel}",
"${res:Dialog.Options.CodeTemplate.EditGroupDialog.Text}",
"");
if (!string.IsNullOrEmpty(result)) {
CodeSnippetGroup g = new CodeSnippetGroup();
g.Extensions = result;
groups.Add(g);
extensionComboBox.SelectedItem = g;
}
}
void RemoveGroupButton_Click(object sender, RoutedEventArgs e)
{
if (extensionComboBox.SelectedIndex >= 0)
groups.RemoveAt(extensionComboBox.SelectedIndex);
}
void EditGroupButton_Click(object sender, RoutedEventArgs e)
{
CodeSnippetGroup g = (CodeSnippetGroup)extensionComboBox.SelectedItem;
if (g != null) {
string result = MessageService.ShowInputBox(
"${res:Dialog.Options.CodeTemplate.EditGroupLabel}",
"${res:Dialog.Options.CodeTemplate.EditGroupDialog.Text}",
g.Extensions);
if (!string.IsNullOrEmpty(result))
g.Extensions = result;
}
}
void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CodeSnippet snippet = dataGrid.SelectedItem as CodeSnippet;
if (snippet != null) {
snippetTextBox.Text = snippet.Text;
snippetTextBox.IsReadOnly = false;
snippetTextBox.Background = SystemColors.WindowBrush;
} else {
snippetTextBox.Text = null;
snippetTextBox.IsReadOnly = true;
snippetTextBox.Background = SystemColors.ControlBrush;
}
}
void SnippetTextBox_TextChanged(object sender, EventArgs e)
{
CodeSnippet snippet = dataGrid.SelectedItem as CodeSnippet;
if (snippet != null)
snippet.Text = snippetTextBox.Text;
}
}
}

122
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Snippets/SnippetOptionPanel.xaml

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="ICSharpCode.AvalonEdit.AddIn.Snippets.SnippetOptionPanel" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:AvalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit">
<Grid>
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="1*" />
<RowDefinition
Height="1*" />
</Grid.RowDefinitions>
<Grid
Grid.Column="0"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition
Height="Auto" />
<RowDefinition
Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Label
Content="{core:StringParse ${res:Dialog.Options.CodeTemplate.ExtensionsLabel}:}"
Grid.Column="0"
Grid.Row="0"
Target="{Binding ElementName=extensionComboBox}" />
<ComboBox
Name="extensionComboBox"
DisplayMemberPath="Extensions"
Grid.Column="1"
Grid.Row="0"
Height="23" />
<StackPanel
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
Orientation="Horizontal">
<Button
Content="{core:Localize Dialog.Options.CodeTemplate.AddGroupLabel}"
Margin="0,8,0,8"
Height="23"
Padding="9,1,9,1"
Click="AddGroupButton_Click" />
<Button
Content="{core:Localize Dialog.Options.CodeTemplate.RemoveGroupLabel}"
Margin="8,8,0,8"
Height="23"
Padding="9,1,9,1"
Click="RemoveGroupButton_Click" />
<Button
Content="{core:Localize Dialog.Options.CodeTemplate.EditGroupLabel}"
Margin="8,8,0,8"
Height="23"
Padding="9,1,9,1"
Click="EditGroupButton_Click" />
</StackPanel>
</Grid>
<!--<DockPanel
Grid.Row="1"
Grid.Column="0">
<StackPanel
DockPanel.Dock="Right"
VerticalAlignment="Center">
<Button
Content="{core:Localize Global.AddButtonText}"
Height="23"
Margin="4,4,4,4"
Padding="9,1,9,1"
Click="AddSnippetButton_Click" />
<Button
Content="{core:Localize Global.EditButtonText}"
Height="23"
Margin="4,4,4,4"
Padding="9,1,9,1"
Click="EditSnippetButton_Click" />
<Button
Content="{core:Localize Global.RemoveButtonText}"
Height="23"
Margin="4,4,4,4"
Padding="9,1,9,1"
Click="RemoveSnippetButton_Click" />
</StackPanel>-->
<DataGrid
Grid.Row="1"
Grid.Column="0"
x:Name="dataGrid"
SelectionMode="Single"
CanUserAddRows="True"
CanUserDeleteRows="True"
SelectionUnit="FullRow"
HeadersVisibility="Column"
CanUserResizeRows="False"
AutoGenerateColumns="False"
ItemsSource="{Binding ElementName=extensionComboBox, Path=SelectedItem.Snippets}"
SelectionChanged="DataGrid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn
Header="{core:Localize Dialog.Options.CodeTemplate.Template}"
Binding="{Binding Name}" />
<DataGridTextColumn
Header="{core:Localize Dialog.Options.CodeTemplate.Description}"
Width="*"
Binding="{Binding Description}" />
</DataGrid.Columns>
</DataGrid>
<!--</DockPanel>-->
<AvalonEdit:TextEditor
x:Name="snippetTextBox"
Grid.Column="0"
Grid.Row="2"
FontFamily="Consolas, Courier New"
TextChanged="SnippetTextBox_TextChanged"/>
</Grid>
</UserControl>

36
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

@ -98,15 +98,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
base.OnSourceInitialized(e); base.OnSourceInitialized(e);
} }
InputHandler myInputHandler;
void AttachEvents() void AttachEvents()
{ {
this.TextArea.Caret.PositionChanged += CaretPositionChanged; this.TextArea.Caret.PositionChanged += CaretPositionChanged;
this.TextArea.MouseWheel += textArea_MouseWheel; this.TextArea.MouseWheel += textArea_MouseWheel;
this.TextArea.PreviewTextInput += textArea_PreviewTextInput; this.TextArea.PreviewTextInput += textArea_PreviewTextInput;
myInputHandler = new InputHandler(this);
this.TextArea.PushStackedInputHandler(myInputHandler);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -116,40 +112,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.MouseWheel -= textArea_MouseWheel; this.TextArea.MouseWheel -= textArea_MouseWheel;
this.TextArea.PreviewTextInput -= textArea_PreviewTextInput; this.TextArea.PreviewTextInput -= textArea_PreviewTextInput;
base.DetachEvents(); base.DetachEvents();
this.TextArea.PopStackedInputHandler(myInputHandler);
} }
#region InputHandler
/// <summary>
/// A dummy input handler (that justs invokes the default input handler).
/// This is used to ensure the completion window closes when any other input handler
/// becomes active.
/// </summary>
sealed class InputHandler : ITextAreaInputHandler
{
readonly CompletionWindow window;
public InputHandler(CompletionWindow window)
{
Debug.Assert(window != null);
this.window = window;
}
public TextArea TextArea {
get { return window.TextArea; }
}
public void Attach()
{
}
public void Detach()
{
window.Close();
}
}
#endregion
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
{ {

51
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs

@ -67,11 +67,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.PreviewLostKeyboardFocus += TextAreaLostFocus; this.TextArea.PreviewLostKeyboardFocus += TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged; this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged += TextAreaDocumentChanged; this.TextArea.DocumentChanged += TextAreaDocumentChanged;
this.TextArea.PreviewKeyDown += TextAreaPreviewKeyDown;
this.TextArea.PreviewKeyUp += TextAreaPreviewKeyUp;
if (parentWindow != null) { if (parentWindow != null) {
parentWindow.LocationChanged += parentWindow_LocationChanged; parentWindow.LocationChanged += parentWindow_LocationChanged;
} }
myInputHandler = new InputHandler(this);
this.TextArea.PushStackedInputHandler(myInputHandler);
} }
/// <summary> /// <summary>
@ -85,24 +86,50 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.PreviewLostKeyboardFocus -= TextAreaLostFocus; this.TextArea.PreviewLostKeyboardFocus -= TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged; this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged -= TextAreaDocumentChanged; this.TextArea.DocumentChanged -= TextAreaDocumentChanged;
this.TextArea.PreviewKeyDown -= TextAreaPreviewKeyDown;
this.TextArea.PreviewKeyUp -= TextAreaPreviewKeyUp;
if (parentWindow != null) { if (parentWindow != null) {
parentWindow.LocationChanged -= parentWindow_LocationChanged; parentWindow.LocationChanged -= parentWindow_LocationChanged;
} }
this.TextArea.PopStackedInputHandler(myInputHandler);
} }
void TextAreaPreviewKeyDown(object sender, KeyEventArgs e) #region InputHandler
{ InputHandler myInputHandler;
e.Handled = RaiseEventPair(this, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
void TextAreaPreviewKeyUp(object sender, KeyEventArgs e) /// <summary>
/// A dummy input handler (that justs invokes the default input handler).
/// This is used to ensure the completion window closes when any other input handler
/// becomes active.
/// </summary>
sealed class InputHandler : TextAreaStackedInputHandler
{ {
e.Handled = RaiseEventPair(this, PreviewKeyUpEvent, KeyUpEvent, readonly CompletionWindowBase window;
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
public InputHandler(CompletionWindowBase window)
: base(window.TextArea)
{
Debug.Assert(window != null);
this.window = window;
}
public override void Detach()
{
base.Detach();
window.Close();
}
public override void OnPreviewKeyDown(KeyEventArgs e)
{
e.Handled = RaiseEventPair(window, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
public override void OnPreviewKeyUp(KeyEventArgs e)
{
e.Handled = RaiseEventPair(window, PreviewKeyUpEvent, KeyUpEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
} }
#endregion
void TextViewScrollOffsetChanged(object sender, EventArgs e) void TextViewScrollOffsetChanged(object sender, EventArgs e)
{ {

32
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs

@ -82,9 +82,7 @@ namespace ICSharpCode.AvalonEdit.Editing
ValidatePosition(); ValidatePosition();
InvalidateVisualColumn(); InvalidateVisualColumn();
if (PositionChanged != null) { RaisePositionChanged();
PositionChanged(this, EventArgs.Empty);
}
Log("Caret position changed to " + value); Log("Caret position changed to " + value);
if (visible) if (visible)
Show(); Show();
@ -218,13 +216,33 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <summary> /// <summary>
/// Event raised when the caret position has changed. /// Event raised when the caret position has changed.
/// This event might be raised multiple times during a big update operation. /// If the caret position is changed inside a document update (between BeginUpdate/EndUpdate calls),
/// You might want to check TextDocument.IsInUpdate and delay time-consuming /// the PositionChanged event is raised only once at the end of the document update.
/// actions until the update operation ends.
/// TODO: only raise this event outside of document updates
/// </summary> /// </summary>
public event EventHandler PositionChanged; public event EventHandler PositionChanged;
bool raisePositionChangedOnUpdateFinished;
void RaisePositionChanged()
{
if (textArea.Document != null && textArea.Document.IsInUpdate) {
raisePositionChangedOnUpdateFinished = true;
} else {
if (PositionChanged != null) {
PositionChanged(this, EventArgs.Empty);
}
}
}
internal void OnDocumentUpdateFinished()
{
if (raisePositionChangedOnUpdateFinished) {
if (PositionChanged != null) {
PositionChanged(this, EventArgs.Empty);
}
}
}
bool visualColumnValid; bool visualColumnValid;
void ValidateVisualColumn() void ValidateVisualColumn()

47
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

@ -128,13 +128,13 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary> /// </summary>
public event EventHandler ActiveInputHandlerChanged; public event EventHandler ActiveInputHandlerChanged;
ImmutableStack<ITextAreaInputHandler> stackedInputHandlers = ImmutableStack<ITextAreaInputHandler>.Empty; ImmutableStack<TextAreaStackedInputHandler> stackedInputHandlers = ImmutableStack<TextAreaStackedInputHandler>.Empty;
/// <summary> /// <summary>
/// Gets the list of currently active stacked input handlers. /// Gets the list of currently active stacked input handlers.
/// </summary> /// </summary>
/// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks> /// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks>
public ImmutableStack<ITextAreaInputHandler> StackedInputHandlers { public ImmutableStack<TextAreaStackedInputHandler> StackedInputHandlers {
get { return stackedInputHandlers; } get { return stackedInputHandlers; }
} }
@ -142,7 +142,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// Pushes an input handler onto the list of stacked input handlers. /// Pushes an input handler onto the list of stacked input handlers.
/// </summary> /// </summary>
/// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks> /// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks>
public void PushStackedInputHandler(ITextAreaInputHandler inputHandler) public void PushStackedInputHandler(TextAreaStackedInputHandler inputHandler)
{ {
if (inputHandler == null) if (inputHandler == null)
throw new ArgumentNullException("inputHandler"); throw new ArgumentNullException("inputHandler");
@ -156,7 +156,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// does nothing. /// does nothing.
/// </summary> /// </summary>
/// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks> /// <remarks><inheritdoc cref="ITextAreaInputHandler"/></remarks>
public void PopStackedInputHandler(ITextAreaInputHandler inputHandler) public void PopStackedInputHandler(TextAreaStackedInputHandler inputHandler)
{ {
if (stackedInputHandlers.Any(i => i == inputHandler)) { if (stackedInputHandlers.Any(i => i == inputHandler)) {
ITextAreaInputHandler oldHandler; ITextAreaInputHandler oldHandler;
@ -198,11 +198,13 @@ namespace ICSharpCode.AvalonEdit.Editing
TextDocumentWeakEventManager.Changing.RemoveListener(oldValue, this); TextDocumentWeakEventManager.Changing.RemoveListener(oldValue, this);
TextDocumentWeakEventManager.Changed.RemoveListener(oldValue, this); TextDocumentWeakEventManager.Changed.RemoveListener(oldValue, this);
TextDocumentWeakEventManager.UpdateStarted.RemoveListener(oldValue, this); TextDocumentWeakEventManager.UpdateStarted.RemoveListener(oldValue, this);
TextDocumentWeakEventManager.UpdateFinished.RemoveListener(oldValue, this);
} }
if (newValue != null) { if (newValue != null) {
TextDocumentWeakEventManager.Changing.AddListener(newValue, this); TextDocumentWeakEventManager.Changing.AddListener(newValue, this);
TextDocumentWeakEventManager.Changed.AddListener(newValue, this); TextDocumentWeakEventManager.Changed.AddListener(newValue, this);
TextDocumentWeakEventManager.UpdateStarted.AddListener(newValue, this); TextDocumentWeakEventManager.UpdateStarted.AddListener(newValue, this);
TextDocumentWeakEventManager.UpdateFinished.AddListener(newValue, this);
} }
if (DocumentChanged != null) if (DocumentChanged != null)
DocumentChanged(this, EventArgs.Empty); DocumentChanged(this, EventArgs.Empty);
@ -262,7 +264,7 @@ namespace ICSharpCode.AvalonEdit.Editing
protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{ {
if (managerType == typeof(TextDocumentWeakEventManager.Changing)) { if (managerType == typeof(TextDocumentWeakEventManager.Changing)) {
caret.OnDocumentChanging(); OnDocumentChanging();
return true; return true;
} else if (managerType == typeof(TextDocumentWeakEventManager.Changed)) { } else if (managerType == typeof(TextDocumentWeakEventManager.Changed)) {
OnDocumentChanged((DocumentChangeEventArgs)e); OnDocumentChanged((DocumentChangeEventArgs)e);
@ -270,6 +272,9 @@ namespace ICSharpCode.AvalonEdit.Editing
} else if (managerType == typeof(TextDocumentWeakEventManager.UpdateStarted)) { } else if (managerType == typeof(TextDocumentWeakEventManager.UpdateStarted)) {
OnUpdateStarted(); OnUpdateStarted();
return true; return true;
} else if (managerType == typeof(TextDocumentWeakEventManager.UpdateFinished)) {
OnUpdateFinished();
return true;
} else if (managerType == typeof(PropertyChangedWeakEventManager)) { } else if (managerType == typeof(PropertyChangedWeakEventManager)) {
OnOptionChanged((PropertyChangedEventArgs)e); OnOptionChanged((PropertyChangedEventArgs)e);
return true; return true;
@ -284,6 +289,11 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region Caret handling on document changes #region Caret handling on document changes
void OnDocumentChanging()
{
caret.OnDocumentChanging();
}
void OnDocumentChanged(DocumentChangeEventArgs e) void OnDocumentChanged(DocumentChangeEventArgs e)
{ {
caret.OnDocumentChanged(e); caret.OnDocumentChanged(e);
@ -295,6 +305,11 @@ namespace ICSharpCode.AvalonEdit.Editing
Document.UndoStack.PushOptional(new RestoreCaretAndSelectionUndoAction(this)); Document.UndoStack.PushOptional(new RestoreCaretAndSelectionUndoAction(this));
} }
void OnUpdateFinished()
{
caret.OnDocumentUpdateFinished();
}
sealed class RestoreCaretAndSelectionUndoAction : IUndoableOperation sealed class RestoreCaretAndSelectionUndoAction : IUndoableOperation
{ {
// keep textarea in weak reference because the IUndoableOperation is stored with the document // keep textarea in weak reference because the IUndoableOperation is stored with the document
@ -870,6 +885,28 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion #endregion
#region OnKeyDown/OnKeyUp #region OnKeyDown/OnKeyUp
/// <inheritdoc/>
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
foreach (TextAreaStackedInputHandler h in stackedInputHandlers) {
if (e.Handled)
break;
h.OnPreviewKeyDown(e);
}
}
/// <inheritdoc/>
protected override void OnPreviewKeyUp(KeyEventArgs e)
{
base.OnPreviewKeyUp(e);
foreach (TextAreaStackedInputHandler h in stackedInputHandlers) {
if (e.Handled)
break;
h.OnPreviewKeyUp(e);
}
}
// Make life easier for text editor extensions that use a different cursor based on the pressed modifier keys. // Make life easier for text editor extensions that use a different cursor based on the pressed modifier keys.
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)

48
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs

@ -49,6 +49,54 @@ namespace ICSharpCode.AvalonEdit.Editing
void Detach(); void Detach();
} }
/// <summary>
/// Stacked input handler.
/// Uses OnEvent-methods instead of registering event handlers to ensure that the events are handled in the correct order.
/// </summary>
public abstract class TextAreaStackedInputHandler : ITextAreaInputHandler
{
readonly TextArea textArea;
/// <inheritdoc/>
public TextArea TextArea {
get { return textArea; }
}
/// <summary>
/// Creates a new TextAreaInputHandler.
/// </summary>
public TextAreaStackedInputHandler(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this.textArea = textArea;
}
/// <inheritdoc/>
public virtual void Attach()
{
}
/// <inheritdoc/>
public virtual void Detach()
{
}
/// <summary>
/// Called for the PreviewKeyDown event.
/// </summary>
public virtual void OnPreviewKeyDown(KeyEventArgs e)
{
}
/// <summary>
/// Called for the PreviewKeyUp event.
/// </summary>
public virtual void OnPreviewKeyUp(KeyEventArgs e)
{
}
}
/// <summary> /// <summary>
/// Default-implementation of <see cref="ITextAreaInputHandler"/>. /// Default-implementation of <see cref="ITextAreaInputHandler"/>.
/// </summary> /// </summary>

14
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs

@ -579,12 +579,20 @@ namespace ICSharpCode.AvalonEdit.Rendering
Dispatcher.VerifyAccess(); Dispatcher.VerifyAccess();
if (inMeasure) if (inMeasure)
throw new InvalidOperationException("The visual line build process is already running! Cannot EnsureVisualLines() during Measure!"); throw new InvalidOperationException("The visual line build process is already running! Cannot EnsureVisualLines() during Measure!");
if (visibleVisualLines == null) { if (!VisualLinesValid) {
// increase priority for re-measure // increase priority for re-measure
InvalidateMeasure(DispatcherPriority.Normal); InvalidateMeasure(DispatcherPriority.Normal);
// force immediate re-measure // force immediate re-measure
UpdateLayout(); UpdateLayout();
} }
// Sometimes we still have invalid lines after UpdateLayout - work around the problem
// by calling MeasureOverride directly.
if (!VisualLinesValid) {
Debug.WriteLine("UpdateLayout() failed in EnsureVisualLines");
MeasureOverride(lastAvailableSize);
}
if (!VisualLinesValid)
throw new VisualLinesInvalidException("Internal error: visual lines invalid after EnsureVisualLines call");
} }
#endregion #endregion
@ -800,8 +808,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// </summary> /// </summary>
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
if (!VisualLinesValid) EnsureVisualLines();
throw new VisualLinesInvalidException();
foreach (UIElement layer in layers) { foreach (UIElement layer in layers) {
layer.Arrange(new Rect(new Point(0, 0), finalSize)); layer.Arrange(new Rect(new Point(0, 0), finalSize));
} }

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/InsertionContext.cs

@ -185,7 +185,8 @@ namespace ICSharpCode.AvalonEdit.Snippets
Deactivate(EventArgs.Empty); Deactivate(EventArgs.Empty);
} else { } else {
myInputHandler = new SnippetInputHandler(this); myInputHandler = new SnippetInputHandler(this);
foreach (ITextAreaInputHandler h in TextArea.StackedInputHandlers) { // disable existing snippet input handlers - there can be only 1 active snippet
foreach (TextAreaStackedInputHandler h in TextArea.StackedInputHandlers) {
if (h is SnippetInputHandler) if (h is SnippetInputHandler)
TextArea.PopStackedInputHandler(h); TextArea.PopStackedInputHandler(h);
} }

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/Snippet.cs

@ -7,6 +7,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;

13
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetBoundElement.cs

@ -6,6 +6,7 @@
// </file> // </file>
using System; using System;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Snippets namespace ICSharpCode.AvalonEdit.Snippets
@ -48,6 +49,18 @@ namespace ICSharpCode.AvalonEdit.Snippets
context.RegisterActiveElement(this, new BoundActiveElement(context, targetElement, this, segment)); context.RegisterActiveElement(this, new BoundActiveElement(context, targetElement, this, segment));
} }
} }
/// <inheritdoc/>
public override Inline ToTextRun()
{
if (targetElement != null) {
string inputText = targetElement.Text;
if (inputText != null) {
return new Italic(new Run(ConvertText(inputText)));
}
}
return base.ToTextRun();
}
} }
sealed class BoundActiveElement : IActiveElement sealed class BoundActiveElement : IActiveElement

15
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetContainerElement.cs

@ -7,6 +7,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;
@ -34,5 +37,17 @@ namespace ICSharpCode.AvalonEdit.Snippets
e.Insert(context); e.Insert(context);
} }
} }
/// <inheritdoc/>
public override Inline ToTextRun()
{
Span span = new Span();
foreach (SnippetElement e in this.Elements) {
Inline r = e.ToTextRun();
if (r != null)
span.Inlines.Add(r);
}
return span;
}
} }
} }

10
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetElement.cs

@ -7,6 +7,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;
@ -22,5 +24,13 @@ namespace ICSharpCode.AvalonEdit.Snippets
/// Performs insertion of the snippet. /// Performs insertion of the snippet.
/// </summary> /// </summary>
public abstract void Insert(InsertionContext context); public abstract void Insert(InsertionContext context);
/// <summary>
/// Converts the snippet to text, with replaceable fields in italic.
/// </summary>
public virtual Inline ToTextRun()
{
return null;
}
} }
} }

34
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetInputHandler.cs

@ -16,42 +16,32 @@ using ICSharpCode.AvalonEdit.Editing;
namespace ICSharpCode.AvalonEdit.Snippets namespace ICSharpCode.AvalonEdit.Snippets
{ {
sealed class SnippetInputHandler : ITextAreaInputHandler sealed class SnippetInputHandler : TextAreaStackedInputHandler
{ {
readonly InsertionContext context; readonly InsertionContext context;
public SnippetInputHandler(InsertionContext context) public SnippetInputHandler(InsertionContext context)
: base(context.TextArea)
{ {
this.context = context; this.context = context;
} }
public TextArea TextArea { public override void Attach()
get { return context.TextArea; }
}
public void Attach()
{ {
TextArea.PreviewKeyDown += TextArea_PreviewKeyDown; base.Attach();
SelectElement(FindNextEditableElement(-1, false)); SelectElement(FindNextEditableElement(-1, false));
} }
void SelectElement(IActiveElement element) public override void Detach()
{
if (element != null) {
TextArea.Selection = new SimpleSelection(element.Segment);
TextArea.Caret.Offset = element.Segment.EndOffset;
}
}
public void Detach()
{ {
TextArea.PreviewKeyDown -= TextArea_PreviewKeyDown; base.Detach();
context.Deactivate(EventArgs.Empty); context.Deactivate(EventArgs.Empty);
} }
void TextArea_PreviewKeyDown(object sender, KeyEventArgs e) public override void OnPreviewKeyDown(KeyEventArgs e)
{ {
base.OnPreviewKeyDown(e);
if (e.Key == Key.Escape || e.Key == Key.Return) { if (e.Key == Key.Escape || e.Key == Key.Return) {
context.Deactivate(e); context.Deactivate(e);
e.Handled = true; e.Handled = true;
@ -62,6 +52,14 @@ namespace ICSharpCode.AvalonEdit.Snippets
} }
} }
void SelectElement(IActiveElement element)
{
if (element != null) {
TextArea.Selection = new SimpleSelection(element.Segment);
TextArea.Caret.Offset = element.Segment.EndOffset;
}
}
IActiveElement FindNextEditableElement(int offset, bool backwards) IActiveElement FindNextEditableElement(int offset, bool backwards)
{ {
IEnumerable<IActiveElement> elements = context.ActiveElements.Where(e => e.IsEditable && e.Segment != null); IEnumerable<IActiveElement> elements = context.ActiveElements.Where(e => e.IsEditable && e.Segment != null);

9
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetReplaceableTextElement.cs

@ -6,10 +6,11 @@
// </file> // </file>
using System; using System;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using System.Linq;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
@ -31,6 +32,12 @@ namespace ICSharpCode.AvalonEdit.Snippets
int end = context.InsertionPosition; int end = context.InsertionPosition;
context.RegisterActiveElement(this, new ReplaceableActiveElement(context, start, end)); context.RegisterActiveElement(this, new ReplaceableActiveElement(context, start, end));
} }
/// <inheritdoc/>
public override Inline ToTextRun()
{
return new Italic(base.ToTextRun());
}
} }
/// <summary> /// <summary>

7
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/SnippetTextElement.cs

@ -6,6 +6,7 @@
// </file> // </file>
using System; using System;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Snippets namespace ICSharpCode.AvalonEdit.Snippets
@ -32,5 +33,11 @@ namespace ICSharpCode.AvalonEdit.Snippets
if (text != null) if (text != null)
context.InsertText(text); context.InsertText(text);
} }
/// <inheritdoc/>
public override Inline ToTextRun()
{
return new Run(text ?? string.Empty);
}
} }
} }

10
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -92,7 +92,6 @@
<Compile Include="Src\Editor\CodeCompletion\OverrideCompletionItem.cs"> <Compile Include="Src\Editor\CodeCompletion\OverrideCompletionItem.cs">
</Compile> </Compile>
<Compile Include="Src\Editor\CodeCompletion\OverrideCompletionItemProvider.cs" /> <Compile Include="Src\Editor\CodeCompletion\OverrideCompletionItemProvider.cs" />
<Compile Include="Src\Editor\CodeCompletion\TemplateCompletionItemProvider.cs" />
<Compile Include="Src\Editor\CodeCompletion\TextCompletionItemProvider.cs" /> <Compile Include="Src\Editor\CodeCompletion\TextCompletionItemProvider.cs" />
<Compile Include="Src\Editor\Commands\CommentRegion.cs" /> <Compile Include="Src\Editor\Commands\CommentRegion.cs" />
<Compile Include="Src\Editor\Commands\GoToDefinition.cs" /> <Compile Include="Src\Editor\Commands\GoToDefinition.cs" />
@ -208,7 +207,6 @@
<Compile Include="Src\Internal\ConditionEvaluators\WriteableSolutionEvaluator.cs" /> <Compile Include="Src\Internal\ConditionEvaluators\WriteableSolutionEvaluator.cs" />
<Compile Include="Src\Internal\Doozers\IOptionPanel.cs" /> <Compile Include="Src\Internal\Doozers\IOptionPanel.cs" />
<Compile Include="Src\Internal\ExternalTool\ExternalTool.cs" /> <Compile Include="Src\Internal\ExternalTool\ExternalTool.cs" />
<Compile Include="Src\Internal\Templates\CodeTemplate.cs" />
<Compile Include="Src\Internal\Templates\Project\ProjectTemplate.cs" /> <Compile Include="Src\Internal\Templates\Project\ProjectTemplate.cs" />
<Compile Include="Src\Internal\Templates\File\FileDescriptionTemplate.cs" /> <Compile Include="Src\Internal\Templates\File\FileDescriptionTemplate.cs" />
<Compile Include="Src\Internal\Templates\File\FileTemplate.cs" /> <Compile Include="Src\Internal\Templates\File\FileTemplate.cs" />
@ -271,13 +269,13 @@
<Compile Include="Src\Services\ParserService\LoadSolutionProjects.cs" /> <Compile Include="Src\Services\ParserService\LoadSolutionProjects.cs" />
<Compile Include="Src\Services\ParserService\ParserService.cs" /> <Compile Include="Src\Services\ParserService\ParserService.cs" />
<Compile Include="Src\Services\ProjectService\CompileModifiedProjectsOnly.cs" /> <Compile Include="Src\Services\ProjectService\CompileModifiedProjectsOnly.cs" />
<Compile Include="Src\Services\ProjectService\SolutionConfigurationEventHandler.cs" />
<Compile Include="Src\Services\RefactoringService\ExtractInterfaceOptions.cs" /> <Compile Include="Src\Services\RefactoringService\ExtractInterfaceOptions.cs" />
<Compile Include="Src\Services\Tasks\ErrorPainter.cs" /> <Compile Include="Src\Services\Tasks\ErrorPainter.cs" />
<Compile Include="Src\Services\Tasks\Task.cs" /> <Compile Include="Src\Services\Tasks\Task.cs" />
<Compile Include="Src\Services\Tasks\TaskService.cs" /> <Compile Include="Src\Services\Tasks\TaskService.cs" />
<Compile Include="Src\Services\DisplayBinding\IDisplayBinding.cs" /> <Compile Include="Src\Services\DisplayBinding\IDisplayBinding.cs" />
<Compile Include="Src\Internal\ExternalTool\ToolLoader.cs" /> <Compile Include="Src\Internal\ExternalTool\ToolLoader.cs" />
<Compile Include="Src\Internal\Templates\CodeTemplateLoader.cs" />
<Compile Include="Src\Services\ProjectBinding\IProjectBinding.cs" /> <Compile Include="Src\Services\ProjectBinding\IProjectBinding.cs" />
<Compile Include="Src\Internal\Templates\Project\ProjectCreateInformation.cs" /> <Compile Include="Src\Internal\Templates\Project\ProjectCreateInformation.cs" />
<Compile Include="Src\Services\ProjectBinding\ProjectBindingService.cs" /> <Compile Include="Src\Services\ProjectBinding\ProjectBindingService.cs" />
@ -417,7 +415,6 @@
</Compile> </Compile>
<Compile Include="Src\Gui\ContentInterfaces\IParseInformationListener.cs" /> <Compile Include="Src\Gui\ContentInterfaces\IParseInformationListener.cs" />
<Compile Include="Src\Commands\CustomStringTagProvider.cs" /> <Compile Include="Src\Commands\CustomStringTagProvider.cs" />
<Compile Include="Src\Internal\Templates\CodeTemplateGroup.cs" />
<Compile Include="Src\Commands\VBConverter\CSharpConvertBuffer.cs" /> <Compile Include="Src\Commands\VBConverter\CSharpConvertBuffer.cs" />
<Compile Include="Src\Internal\ConditionEvaluators\ActiveViewContentUntitledEvaluator.cs" /> <Compile Include="Src\Internal\ConditionEvaluators\ActiveViewContentUntitledEvaluator.cs" />
<Compile Include="Src\Services\Debugger\DebuggerService.cs" /> <Compile Include="Src\Services\Debugger\DebuggerService.cs" />
@ -465,7 +462,6 @@
<Compile Include="Src\Services\ProjectService\ProjectEventHandler.cs" /> <Compile Include="Src\Services\ProjectService\ProjectEventHandler.cs" />
<Compile Include="Src\Commands\FileMenuCommands.cs" /> <Compile Include="Src\Commands\FileMenuCommands.cs" />
<Compile Include="Src\Services\ParserService\ParseInformationEventArgs.cs" /> <Compile Include="Src\Services\ParserService\ParseInformationEventArgs.cs" />
<Compile Include="Src\Services\ProjectService\SolutionConfigurationEventHandler.cs" />
<Compile Include="Src\Services\ProjectService\ProjectConfigurationEventHandler.cs" /> <Compile Include="Src\Services\ProjectService\ProjectConfigurationEventHandler.cs" />
<Compile Include="Src\Commands\DebugCommands.cs" /> <Compile Include="Src\Commands\DebugCommands.cs" />
<Compile Include="Src\Gui\Pads\ProjectBrowser\TreeNodes\AbstractProjectBrowserTreeNode.cs" /> <Compile Include="Src\Gui\Pads\ProjectBrowser\TreeNodes\AbstractProjectBrowserTreeNode.cs" />
@ -566,7 +562,6 @@
<EmbeddedResource Include="Resources\WordCountDialog.xfrm" /> <EmbeddedResource Include="Resources\WordCountDialog.xfrm" />
<EmbeddedResource Include="Resources\BehaviorTextEditorPanel.xfrm" /> <EmbeddedResource Include="Resources\BehaviorTextEditorPanel.xfrm" />
<EmbeddedResource Include="Resources\GeneralTextEditorPanel.xfrm" /> <EmbeddedResource Include="Resources\GeneralTextEditorPanel.xfrm" />
<EmbeddedResource Include="Resources\CodeTemplatePanel.xfrm" />
<EmbeddedResource Include="Resources\MarkersTextEditorPanel.xfrm" /> <EmbeddedResource Include="Resources\MarkersTextEditorPanel.xfrm" />
<Compile Include="Src\TextEditor\Bookmarks\BookmarkBase.cs" /> <Compile Include="Src\TextEditor\Bookmarks\BookmarkBase.cs" />
<Compile Include="Src\TextEditor\Bookmarks\Commands\MenuCommands.cs" /> <Compile Include="Src\TextEditor\Bookmarks\Commands\MenuCommands.cs" />
@ -623,9 +618,6 @@
<Compile Include="Src\TextEditor\Gui\OptionPanels\BehaviorTextEditorPanel.cs"> <Compile Include="Src\TextEditor\Gui\OptionPanels\BehaviorTextEditorPanel.cs">
<SubType>UserControl</SubType> <SubType>UserControl</SubType>
</Compile> </Compile>
<Compile Include="Src\TextEditor\Gui\OptionPanels\CodeTemplatePanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Src\TextEditor\Gui\OptionPanels\GeneralTextEditorPanel.cs"> <Compile Include="Src\TextEditor\Gui\OptionPanels\GeneralTextEditorPanel.cs">
<SubType>UserControl</SubType> <SubType>UserControl</SubType>
</Compile> </Compile>

108
src/Main/Base/Project/Resources/CodeTemplatePanel.xfrm

@ -1,108 +0,0 @@
<Components version="1.0">
<System.Windows.Forms.UserControl>
<Name value="MyUserControl" />
<DockPadding value="" />
<ClientSize value="{Width=320, Height=320}" />
<Controls>
<System.Windows.Forms.Panel>
<Name value="editorPanel" />
<Location value="{X=8,Y=192}" />
<Size value="{Width=304, Height=120}" />
<DockPadding value="" />
<Anchor value="Top, Bottom, Left, Right" />
<TabIndex value="8" />
<Controls>
<System.Windows.Forms.TextBox>
<Name value="templateTextBox" />
<TabIndex value="0" />
<Dock value="Fill" />
<Location value="{X=0,Y=0}" />
<AcceptsReturn value="True" />
<Size value="{Width=304, Height=120}" />
<Multiline value="True" />
<AcceptsTab value="True" />
<AutoSize value="False" />
<Text value="" />
<RightToLeft value="No" />
</System.Windows.Forms.TextBox>
</Controls>
</System.Windows.Forms.Panel>
<System.Windows.Forms.Button>
<Name value="removeButton" />
<Location value="{X=232,Y=160}" />
<Text value="${res:Global.RemoveButtonText}" />
<Anchor value="Top, Right" />
<TabIndex value="7" />
</System.Windows.Forms.Button>
<System.Windows.Forms.Button>
<Name value="editButton" />
<Location value="{X=232,Y=128}" />
<Text value="${res:Global.EditButtonText}" />
<Anchor value="Top, Right" />
<TabIndex value="6" />
</System.Windows.Forms.Button>
<System.Windows.Forms.Button>
<Name value="addButton" />
<Location value="{X=232,Y=96}" />
<Text value="${res:Global.AddButtonText}" />
<Anchor value="Top, Right" />
<TabIndex value="5" />
</System.Windows.Forms.Button>
<System.Windows.Forms.ListView>
<Name value="templateListView" />
<GridLines value="True" />
<Anchor value="Top, Left, Right" />
<TabIndex value="4" />
<View value="Details" />
<Sorting value="Ascending" />
<FullRowSelect value="True" />
<Location value="{X=8,Y=72}" />
<Size value="{Width=216, Height=112}" />
<HideSelection value="False" />
<RightToLeft value="No" />
<Columns>
<System.Windows.Forms.ColumnHeader>
<Width value="70" />
<Name value="columnHeader" />
<Text value="${res:Dialog.Options.CodeTemplate.Template}" />
</System.Windows.Forms.ColumnHeader>
<System.Windows.Forms.ColumnHeader>
<Width value="140" />
<Name value="columnHeader2" />
<Text value="${res:Dialog.Options.CodeTemplate.Description}" />
</System.Windows.Forms.ColumnHeader>
</Columns>
</System.Windows.Forms.ListView>
<System.Windows.Forms.Button>
<Name value="removeGroupButton" />
<Location value="{X=200,Y=40}" />
<Size value="{Width=96, Height=23}" />
<Text value="${res:Dialog.Options.CodeTemplate.RemoveGroupLabel}" />
<TabIndex value="3" />
</System.Windows.Forms.Button>
<System.Windows.Forms.Button>
<Name value="addGroupButton" />
<Location value="{X=88,Y=40}" />
<Size value="{Width=104, Height=23}" />
<Text value="${res:Dialog.Options.CodeTemplate.AddGroupLabel}" />
<TabIndex value="2" />
</System.Windows.Forms.Button>
<System.Windows.Forms.ComboBox>
<Name value="groupComboBox" />
<Anchor value="Top, Left, Right" />
<TabIndex value="1" />
<Location value="{X=88,Y=8}" />
<Size value="{Width=228, Height=21}" />
<RightToLeft value="No" />
</System.Windows.Forms.ComboBox>
<System.Windows.Forms.Label>
<Name value="extensionLabel" />
<Text value="${res:Dialog.Options.CodeTemplate.ExtensionsLabel}" />
<TextAlign value="MiddleRight" />
<TabIndex value="0" />
<Size value="{Width=80, Height=23}" />
<Location value="{X=8,Y=8}" />
</System.Windows.Forms.Label>
</Controls>
</System.Windows.Forms.UserControl>
</Components>

2
src/Main/Base/Project/Src/Commands/CustomStringTagProvider.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Commands
case "STARTUPPATH": case "STARTUPPATH":
return Application.StartupPath; return Application.StartupPath;
} }
return String.Empty; return null;
} }
} }

9
src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs

@ -5,13 +5,15 @@
// <version>$Revision$</version> // <version>$Revision$</version>
// </file> // </file>
using ICSharpCode.AvalonEdit.Document;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion; using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
@ -241,6 +243,11 @@ namespace ICSharpCode.SharpDevelop.Editor.AvalonEdit
return null; return null;
} }
public virtual IEnumerable<ICompletionItem> GetSnippets()
{
return Enumerable.Empty<ICompletionItem>();
}
public virtual ITextEditor PrimaryView { public virtual ITextEditor PrimaryView {
get { get {
return this; return this;

45
src/Main/Base/Project/Src/Editor/CodeCompletion/CtrlSpaceCompletionItemProvider.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Linq;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Dom;
using System.Collections.Generic; using System.Collections.Generic;
@ -43,43 +44,27 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
/// </summary> /// </summary>
public bool ShowTemplates { get; set; } public bool ShowTemplates { get; set; }
// TODO: AVALONEDIT implement templates void AddTemplates(ITextEditor editor, DefaultCompletionItemList list)
/*
void AddTemplates(ITextEditor editor, char charTyped)
{ {
if (!ShowTemplates) if (list == null)
return; return;
ICompletionData suggestedData = DefaultIndex >= 0 ? completionData[DefaultIndex] : null; List<ICompletionItem> snippets = editor.GetSnippets().ToList();
var templateCompletion = new TemplateCompletionItemProvider().GenerateCompletionList(editor); list.Items.RemoveAll(item => item.Image == ClassBrowserIconService.Keyword && snippets.Exists(i => i.Text == item.Text));
if (templateCompletion == null || templateCompletionData.Length == 0) list.Items.AddRange(snippets);
return; list.SortItems();
for (int i = 0; i < completionData.Count; i++) {
if (completionData[i].ImageIndex == ClassBrowserIconService.KeywordIndex) {
string text = completionData[i].Text;
for (int j = 0; j < templateCompletionData.Length; j++) {
if (templateCompletionData[j] != null && templateCompletionData[j].Text == text) {
// replace keyword with template
completionData[i] = templateCompletionData[j];
templateCompletionData[j] = null;
}
}
}
}
// add non-keyword code templates
for (int j = 0; j < templateCompletionData.Length; j++) {
if (templateCompletionData[j] != null)
completionData.Add(templateCompletionData[j]);
}
if (suggestedData != null) {
completionData.Sort(DefaultCompletionData.Compare);
DefaultIndex = completionData.IndexOf(suggestedData);
}
} }
*/
int preselectionLength; int preselectionLength;
public override ICompletionItemList GenerateCompletionList(ITextEditor editor) public override ICompletionItemList GenerateCompletionList(ITextEditor editor)
{
ICompletionItemList list = GenerateCompletionListCore(editor);
if (ShowTemplates)
AddTemplates(editor, list as DefaultCompletionItemList);
return list;
}
ICompletionItemList GenerateCompletionListCore(ITextEditor editor)
{ {
preselectionLength = 0; preselectionLength = 0;
if (!allowCompleteExistingExpression) { if (!allowCompleteExistingExpression) {

8
src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionItemList.cs

@ -74,7 +74,13 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
public void SortItems() public void SortItems()
{ {
// the user might use method names is his language, so sort using CurrentCulture // the user might use method names is his language, so sort using CurrentCulture
items.Sort((a,b) => string.Compare(a.Text, b.Text, StringComparison.CurrentCultureIgnoreCase)); items.Sort((a,b) => {
int r = string.Compare(a.Text, b.Text, StringComparison.CurrentCultureIgnoreCase);
if (r != 0)
return r;
else
return string.Compare(a.Text, b.Text, StringComparison.CurrentCulture);
});
} }
/// <inheritdoc/> /// <inheritdoc/>

69
src/Main/Base/Project/Src/Editor/CodeCompletion/TemplateCompletionItemProvider.cs

@ -1,69 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Internal.Templates;
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
{
public class TemplateCompletionItemProvider : AbstractCompletionItemProvider
{
public bool AutomaticInsert;
/// <inheritdoc/>
public override ICompletionItemList GenerateCompletionList(ITextEditor editor)
{
CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(editor.FileName);
if (templateGroup == null) {
return null;
}
DefaultCompletionItemList result = new DefaultCompletionItemList();
bool automaticInsert = this.AutomaticInsert || DefaultEditor.Gui.Editor.SharpDevelopTextEditorProperties.Instance.AutoInsertTemplates;
foreach (CodeTemplate template in templateGroup.Templates) {
result.Items.Add(new TemplateCompletionItem(template));
}
result.SortItems();
return result;
}
sealed class TemplateCompletionItem : ICompletionItem
{
public readonly CodeTemplate template;
public TemplateCompletionItem(CodeTemplate template)
{
this.template = template;
}
public string Text {
get {
return template.Shortcut;
}
}
public string Description {
get {
return template.Description + StringParser.Parse("\n${res:Dialog.Options.CodeTemplate.PressTabToInsertTemplate}\n\n")
+ template.Text;
}
}
public IImage Image {
get {
return ClassBrowserIconService.CodeTemplate;
}
}
public void Complete(CompletionContext context)
{
context.Editor.Document.Replace(context.StartOffset, context.Length, template.Text);
}
}
}
}

5
src/Main/Base/Project/Src/Editor/ITextEditor.cs

@ -117,6 +117,11 @@ namespace ICSharpCode.SharpDevelop.Editor
/// </summary> /// </summary>
IInsightWindow ActiveInsightWindow { get; } IInsightWindow ActiveInsightWindow { get; }
/// <summary>
/// Gets the list of available code snippets.
/// </summary>
IEnumerable<ICompletionItem> GetSnippets();
[Obsolete("Use the overload taking ICompletionItemList")] [Obsolete("Use the overload taking ICompletionItemList")]
void ShowCompletionWindow(ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider provider, char ch); void ShowCompletionWindow(ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider provider, char ch);
} }

22
src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/EditTemplateDialog.cs

@ -16,32 +16,18 @@ namespace ICSharpCode.SharpDevelop.Gui
{ {
public class EditTemplateDialog : BaseSharpDevelopForm public class EditTemplateDialog : BaseSharpDevelopForm
{ {
CodeTemplate codeTemplate;
public CodeTemplate CodeTemplate {
get {
return codeTemplate;
}
}
public EditTemplateDialog(CodeTemplate codeTemplate)
{
this.codeTemplate = codeTemplate;
InitializeComponents();
}
void AcceptEvent(object sender, EventArgs e) void AcceptEvent(object sender, EventArgs e)
{ {
codeTemplate.Shortcut = ControlDictionary["templateTextBox"].Text; // codeTemplate.Shortcut = ControlDictionary["templateTextBox"].Text;
codeTemplate.Description = ControlDictionary["descriptionTextBox"].Text; // codeTemplate.Description = ControlDictionary["descriptionTextBox"].Text;
} }
void InitializeComponents() void InitializeComponents()
{ {
SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Resources.EditTemplateDialog.xfrm")); SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Resources.EditTemplateDialog.xfrm"));
ControlDictionary["templateTextBox"].Text = codeTemplate.Shortcut; // ControlDictionary["templateTextBox"].Text = codeTemplate.Shortcut;
ControlDictionary["descriptionTextBox"].Text = codeTemplate.Description; // ControlDictionary["descriptionTextBox"].Text = codeTemplate.Description;
ControlDictionary["okButton"].Click += new EventHandler(AcceptEvent); ControlDictionary["okButton"].Click += new EventHandler(AcceptEvent);

91
src/Main/Base/Project/Src/Internal/Templates/CodeTemplate.cs

@ -1,91 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Xml;
namespace ICSharpCode.SharpDevelop.Internal.Templates
{
/// <summary>
/// This class reperesents a single Code Template
/// </summary>
public class CodeTemplate
{
string shortcut = String.Empty;
string description = String.Empty;
string text = String.Empty;
public string Shortcut {
get {
return shortcut;
}
set {
shortcut = value;
System.Diagnostics.Debug.Assert(shortcut != null, "ICSharpCode.SharpDevelop.Internal.Template : string Shortcut == null");
}
}
public string Description {
get {
return description;
}
set {
description = value;
System.Diagnostics.Debug.Assert(description != null, "ICSharpCode.SharpDevelop.Internal.Template : string Description == null");
}
}
public string Text {
get {
return text;
}
set {
text = value;
System.Diagnostics.Debug.Assert(text != null, "ICSharpCode.SharpDevelop.Internal.Template : string Text == null");
}
}
public CodeTemplate()
{
}
public CodeTemplate(string shortcut, string description, string text)
{
this.shortcut = shortcut;
this.description = description;
this.text = text;
}
public CodeTemplate(XmlElement el)
{
if (el == null) {
throw new ArgumentNullException("el");
}
if (el.Attributes["template"] == null || el.Attributes["description"] == null) {
throw new Exception("CodeTemplate(XmlElement el) : template and description attributes must exist (check the CodeTemplate XML)");
}
Shortcut = el.GetAttribute("template");
Description = el.GetAttribute("description");
Text = el.InnerText;
}
public XmlElement ToXmlElement(XmlDocument doc)
{
if (doc == null) {
throw new ArgumentNullException("doc");
}
XmlElement newElement = doc.CreateElement("CodeTemplate");
newElement.SetAttribute("template", Shortcut);
newElement.SetAttribute("description", Description);
newElement.InnerText = Text;
return newElement;
}
}
}

87
src/Main/Base/Project/Src/Internal/Templates/CodeTemplateGroup.cs

@ -1,87 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Xml;
namespace ICSharpCode.SharpDevelop.Internal.Templates
{
/// <summary>
/// This class reperesents a single Code Template
/// </summary>
public class CodeTemplateGroup
{
List<string> extensions = new List<string>();
List<CodeTemplate> templates = new List<CodeTemplate>();
public List<string> Extensions {
get {
return extensions;
}
}
public List<CodeTemplate> Templates {
get {
return templates;
}
}
public string[] ExtensionStrings {
get {
string[] extensionStrings = new string[extensions.Count];
extensions.CopyTo(extensionStrings, 0);
return extensionStrings;
}
set {
extensions.Clear();
foreach (string str in value) {
extensions.Add(str);
}
}
}
public CodeTemplateGroup(string extensions)
{
ExtensionStrings = extensions.Split(';');
}
public CodeTemplateGroup(XmlElement el)
{
if (el == null) {
throw new ArgumentNullException("el");
}
string[] exts = el.GetAttribute("extensions").Split(';');
foreach (string ext in exts) {
extensions.Add(ext);
}
foreach (XmlNode childNode in el.ChildNodes) {
XmlElement childElement = childNode as XmlElement;
if (childElement != null) {
templates.Add(new CodeTemplate(childElement));
}
}
}
public XmlElement ToXmlElement(XmlDocument doc)
{
if (doc == null) {
throw new ArgumentNullException("doc");
}
XmlElement newElement = doc.CreateElement("CodeTemplateGroup");
newElement.SetAttribute("extensions", String.Join(";", ExtensionStrings));
foreach (CodeTemplate codeTemplate in templates) {
newElement.AppendChild(codeTemplate.ToXmlElement(doc));
}
return newElement;
}
}
}

119
src/Main/Base/Project/Src/Internal/Templates/CodeTemplateLoader.cs

@ -1,119 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.IO;
using System.Xml;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Internal.Templates
{
/// <summary>
/// This class handles the code templates
/// </summary>
public class CodeTemplateLoader
{
static string TemplateFileName = "SharpDevelop-templates.xml";
static string TemplateVersion = "2.0";
static ArrayList templateGroups = new ArrayList();
public static ArrayList TemplateGroups {
get {
return templateGroups;
}
set {
templateGroups = value;
System.Diagnostics.Debug.Assert(templateGroups != null);
}
}
public static CodeTemplateGroup GetTemplateGroupPerFilename(string fileName)
{
return GetTemplateGroupPerExtension(Path.GetExtension(fileName));
}
public static CodeTemplateGroup GetTemplateGroupPerExtension(string extension)
{
foreach (CodeTemplateGroup group in templateGroups) {
foreach (string groupExtension in group.Extensions) {
if (groupExtension == extension) {
return group;
}
}
}
return null;
}
static bool LoadTemplatesFromStream(string filename)
{
if (!File.Exists(filename)) {
return false;
}
XmlDocument doc = new XmlDocument();
try {
doc.PreserveWhitespace = true;
doc.Load(filename);
templateGroups = new ArrayList();
if (doc.DocumentElement.GetAttribute("version") != TemplateVersion) {
return false;
}
foreach (XmlNode n in doc.DocumentElement.ChildNodes) {
XmlElement el = n as XmlElement;
if (el != null) {
templateGroups.Add(new CodeTemplateGroup(el));
}
}
} catch (FileNotFoundException) {
return false;
}
return true;
}
static void WriteTemplatesToFile(string fileName)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<CodeTemplates version = \"" + TemplateVersion + "\" />");
foreach (CodeTemplateGroup codeTemplateGroup in templateGroups) {
doc.DocumentElement.AppendChild(codeTemplateGroup.ToXmlElement(doc));
}
FileUtility.ObservedSave(new NamedFileOperationDelegate(doc.Save), fileName, FileErrorPolicy.ProvideAlternative);
}
/// <summary>
/// This method loads the code templates from a XML based
/// configuration file.
/// </summary>
static CodeTemplateLoader()
{
if (!LoadTemplatesFromStream(Path.Combine(PropertyService.ConfigDirectory, TemplateFileName))) {
LoggingService.Info("Templates: can't load user defaults, reading system defaults");
if (!LoadTemplatesFromStream(FileUtility.Combine(PropertyService.DataDirectory, "options", TemplateFileName))) {
MessageService.ShowWarning("${res:Internal.Templates.CodeTemplateLoader.CantLoadTemplatesWarning}");
}
}
}
/// <summary>
/// This method saves the code templates to a XML based
/// configuration file in the current user's own files directory
/// </summary>
public static void SaveTemplates()
{
WriteTemplatesToFile(Path.Combine(PropertyService.ConfigDirectory, TemplateFileName));
}
}
}

11
src/Main/Base/Project/Src/TextEditor/Actions.cs

@ -15,17 +15,6 @@ using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Actions namespace ICSharpCode.SharpDevelop.DefaultEditor.Actions
{ {
public class TemplateCompletion : AbstractEditAction
{
public override void Execute(TextArea services)
{
SharpDevelopTextAreaControl sdtac = (SharpDevelopTextAreaControl)services.MotherTextEditorControl;
services.AutoClearSelection = false;
new ICSharpCode.SharpDevelop.Editor.CodeCompletion.TemplateCompletionItemProvider().ShowCompletion(sdtac.Adapter);
}
}
public class CodeCompletionPopup : AbstractEditAction public class CodeCompletionPopup : AbstractEditAction
{ {
public override void Execute(TextArea textArea) public override void Execute(TextArea textArea)

51
src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

@ -299,7 +299,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{ {
string word = GetWordBeforeCaret(); string word = GetWordBeforeCaret();
if (word != null) { if (word != null) {
CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(FileName); /*CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(FileName);
if (templateGroup != null) { if (templateGroup != null) {
foreach (CodeTemplate template in templateGroup.Templates) { foreach (CodeTemplate template in templateGroup.Templates) {
if (template.Shortcut == word) { if (template.Shortcut == word) {
@ -313,7 +313,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
return true; return true;
} }
} }
} }*/
} }
return false; return false;
} }
@ -360,53 +360,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
return start; return start;
} }
/// <remarks>
/// This method inserts a code template at the current caret position
/// </remarks>
public void InsertTemplate(CodeTemplate template)
{
string selectedText = String.Empty;
Document.UndoStack.StartUndoGroup();
if (base.ActiveTextAreaControl.TextArea.SelectionManager.HasSomethingSelected) {
selectedText = base.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText;
ActiveTextAreaControl.TextArea.Caret.Position = ActiveTextAreaControl.TextArea.SelectionManager.SelectionCollection[0].StartPosition;
base.ActiveTextAreaControl.TextArea.SelectionManager.RemoveSelectedText();
}
// save old properties, these properties cause strange effects, when not
// be turned off (like insert curly braces or other formatting stuff)
string templateText = StringParser.Parse(template.Text, new string[,] { { "Selection", selectedText } });
int finalCaretOffset = templateText.IndexOf('|');
if (finalCaretOffset >= 0) {
templateText = templateText.Remove(finalCaretOffset, 1);
} else {
finalCaretOffset = templateText.Length;
}
int caretOffset = ActiveTextAreaControl.TextArea.Caret.Offset;
BeginUpdate();
int beginLine = ActiveTextAreaControl.TextArea.Caret.Line;
Document.Insert(caretOffset, templateText);
ActiveTextAreaControl.TextArea.Caret.Position = Document.OffsetToPosition(caretOffset + finalCaretOffset);
int endLine = Document.OffsetToPosition(caretOffset + templateText.Length).Y;
IndentStyle save1 = TextEditorProperties.IndentStyle;
TextEditorProperties.IndentStyle = IndentStyle.Smart;
Console.WriteLine("Indent between {0} and {1}", beginLine, endLine);
Document.FormattingStrategy.IndentLines(ActiveTextAreaControl.TextArea, beginLine, endLine);
Document.UndoStack.EndUndoGroup();
EndUpdate();
Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
Document.CommitUpdate();
// restore old property settings
TextEditorProperties.IndentStyle = save1;
}
protected override void OnReloadHighlighting(object sender, EventArgs e) protected override void OnReloadHighlighting(object sender, EventArgs e)
{ {
base.OnReloadHighlighting(sender, e); base.OnReloadHighlighting(sender, e);

262
src/Main/Base/Project/Src/TextEditor/Gui/OptionPanels/CodeTemplatePanel.cs

@ -1,262 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Windows.Forms;
using ICSharpCode.Core.WinForms;
using ICSharpCode.SharpDevelop.Internal.Templates;
namespace ICSharpCode.SharpDevelop.Gui.OptionPanels
{
public class CodeTemplatePanel : XmlFormsOptionPanel
{
ArrayList templateGroups;
int currentSelectedGroup = -1;
public CodeTemplateGroup CurrentTemplateGroup {
get {
if (currentSelectedGroup < 0 || currentSelectedGroup >= templateGroups.Count) {
return null;
}
return (CodeTemplateGroup)templateGroups[currentSelectedGroup];
}
}
public override void LoadPanelContents()
{
templateGroups = CopyCodeTemplateGroups(CodeTemplateLoader.TemplateGroups);
SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Resources.CodeTemplatePanel.xfrm"));
ControlDictionary["removeButton"].Click += new System.EventHandler(RemoveEvent);
ControlDictionary["addButton"].Click += new System.EventHandler(AddEvent);
ControlDictionary["editButton"].Click += new System.EventHandler(EditEvent);
ControlDictionary["addGroupButton"].Click += new System.EventHandler(AddGroupEvent);
ControlDictionary["removeGroupButton"].Click += new System.EventHandler(RemoveGroupEvent);
((TextBox)ControlDictionary["templateTextBox"]).Font = WinFormsResourceService.DefaultMonospacedFont;
((TextBox)ControlDictionary["templateTextBox"]).TextChanged += new EventHandler(TextChange);
((ListView)ControlDictionary["templateListView"]).Activation = ItemActivation.Standard;
((ListView)ControlDictionary["templateListView"]).ItemActivate += new System.EventHandler(EditEvent);
((ListView)ControlDictionary["templateListView"]).SelectedIndexChanged += new System.EventHandler(IndexChange);
((ComboBox)ControlDictionary["groupComboBox"]).DropDown += new EventHandler(FillGroupBoxEvent);
if (templateGroups.Count > 0) {
currentSelectedGroup = 0;
}
FillGroupComboBox();
BuildListView();
IndexChange(null, null);
SetEnabledStatus();
}
public override bool StorePanelContents()
{
CodeTemplateLoader.TemplateGroups = templateGroups;
CodeTemplateLoader.SaveTemplates();
return true;
}
void FillGroupBoxEvent(object sender, EventArgs e)
{
FillGroupComboBox();
}
void SetEnabledStatus()
{
bool groupSelected = CurrentTemplateGroup != null;
bool groupsEmpty = templateGroups.Count != 0;
SetEnabledStatus(groupSelected, "addButton", "editButton", "removeButton", "templateListView", "templateTextBox");
SetEnabledStatus(groupsEmpty, "groupComboBox", "extensionLabel");
if (groupSelected) {
bool oneItemSelected = ((ListView)ControlDictionary["templateListView"]).SelectedItems.Count == 1;
bool isItemSelected = ((ListView)ControlDictionary["templateListView"]).SelectedItems.Count > 0;
SetEnabledStatus(oneItemSelected, "editButton", "templateTextBox");
SetEnabledStatus(isItemSelected, "removeButton");
}
}
#region GroupComboBox event handler
void SetGroupSelection(object sender, EventArgs e)
{
currentSelectedGroup = ((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex;
BuildListView();
}
void GroupComboBoxTextChanged(object sender, EventArgs e)
{
if (((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex >= 0) {
currentSelectedGroup = ((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex;
}
if (CurrentTemplateGroup != null) {
CurrentTemplateGroup.ExtensionStrings = ((ComboBox)ControlDictionary["groupComboBox"]).Text.Split(';');
}
}
#endregion
#region Group Button events
void AddGroupEvent(object sender, EventArgs e)
{
templateGroups.Add(new CodeTemplateGroup(".???"));
FillGroupComboBox();
((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex = templateGroups.Count - 1;
SetEnabledStatus();
}
void RemoveGroupEvent(object sender, EventArgs e)
{
if (CurrentTemplateGroup != null) {
templateGroups.RemoveAt(currentSelectedGroup);
if (templateGroups.Count == 0) {
currentSelectedGroup = -1;
} else {
((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex = Math.Min(currentSelectedGroup, templateGroups.Count - 1);
}
FillGroupComboBox();
BuildListView();
SetEnabledStatus();
}
}
#endregion
#region Template Button events
void RemoveEvent(object sender, System.EventArgs e)
{
object[] selectedItems = new object[((ListView)ControlDictionary["templateListView"]).SelectedItems.Count];
((ListView)ControlDictionary["templateListView"]).SelectedItems.CopyTo(selectedItems, 0);
foreach (ListViewItem item in selectedItems) {
((ListView)ControlDictionary["templateListView"]).Items.Remove(item);
}
StoreTemplateGroup();
}
void AddEvent(object sender, System.EventArgs e)
{
CodeTemplate newTemplate = new CodeTemplate();
using (EditTemplateDialog etd = new EditTemplateDialog(newTemplate)) {
if (etd.ShowDialog(WorkbenchSingleton.MainWin32Window) == DialogResult.OK) {
CurrentTemplateGroup.Templates.Add(newTemplate);
((ListView)ControlDictionary["templateListView"]).SelectedItems.Clear();
BuildListView();
((ListView)ControlDictionary["templateListView"]).Select();
}
}
}
void EditEvent(object sender, System.EventArgs e)
{
int i = GetCurrentIndex();
if (i != -1) {
ListViewItem item = ((ListView)ControlDictionary["templateListView"]).SelectedItems[0];
CodeTemplate template = (CodeTemplate)item.Tag;
template = new CodeTemplate(template.Shortcut, template.Description, template.Text);
using (EditTemplateDialog etd = new EditTemplateDialog(template)) {
if (etd.ShowDialog(WorkbenchSingleton.MainWin32Window) == DialogResult.OK) {
item.Tag = template;
StoreTemplateGroup();
}
}
BuildListView();
}
}
#endregion
void FillGroupComboBox()
{
((ComboBox)ControlDictionary["groupComboBox"]).TextChanged -= new EventHandler(GroupComboBoxTextChanged);
((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndexChanged -= new EventHandler(SetGroupSelection);
((ComboBox)ControlDictionary["groupComboBox"]).Items.Clear();
foreach (CodeTemplateGroup templateGroup in templateGroups) {
((ComboBox)ControlDictionary["groupComboBox"]).Items.Add(String.Join(";", templateGroup.ExtensionStrings));
}
((ComboBox)ControlDictionary["groupComboBox"]).Text = CurrentTemplateGroup != null ? ((ComboBox)ControlDictionary["groupComboBox"]).Items[currentSelectedGroup].ToString() : String.Empty;
if (currentSelectedGroup >= 0) {
((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndex = currentSelectedGroup;
}
((ComboBox)ControlDictionary["groupComboBox"]).SelectedIndexChanged += new EventHandler(SetGroupSelection);
((ComboBox)ControlDictionary["groupComboBox"]).TextChanged += new EventHandler(GroupComboBoxTextChanged);
}
int GetCurrentIndex()
{
if (((ListView)ControlDictionary["templateListView"]).SelectedItems.Count == 1) {
return ((ListView)ControlDictionary["templateListView"]).SelectedItems[0].Index;
}
return -1;
}
void IndexChange(object sender, System.EventArgs e)
{
int i = GetCurrentIndex();
if (i != -1) {
ControlDictionary["templateTextBox"].Text = ((CodeTemplate)((ListView)ControlDictionary["templateListView"]).SelectedItems[0].Tag).Text;
} else {
ControlDictionary["templateTextBox"].Text = String.Empty;
}
SetEnabledStatus();
}
void TextChange(object sender, EventArgs e)
{
int i = GetCurrentIndex();
if (i != -1) {
((CodeTemplate)((ListView)ControlDictionary["templateListView"]).SelectedItems[0].Tag).Text = ControlDictionary["templateTextBox"].Text;
}
}
void StoreTemplateGroup()
{
if (CurrentTemplateGroup != null) {
CurrentTemplateGroup.Templates.Clear();
foreach (ListViewItem item in ((ListView)ControlDictionary["templateListView"]).Items) {
CurrentTemplateGroup.Templates.Add((CodeTemplate)item.Tag);
}
}
}
void BuildListView()
{
((ListView)ControlDictionary["templateListView"]).Items.Clear();
if (CurrentTemplateGroup != null) {
foreach (CodeTemplate template in CurrentTemplateGroup.Templates) {
ListViewItem newItem = new ListViewItem(new string[] { template.Shortcut, template.Description });
newItem.Tag = template;
((ListView)ControlDictionary["templateListView"]).Items.Add(newItem);
}
}
IndexChange(this, EventArgs.Empty);
}
ArrayList CopyCodeTemplateGroups(ArrayList groups)
{
ArrayList copiedGroups = new ArrayList();
foreach (CodeTemplateGroup group in groups) {
CodeTemplateGroup newGroup = new CodeTemplateGroup(String.Join(";", group.ExtensionStrings));
foreach (CodeTemplate template in group.Templates) {
CodeTemplate newTemplate = new CodeTemplate(template.Shortcut, template.Description, template.Text);
newGroup.Templates.Add(newTemplate);
}
copiedGroups.Add(newGroup);
}
return copiedGroups;
}
}
}

5
src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs

@ -264,6 +264,11 @@ namespace ICSharpCode.SharpDevelop
return this; return this;
} }
} }
public IEnumerable<ICompletionItem> GetSnippets()
{
return Enumerable.Empty<ICompletionItem>();
}
} }
sealed class CompletionItemListAdapter : ICompletionDataProvider sealed class CompletionItemListAdapter : ICompletionDataProvider

8
src/Main/Core/Project/Src/Services/StringParser/StringParser.cs

@ -149,8 +149,14 @@ namespace ICSharpCode.Core
return Parse(input, pairs); return Parse(input, pairs);
} }
static string GetValue(string propertyName, StringTagPair[] customTags) /// <summary>
/// Evaluates a property using the StringParser. Equivalent to StringParser.Parse("${" + propertyName + "}");
/// </summary>
public static string GetValue(string propertyName, params StringTagPair[] customTags)
{ {
if (propertyName == null)
throw new ArgumentNullException("propertyName");
if (customTags != null) { if (customTags != null) {
foreach (StringTagPair pair in customTags) { foreach (StringTagPair pair in customTags) {
if (propertyName.Equals(pair.Tag, StringComparison.OrdinalIgnoreCase)) { if (propertyName.Equals(pair.Tag, StringComparison.OrdinalIgnoreCase)) {

15
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs

@ -317,6 +317,8 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
#region Generate property #region Generate property
public virtual string GetPropertyName(string fieldName) public virtual string GetPropertyName(string fieldName)
{ {
if (string.IsNullOrEmpty(fieldName))
return fieldName;
if (fieldName.StartsWith("_") && fieldName.Length > 1) if (fieldName.StartsWith("_") && fieldName.Length > 1)
return Char.ToUpper(fieldName[1]) + fieldName.Substring(2); return Char.ToUpper(fieldName[1]) + fieldName.Substring(2);
else if (fieldName.StartsWith("m_") && fieldName.Length > 2) else if (fieldName.StartsWith("m_") && fieldName.Length > 2)
@ -327,6 +329,8 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
public virtual string GetParameterName(string fieldName) public virtual string GetParameterName(string fieldName)
{ {
if (string.IsNullOrEmpty(fieldName))
return fieldName;
if (fieldName.StartsWith("_") && fieldName.Length > 1) if (fieldName.StartsWith("_") && fieldName.Length > 1)
return Char.ToLower(fieldName[1]) + fieldName.Substring(2); return Char.ToLower(fieldName[1]) + fieldName.Substring(2);
else if (fieldName.StartsWith("m_") && fieldName.Length > 2) else if (fieldName.StartsWith("m_") && fieldName.Length > 2)
@ -335,6 +339,17 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
return Char.ToLower(fieldName[0]) + fieldName.Substring(1); return Char.ToLower(fieldName[0]) + fieldName.Substring(1);
} }
public virtual string GetFieldName(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
return propertyName;
string newName = Char.ToLower(propertyName[0]) + propertyName.Substring(1);
if (newName == propertyName)
return "_" + newName;
else
return newName;
}
public virtual PropertyDeclaration CreateProperty(IField field, bool createGetter, bool createSetter) public virtual PropertyDeclaration CreateProperty(IField field, bool createGetter, bool createSetter)
{ {
ClassFinder targetContext = new ClassFinder(field); ClassFinder targetContext = new ClassFinder(field);

5
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/VBNetCodeGenerator.cs

@ -27,6 +27,11 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
return v; return v;
} }
public override string GetFieldName(string propertyName)
{
return "m_" + propertyName;
}
public override PropertyDeclaration CreateProperty(IField field, bool createGetter, bool createSetter) public override PropertyDeclaration CreateProperty(IField field, bool createGetter, bool createSetter)
{ {
string propertyName = GetPropertyName(field.Name); string propertyName = GetPropertyName(field.Name);

Loading…
Cancel
Save