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 @@ @@ -167,16 +167,6 @@
class = "ICSharpCode.SharpDevelop.Project.LoadSolution"
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"
name = "${res:SharpDevelop.FileFilter.AllFiles}"
extensions = "*.*"/>
@ -1718,12 +1708,6 @@ @@ -1718,12 +1708,6 @@
<!-- 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">
<DisplayBinding id = "OldText"
insertafter = "Text"
@ -1962,16 +1946,6 @@ @@ -1962,16 +1946,6 @@
</OptionPanel>
</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">
<ToolbarItem id = "GotoPrev"
icon = "Bookmarks.GotoPrev"

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

@ -0,0 +1,20 @@ @@ -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 @@ -94,13 +94,15 @@ namespace CSharpBinding
if (char.IsLetter(ch) && CodeCompletionOptions.CompleteWhenTyping) {
if (editor.SelectionLength > 0) {
// allow code completion when overwriting an identifier
cursor = editor.SelectionStart;
int endOffset = cursor + editor.SelectionLength;
int endOffset = editor.SelectionStart + editor.SelectionLength;
// but block code completion when overwriting only part of an identifier
if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset)))
return CodeCompletionKeyPressResult.None;
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) : ' ';
bool afterUnderscore = prevChar == '_';

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

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

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

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

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

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

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

@ -7,8 +7,10 @@ @@ -7,8 +7,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.AvalonEdit.AddIn.Snippets;
using ICSharpCode.AvalonEdit.Indentation;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
@ -25,7 +27,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -25,7 +27,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
{
readonly CodeEditor codeEditor;
public CodeEditorAdapter(CodeEditor codeEditor, TextEditor textEditor) : base(textEditor)
public CodeEditorAdapter(CodeEditor codeEditor, CodeEditorView textEditor) : base(textEditor)
{
if (codeEditor == null)
throw new ArgumentNullException("codeEditor");
@ -94,5 +96,15 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -94,5 +96,15 @@ namespace ICSharpCode.AvalonEdit.AddIn
public override ITextEditor PrimaryView {
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 @@ @@ -1,19 +1,20 @@
/*
* Created by SharpDevelop.
* User: daniel
* Date: 31.08.2009
* Time: 14:55
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// <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.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.AddIn.Snippets;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop;
@ -41,6 +42,50 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -41,6 +42,50 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.MouseHoverStopped += TextEditorMouseHoverStopped;
this.MouseLeave += TextEditorMouseLeave;
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

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

@ -114,10 +114,20 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -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
{
readonly SharpDevelopCompletionWindow window;
readonly ICompletionItem item;
readonly IFancyCompletionItem fancyCompletionItem;
public CodeCompletionDataAdapter(SharpDevelopCompletionWindow window, ICompletionItem item)
{
@ -127,6 +137,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -127,6 +137,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
throw new ArgumentNullException("item");
this.window = window;
this.item = item;
this.fancyCompletionItem = item as IFancyCompletionItem;
}
public ICompletionItem Item {
@ -138,12 +149,14 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -138,12 +149,14 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
public object Content {
get { return item.Text; }
get {
return (fancyCompletionItem != null) ? fancyCompletionItem.Content : item.Text;
}
}
public object Description {
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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ -98,15 +98,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
base.OnSourceInitialized(e);
}
InputHandler myInputHandler;
void AttachEvents()
{
this.TextArea.Caret.PositionChanged += CaretPositionChanged;
this.TextArea.MouseWheel += textArea_MouseWheel;
this.TextArea.PreviewTextInput += textArea_PreviewTextInput;
myInputHandler = new InputHandler(this);
this.TextArea.PushStackedInputHandler(myInputHandler);
}
/// <inheritdoc/>
@ -116,40 +112,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -116,40 +112,8 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.MouseWheel -= textArea_MouseWheel;
this.TextArea.PreviewTextInput -= textArea_PreviewTextInput;
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/>
protected override void OnClosed(EventArgs e)
{

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

@ -67,11 +67,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -67,11 +67,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.PreviewLostKeyboardFocus += TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged += TextAreaDocumentChanged;
this.TextArea.PreviewKeyDown += TextAreaPreviewKeyDown;
this.TextArea.PreviewKeyUp += TextAreaPreviewKeyUp;
if (parentWindow != null) {
parentWindow.LocationChanged += parentWindow_LocationChanged;
}
myInputHandler = new InputHandler(this);
this.TextArea.PushStackedInputHandler(myInputHandler);
}
/// <summary>
@ -85,24 +86,50 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -85,24 +86,50 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.PreviewLostKeyboardFocus -= TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged -= TextAreaDocumentChanged;
this.TextArea.PreviewKeyDown -= TextAreaPreviewKeyDown;
this.TextArea.PreviewKeyUp -= TextAreaPreviewKeyUp;
if (parentWindow != null) {
parentWindow.LocationChanged -= parentWindow_LocationChanged;
}
this.TextArea.PopStackedInputHandler(myInputHandler);
}
void TextAreaPreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = RaiseEventPair(this, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
#region InputHandler
InputHandler myInputHandler;
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,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
readonly CompletionWindowBase window;
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)
{

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

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

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

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

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

@ -49,6 +49,54 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -49,6 +49,54 @@ namespace ICSharpCode.AvalonEdit.Editing
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>
/// Default-implementation of <see cref="ITextAreaInputHandler"/>.
/// </summary>

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

@ -579,12 +579,20 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -579,12 +579,20 @@ namespace ICSharpCode.AvalonEdit.Rendering
Dispatcher.VerifyAccess();
if (inMeasure)
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
InvalidateMeasure(DispatcherPriority.Normal);
// force immediate re-measure
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
@ -800,8 +808,8 @@ namespace ICSharpCode.AvalonEdit.Rendering @@ -800,8 +808,8 @@ namespace ICSharpCode.AvalonEdit.Rendering
/// </summary>
protected override Size ArrangeOverride(Size finalSize)
{
if (!VisualLinesValid)
throw new VisualLinesInvalidException();
EnsureVisualLines();
foreach (UIElement layer in layers) {
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 @@ -185,7 +185,8 @@ namespace ICSharpCode.AvalonEdit.Snippets
Deactivate(EventArgs.Empty);
} else {
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)
TextArea.PopStackedInputHandler(h);
}

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

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

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

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Snippets
@ -48,6 +49,18 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -48,6 +49,18 @@ namespace ICSharpCode.AvalonEdit.Snippets
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

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

@ -7,6 +7,9 @@ @@ -7,6 +7,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils;
@ -34,5 +37,17 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -34,5 +37,17 @@ namespace ICSharpCode.AvalonEdit.Snippets
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 @@ @@ -7,6 +7,8 @@
using System;
using System.Collections.Generic;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Utils;
@ -22,5 +24,13 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -22,5 +24,13 @@ namespace ICSharpCode.AvalonEdit.Snippets
/// Performs insertion of the snippet.
/// </summary>
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; @@ -16,42 +16,32 @@ using ICSharpCode.AvalonEdit.Editing;
namespace ICSharpCode.AvalonEdit.Snippets
{
sealed class SnippetInputHandler : ITextAreaInputHandler
sealed class SnippetInputHandler : TextAreaStackedInputHandler
{
readonly InsertionContext context;
public SnippetInputHandler(InsertionContext context)
: base(context.TextArea)
{
this.context = context;
}
public TextArea TextArea {
get { return context.TextArea; }
}
public void Attach()
public override void Attach()
{
TextArea.PreviewKeyDown += TextArea_PreviewKeyDown;
base.Attach();
SelectElement(FindNextEditableElement(-1, false));
}
void SelectElement(IActiveElement element)
{
if (element != null) {
TextArea.Selection = new SimpleSelection(element.Segment);
TextArea.Caret.Offset = element.Segment.EndOffset;
}
}
public void Detach()
public override void Detach()
{
TextArea.PreviewKeyDown -= TextArea_PreviewKeyDown;
base.Detach();
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) {
context.Deactivate(e);
e.Handled = true;
@ -62,6 +52,14 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -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)
{
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 @@ @@ -6,10 +6,11 @@
// </file>
using System;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Threading;
using System.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
@ -31,6 +32,12 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -31,6 +32,12 @@ namespace ICSharpCode.AvalonEdit.Snippets
int end = context.InsertionPosition;
context.RegisterActiveElement(this, new ReplaceableActiveElement(context, start, end));
}
/// <inheritdoc/>
public override Inline ToTextRun()
{
return new Italic(base.ToTextRun());
}
}
/// <summary>

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

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Snippets
@ -32,5 +33,11 @@ namespace ICSharpCode.AvalonEdit.Snippets @@ -32,5 +33,11 @@ namespace ICSharpCode.AvalonEdit.Snippets
if (text != null)
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 @@ @@ -92,7 +92,6 @@
<Compile Include="Src\Editor\CodeCompletion\OverrideCompletionItem.cs">
</Compile>
<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\Commands\CommentRegion.cs" />
<Compile Include="Src\Editor\Commands\GoToDefinition.cs" />
@ -208,7 +207,6 @@ @@ -208,7 +207,6 @@
<Compile Include="Src\Internal\ConditionEvaluators\WriteableSolutionEvaluator.cs" />
<Compile Include="Src\Internal\Doozers\IOptionPanel.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\File\FileDescriptionTemplate.cs" />
<Compile Include="Src\Internal\Templates\File\FileTemplate.cs" />
@ -271,13 +269,13 @@ @@ -271,13 +269,13 @@
<Compile Include="Src\Services\ParserService\LoadSolutionProjects.cs" />
<Compile Include="Src\Services\ParserService\ParserService.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\Tasks\ErrorPainter.cs" />
<Compile Include="Src\Services\Tasks\Task.cs" />
<Compile Include="Src\Services\Tasks\TaskService.cs" />
<Compile Include="Src\Services\DisplayBinding\IDisplayBinding.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\Internal\Templates\Project\ProjectCreateInformation.cs" />
<Compile Include="Src\Services\ProjectBinding\ProjectBindingService.cs" />
@ -417,7 +415,6 @@ @@ -417,7 +415,6 @@
</Compile>
<Compile Include="Src\Gui\ContentInterfaces\IParseInformationListener.cs" />
<Compile Include="Src\Commands\CustomStringTagProvider.cs" />
<Compile Include="Src\Internal\Templates\CodeTemplateGroup.cs" />
<Compile Include="Src\Commands\VBConverter\CSharpConvertBuffer.cs" />
<Compile Include="Src\Internal\ConditionEvaluators\ActiveViewContentUntitledEvaluator.cs" />
<Compile Include="Src\Services\Debugger\DebuggerService.cs" />
@ -465,7 +462,6 @@ @@ -465,7 +462,6 @@
<Compile Include="Src\Services\ProjectService\ProjectEventHandler.cs" />
<Compile Include="Src\Commands\FileMenuCommands.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\Commands\DebugCommands.cs" />
<Compile Include="Src\Gui\Pads\ProjectBrowser\TreeNodes\AbstractProjectBrowserTreeNode.cs" />
@ -566,7 +562,6 @@ @@ -566,7 +562,6 @@
<EmbeddedResource Include="Resources\WordCountDialog.xfrm" />
<EmbeddedResource Include="Resources\BehaviorTextEditorPanel.xfrm" />
<EmbeddedResource Include="Resources\GeneralTextEditorPanel.xfrm" />
<EmbeddedResource Include="Resources\CodeTemplatePanel.xfrm" />
<EmbeddedResource Include="Resources\MarkersTextEditorPanel.xfrm" />
<Compile Include="Src\TextEditor\Bookmarks\BookmarkBase.cs" />
<Compile Include="Src\TextEditor\Bookmarks\Commands\MenuCommands.cs" />
@ -623,9 +618,6 @@ @@ -623,9 +618,6 @@
<Compile Include="Src\TextEditor\Gui\OptionPanels\BehaviorTextEditorPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Src\TextEditor\Gui\OptionPanels\CodeTemplatePanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Src\TextEditor\Gui\OptionPanels\GeneralTextEditorPanel.cs">
<SubType>UserControl</SubType>
</Compile>

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

@ -1,108 +0,0 @@ @@ -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 @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Commands
case "STARTUPPATH":
return Application.StartupPath;
}
return String.Empty;
return null;
}
}

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

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

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

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
using System;
using System.Collections;
using System.Linq;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Dom;
using System.Collections.Generic;
@ -43,43 +44,27 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -43,43 +44,27 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
/// </summary>
public bool ShowTemplates { get; set; }
// TODO: AVALONEDIT implement templates
/*
void AddTemplates(ITextEditor editor, char charTyped)
void AddTemplates(ITextEditor editor, DefaultCompletionItemList list)
{
if (!ShowTemplates)
if (list == null)
return;
ICompletionData suggestedData = DefaultIndex >= 0 ? completionData[DefaultIndex] : null;
var templateCompletion = new TemplateCompletionItemProvider().GenerateCompletionList(editor);
if (templateCompletion == null || templateCompletionData.Length == 0)
return;
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);
}
List<ICompletionItem> snippets = editor.GetSnippets().ToList();
list.Items.RemoveAll(item => item.Image == ClassBrowserIconService.Keyword && snippets.Exists(i => i.Text == item.Text));
list.Items.AddRange(snippets);
list.SortItems();
}
*/
int preselectionLength;
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;
if (!allowCompleteExistingExpression) {

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

@ -74,7 +74,13 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -74,7 +74,13 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
public void SortItems()
{
// 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/>

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

@ -1,69 +0,0 @@ @@ -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 @@ -117,6 +117,11 @@ namespace ICSharpCode.SharpDevelop.Editor
/// </summary>
IInsightWindow ActiveInsightWindow { get; }
/// <summary>
/// Gets the list of available code snippets.
/// </summary>
IEnumerable<ICompletionItem> GetSnippets();
[Obsolete("Use the overload taking ICompletionItemList")]
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 @@ -16,32 +16,18 @@ namespace ICSharpCode.SharpDevelop.Gui
{
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)
{
codeTemplate.Shortcut = ControlDictionary["templateTextBox"].Text;
codeTemplate.Description = ControlDictionary["descriptionTextBox"].Text;
// codeTemplate.Shortcut = ControlDictionary["templateTextBox"].Text;
// codeTemplate.Description = ControlDictionary["descriptionTextBox"].Text;
}
void InitializeComponents()
{
SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Resources.EditTemplateDialog.xfrm"));
ControlDictionary["templateTextBox"].Text = codeTemplate.Shortcut;
ControlDictionary["descriptionTextBox"].Text = codeTemplate.Description;
// ControlDictionary["templateTextBox"].Text = codeTemplate.Shortcut;
// ControlDictionary["descriptionTextBox"].Text = codeTemplate.Description;
ControlDictionary["okButton"].Click += new EventHandler(AcceptEvent);

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

@ -1,91 +0,0 @@ @@ -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 @@ @@ -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 @@ @@ -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; @@ -15,17 +15,6 @@ using ICSharpCode.TextEditor.Document;
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 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 @@ -299,7 +299,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
string word = GetWordBeforeCaret();
if (word != null) {
CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(FileName);
/*CodeTemplateGroup templateGroup = CodeTemplateLoader.GetTemplateGroupPerFilename(FileName);
if (templateGroup != null) {
foreach (CodeTemplate template in templateGroup.Templates) {
if (template.Shortcut == word) {
@ -313,7 +313,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -313,7 +313,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
return true;
}
}
}
}*/
}
return false;
}
@ -360,53 +360,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -360,53 +360,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
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)
{
base.OnReloadHighlighting(sender, e);

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

@ -1,262 +0,0 @@ @@ -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 @@ -264,6 +264,11 @@ namespace ICSharpCode.SharpDevelop
return this;
}
}
public IEnumerable<ICompletionItem> GetSnippets()
{
return Enumerable.Empty<ICompletionItem>();
}
}
sealed class CompletionItemListAdapter : ICompletionDataProvider

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

@ -149,8 +149,14 @@ namespace ICSharpCode.Core @@ -149,8 +149,14 @@ namespace ICSharpCode.Core
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) {
foreach (StringTagPair pair in customTags) {
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 @@ -317,6 +317,8 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
#region Generate property
public virtual string GetPropertyName(string fieldName)
{
if (string.IsNullOrEmpty(fieldName))
return fieldName;
if (fieldName.StartsWith("_") && fieldName.Length > 1)
return Char.ToUpper(fieldName[1]) + fieldName.Substring(2);
else if (fieldName.StartsWith("m_") && fieldName.Length > 2)
@ -327,6 +329,8 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -327,6 +329,8 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
public virtual string GetParameterName(string fieldName)
{
if (string.IsNullOrEmpty(fieldName))
return fieldName;
if (fieldName.StartsWith("_") && fieldName.Length > 1)
return Char.ToLower(fieldName[1]) + fieldName.Substring(2);
else if (fieldName.StartsWith("m_") && fieldName.Length > 2)
@ -335,6 +339,17 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring @@ -335,6 +339,17 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
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)
{
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 @@ -27,6 +27,11 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring
return v;
}
public override string GetFieldName(string propertyName)
{
return "m_" + propertyName;
}
public override PropertyDeclaration CreateProperty(IField field, bool createGetter, bool createSetter)
{
string propertyName = GetPropertyName(field.Name);

Loading…
Cancel
Save