diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-19 23:12:56 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-19 23:12:56 +0300 |
| commit | 9b7875d904456c34c3698d7fc569078f99ed5187 (patch) | |
| tree | cb6ef38d0f2bde6b78d241e6a9a1ec4ba49ec82f /Software/Visual_Studio/Tango.Stubs | |
| parent | 6e172dd3bc3e2388e532fd43381896f15abaed70 (diff) | |
| download | Tango-9b7875d904456c34c3698d7fc569078f99ed5187.tar.gz Tango-9b7875d904456c34c3698d7fc569078f99ed5187.zip | |
Scripting refactoring.
Diffstat (limited to 'Software/Visual_Studio/Tango.Stubs')
5 files changed, 914 insertions, 2 deletions
diff --git a/Software/Visual_Studio/Tango.Stubs/CSharp-Mode.xshd b/Software/Visual_Studio/Tango.Stubs/CSharp-Mode.xshd new file mode 100644 index 000000000..cb2520461 --- /dev/null +++ b/Software/Visual_Studio/Tango.Stubs/CSharp-Mode.xshd @@ -0,0 +1,298 @@ +<?xml version="1.0"?> +<SyntaxDefinition name="C#" extensions=".cs" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"> + <!-- The named colors 'Comment' and 'String' are used in SharpDevelop to detect if a line is inside a multiline string/comment --> + <Color name="Comment" foreground="#608B4E" exampleText="// comment" /> + <Color name="String" foreground="#C67070" exampleText="string text = "Hello, World!""/> + <Color name="Char" foreground="#C67070" exampleText="char linefeed = '\n';"/> + <Color name="Preprocessor" foreground="DimGray" exampleText="#region Title" /> + <Color name="Punctuation" exampleText="a(b.c);" /> + <Color name="ValueTypes" fontWeight="bold" foreground="#025DB4" exampleText="bool b = true;" /> + <Color name="ReferenceTypes" foreground="#4EC9B0" exampleText="object o;" /> + <Color name="MethodCall" foreground="Gainsboro" fontWeight="bold" exampleText="o.ToString();"/> + <Color name="NumberLiteral" foreground="#E7CA6C" exampleText="3.1415f"/> + <Color name="ThisOrBaseReference" fontWeight="bold" exampleText="this.Do(); base.Do();"/> + <Color name="NullOrValueKeywords" fontWeight="bold" exampleText="if (value == null)"/> + <Color name="Keywords" fontWeight="bold" foreground="#025DB4" exampleText="if (a) {} else {}"/> + <Color name="GotoKeywords" foreground="#3F8FD6" exampleText="continue; return null;"/> + <Color name="ContextKeywords" foreground="#3F8FD6" exampleText="var a = from x in y select z;"/> + <Color name="ExceptionKeywords" fontWeight="bold" foreground="#3F8FD6" exampleText="try {} catch {} finally {}"/> + <Color name="CheckedKeyword" fontWeight="bold" foreground="DarkGray" exampleText="checked {}"/> + <Color name="UnsafeKeywords" foreground="#3F8FD6" exampleText="unsafe { fixed (..) {} }"/> + <Color name="OperatorKeywords" fontWeight="bold" foreground="Pink" exampleText="public static implicit operator..."/> + <Color name="ParameterModifiers" fontWeight="bold" foreground="DeepPink" exampleText="(ref int a, params int[] b)"/> + <Color name="Modifiers" foreground="#3F8FD6" exampleText="static readonly int a;"/> + <Color name="CustomTypes" foreground="#3F8FD6" /> + <Color name="Visibility" fontWeight="bold" foreground="#3F8FD6" exampleText="public override void ToString();"/> + <Color name="NamespaceKeywords" fontWeight="bold" foreground="#569CD6" exampleText="namespace A.B { using System; }"/> + <Color name="GetSetAddRemove" foreground="#3F8FD6" exampleText="int Prop { get; set; }"/> + <Color name="TrueFalse" fontWeight="bold" foreground="#3F8FD6" exampleText="b = false; a = true;" /> + <Color name="TypeKeywords" fontWeight="bold" foreground="#3F8FD6" exampleText="if (x is int) { a = x as int; type = typeof(int); size = sizeof(int); c = new object(); }"/> + + <Property name="DocCommentMarker" value="///" /> + + <RuleSet name="CommentMarkerSet"> + <Keywords fontWeight="bold" foreground="Red"> + <Word>TODO</Word> + <Word>FIXME</Word> + </Keywords> + <Keywords fontWeight="bold" foreground="#E0E000"> + <Word>HACK</Word> + <Word>UNDONE</Word> + </Keywords> + </RuleSet> + + <!-- This is the main ruleset. --> + <RuleSet> + <Span color="Preprocessor"> + <Begin>\#</Begin> + <RuleSet name="PreprocessorSet"> + <Span> <!-- preprocessor directives that allows comments --> + <Begin fontWeight="bold"> + (define|undef|if|elif|else|endif|line)\b + </Begin> + <RuleSet> + <Span color="Comment" ruleSet="CommentMarkerSet"> + <Begin>//</Begin> + </Span> + </RuleSet> + </Span> + <Span> <!-- preprocessor directives that don't allow comments --> + <Begin fontWeight="bold"> + (region|endregion|error|warning|pragma)\b + </Begin> + </Span> + </RuleSet> + </Span> + + <Span color="Comment"> + <Begin color="XmlDoc/DocComment">///</Begin> + <RuleSet> + <Import ruleSet="XmlDoc/DocCommentSet"/> + <Import ruleSet="CommentMarkerSet"/> + </RuleSet> + </Span> + + <Span color="Comment" ruleSet="CommentMarkerSet"> + <Begin>//</Begin> + </Span> + + <Span color="Comment" ruleSet="CommentMarkerSet" multiline="true"> + <Begin>/\*</Begin> + <End>\*/</End> + </Span> + + <Span color="String"> + <Begin>"</Begin> + <End>"</End> + <RuleSet> + <!-- span for escape sequences --> + <Span begin="\\" end="."/> + </RuleSet> + </Span> + + <Span color="Char"> + <Begin>'</Begin> + <End>'</End> + <RuleSet> + <!-- span for escape sequences --> + <Span begin="\\" end="."/> + </RuleSet> + </Span> + + <Span color="String" multiline="true"> + <Begin>@"</Begin> + <End>"</End> + <RuleSet> + <!-- span for escape sequences --> + <Span begin='""' end=""/> + </RuleSet> + </Span> + + <!-- don't highlight "@int" as keyword --> + <Rule> + @[\w\d_]+ + </Rule> + + <Keywords color="CustomTypes"> + @CUSTOM_TYPES@ + </Keywords> + + <Keywords color="ThisOrBaseReference"> + <Word>this</Word> + <Word>base</Word> + </Keywords> + + <Keywords color="TypeKeywords"> + <Word>as</Word> + <Word>is</Word> + <Word>new</Word> + <Word>sizeof</Word> + <Word>typeof</Word> + <Word>stackalloc</Word> + </Keywords> + + <Keywords color="TrueFalse"> + <Word>true</Word> + <Word>false</Word> + </Keywords> + + <Keywords color="Keywords"> + <Word>else</Word> + <Word>if</Word> + <Word>switch</Word> + <Word>case</Word> + <Word>default</Word> + <Word>do</Word> + <Word>for</Word> + <Word>foreach</Word> + <Word>in</Word> + <Word>while</Word> + <Word>lock</Word> + </Keywords> + + <Keywords color="GotoKeywords"> + <Word>break</Word> + <Word>continue</Word> + <Word>goto</Word> + <Word>return</Word> + </Keywords> + + <Keywords color="ContextKeywords"> + <Word>yield</Word> + <Word>partial</Word> + <Word>global</Word> + <Word>where</Word> + <Word>select</Word> + <Word>group</Word> + <Word>by</Word> + <Word>into</Word> + <Word>from</Word> + <Word>ascending</Word> + <Word>descending</Word> + <Word>orderby</Word> + <Word>let</Word> + <Word>join</Word> + <Word>on</Word> + <Word>equals</Word> + <Word>var</Word> + <Word>dynamic</Word> + <Word>await</Word> + </Keywords> + + <Keywords color="ExceptionKeywords"> + <Word>try</Word> + <Word>throw</Word> + <Word>catch</Word> + <Word>finally</Word> + </Keywords> + + <Keywords color="CheckedKeyword"> + <Word>checked</Word> + <Word>unchecked</Word> + </Keywords> + + <Keywords color="UnsafeKeywords"> + <Word>fixed</Word> + <Word>unsafe</Word> + </Keywords> + + <Keywords color="ValueTypes"> + <Word>bool</Word> + <Word>byte</Word> + <Word>char</Word> + <Word>decimal</Word> + <Word>double</Word> + <Word>enum</Word> + <Word>float</Word> + <Word>int</Word> + <Word>long</Word> + <Word>sbyte</Word> + <Word>short</Word> + <Word>struct</Word> + <Word>uint</Word> + <Word>ushort</Word> + <Word>ulong</Word> + </Keywords> + + <Keywords color="ReferenceTypes"> + <Word>class</Word> + <Word>interface</Word> + <Word>delegate</Word> + <Word>object</Word> + <Word>string</Word> + <Word>void</Word> + </Keywords> + + <Keywords color="OperatorKeywords"> + <Word>explicit</Word> + <Word>implicit</Word> + <Word>operator</Word> + </Keywords> + + <Keywords color="ParameterModifiers"> + <Word>params</Word> + <Word>ref</Word> + <Word>out</Word> + </Keywords> + + <Keywords color="Modifiers"> + <Word>abstract</Word> + <Word>const</Word> + <Word>event</Word> + <Word>extern</Word> + <Word>override</Word> + <Word>readonly</Word> + <Word>sealed</Word> + <Word>static</Word> + <Word>virtual</Word> + <Word>volatile</Word> + <Word>async</Word> + </Keywords> + + <Keywords color="Visibility"> + <Word>public</Word> + <Word>protected</Word> + <Word>private</Word> + <Word>internal</Word> + </Keywords> + + <Keywords color="NamespaceKeywords"> + <Word>namespace</Word> + <Word>using</Word> + <Word>include</Word> + </Keywords> + + <Keywords color="GetSetAddRemove"> + <Word>get</Word> + <Word>set</Word> + <Word>add</Word> + <Word>remove</Word> + </Keywords> + + <Keywords color="NullOrValueKeywords"> + <Word>null</Word> + <Word>value</Word> + </Keywords> + + <!-- Mark previous rule--> + <Rule color="MethodCall"> + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + </Rule> + + <!-- Digits --> + <Rule color="NumberLiteral"> + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + </Rule> + + <Rule color="Punctuation"> + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + </Rule> + </RuleSet> +</SyntaxDefinition> diff --git a/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml b/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml new file mode 100644 index 000000000..3c8796eca --- /dev/null +++ b/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml @@ -0,0 +1,113 @@ +<UserControl x:Class="Tango.Stubs.Controls.ScriptEditorControl" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:fa="http://schemas.fontawesome.io/icons/" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + mc:Ignorable="d" + d:DesignHeight="400" d:DesignWidth="600" Background="#151515"> + + <UserControl.InputBindings> + <KeyBinding Key="F5" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=RunCommand}" /> + </UserControl.InputBindings> + + <Grid> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="40"/> + <RowDefinition Height="1*"/> + </Grid.RowDefinitions> + <Border BorderThickness="0 0 0 1" BorderBrush="#545454"> + <ToolBar Background="#202020"> + <StackPanel Margin="20 0 0 0" Orientation="Horizontal"> + <Button Cursor="Hand" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=SaveCommand}" ToolTip="Save" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="16"> + <fa:ImageAwesome Icon="Save" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Rectangle Margin="20 7 10 5" HorizontalAlignment="Center" VerticalAlignment="Stretch" Stroke="#3E3E3E" StrokeThickness="2"></Rectangle> + <Button Cursor="Hand" Command="Undo" Margin="10 0 0 0" ToolTip="Undo" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="16"> + <fa:ImageAwesome Icon="Undo" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Button Cursor="Hand" Command="Redo" Margin="10 0 0 0" ToolTip="Redo" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="16"> + <fa:ImageAwesome Icon="Repeat" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Rectangle Margin="20 7 10 5" HorizontalAlignment="Center" VerticalAlignment="Stretch" Stroke="#3E3E3E" StrokeThickness="2"></Rectangle> + <Button Cursor="Hand" Command="Cut" Margin="10 0 0 0" ToolTip="Cut" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="16"> + <fa:ImageAwesome Icon="Cut" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Button Cursor="Hand" Command="Copy" Margin="10 0 0 0" ToolTip="Copy" Style="{DynamicResource MetroCircleButtonStyle}" Width="20" Height="16"> + <fa:ImageAwesome Icon="Copy" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Button Cursor="Hand" Command="Paste" Margin="10 0 0 0" ToolTip="Paste" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="20"> + <fa:ImageAwesome Icon="Paste" Foreground="LightGray"></fa:ImageAwesome> + </Button> + <Rectangle Margin="20 7 10 5" HorizontalAlignment="Center" VerticalAlignment="Stretch" Stroke="#3E3E3E" StrokeThickness="2"></Rectangle> + <Button Cursor="Hand" Margin="10 0 0 0" ToolTip="Run (F5)" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=RunCommand}" Style="{DynamicResource MetroCircleButtonStyle}" Width="16" Height="16"> + <fa:ImageAwesome Icon="Play"> + <fa:ImageAwesome.Style> + <Style TargetType="fa:ImageAwesome"> + <Setter Property="Foreground" Value="#8DD28A"></Setter> + <Style.Triggers> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Foreground" Value="Gray"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </fa:ImageAwesome.Style> + </fa:ImageAwesome> + </Button> + <Button Cursor="Hand" Margin="15 0 0 0" ToolTip="Stop" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=StopCommand}" Style="{DynamicResource MetroCircleButtonStyle}" Width="14" Height="14"> + <fa:ImageAwesome Icon="Stop"> + <fa:ImageAwesome.Style> + <Style TargetType="fa:ImageAwesome"> + <Setter Property="Foreground" Value="#F38B76"></Setter> + <Style.Triggers> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Foreground" Value="Gray"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </fa:ImageAwesome.Style> + </fa:ImageAwesome> + </Button> + </StackPanel> + </ToolBar> + </Border> + + <Border Grid.Row="1" CornerRadius="5" BorderThickness="0" BorderBrush="#404040"> + <avalonEdit:TextEditor Padding="5" TextChanged="textEditor_TextChanged" Background="#151515" Foreground="Gainsboro" Margin="5 5 0 0" ScrollViewer.HorizontalScrollBarVisibility="Auto" + Name="textEditor" + FontFamily="Consolas" + FontSize="10pt" + SyntaxHighlighting="C#" + ShowLineNumbers="True"> + <avalonEdit:TextEditor.ContextMenu> + <ContextMenu> + <ContextMenu.Resources> + <Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}"> + <Setter Property="Foreground" Value="Gainsboro"></Setter> + </Style> + </ContextMenu.Resources> + <MenuItem Header="Cut" MinWidth="150" Command="Cut"> + <MenuItem.Icon> + <fa:ImageAwesome Icon="Cut" Width="12" Foreground="Gainsboro" Margin="2" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem Header="Copy" Command="Copy"> + <MenuItem.Icon> + <fa:ImageAwesome Icon="Copy" Width="12" Foreground="Gainsboro" Margin="2" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="Paste" Command="Paste"> + <MenuItem.Icon> + <fa:ImageAwesome Icon="Paste" Width="12" Foreground="Gainsboro" Margin="2" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + </avalonEdit:TextEditor.ContextMenu> + </avalonEdit:TextEditor> + </Border> + </Grid> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml.cs b/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml.cs new file mode 100644 index 000000000..7628e5655 --- /dev/null +++ b/Software/Visual_Studio/Tango.Stubs/Controls/ScriptEditorControl.xaml.cs @@ -0,0 +1,488 @@ +using ICSharpCode.AvalonEdit.CodeCompletion; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Editing; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using System.Xml; +using Tango.Core.Commands; +using Tango.Scripting; +using Tango.SharedUI; +using Tango.SharedUI.Helpers; + +namespace Tango.Stubs.Controls +{ + /// <summary> + /// Represents a C# script editor control. + /// </summary> + /// <seealso cref="System.Windows.Controls.UserControl" /> + /// <seealso cref="System.Windows.Markup.IComponentConnector" /> + public partial class ScriptEditorControl : UserControl + { + #region Completion + + /// <summary> + /// Represents an auto complete item. + /// </summary> + /// <seealso cref="ICSharpCode.AvalonEdit.CodeCompletion.ICompletionData" /> + internal class CompletionData : ICompletionData + { + private String _description; + + /// <summary> + /// Gets or sets the icon source. + /// </summary> + public BitmapSource Source { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="CompletionData"/> class. + /// </summary> + /// <param name="text">The text.</param> + /// <param name="description">The description.</param> + public CompletionData(string text, String description) + { + this.Text = text; + _description = description; + } + + /// <summary> + /// Gets the image. + /// </summary> + public System.Windows.Media.ImageSource Image + { + get { return Source; } + } + + /// <summary> + /// Gets the text. This property is used to filter the list of visible elements. + /// </summary> + public string Text { get; private set; } + + // Use this property if you want to show a fancy UIElement in the drop down list. + public object Content + { + get { return this.Text; } + } + + /// <summary> + /// Gets the description. + /// </summary> + public object Description + { + get { return _description; } + } + + /// <summary> + /// Gets the priority. This property is used in the selection logic. You can use it to prefer selecting those items + /// which the user is accessing most frequently. + /// </summary> + public double Priority { get { return 0; } } + + /// <summary> + /// Perform the completion. + /// </summary> + /// <param name="textArea">The text area on which completion is performed.</param> + /// <param name="completionSegment">The text segment that was used by the completion window if + /// the user types (segment between CompletionWindow.StartOffset and CompletionWindow.EndOffset).</param> + /// <param name="insertionRequestEventArgs">The EventArgs used for the insertion request. + /// These can be TextCompositionEventArgs, KeyEventArgs, MouseEventArgs, depending on how + /// the insertion was triggered.</param> + public void Complete(TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs) + { + textArea.Document.Replace(completionSegment, this.Text); + } + + /// <summary> + /// Returns a <see cref="System.String" /> that represents this instance. + /// </summary> + /// <returns> + /// A <see cref="System.String" /> that represents this instance. + /// </returns> + public override string ToString() + { + return Text; + } + } + + #endregion + + private CompletionWindow completionWindow; //Holds the auto-complete window instance. + + #region Constructors + + /// <summary> + /// Initializes a new instance of the <see cref="ScriptEditorControl"/> class. + /// </summary> + public ScriptEditorControl() + { + InitializeComponent(); + + textEditor.TextArea.IndentationStrategy = new ICSharpCode.AvalonEdit.Indentation.CSharp.CSharpIndentationStrategy(); + textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering; + textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered; + + this.Loaded += ScriptEditorControl_Loaded; + } + + #endregion + + #region Event Handlers + + /// <summary> + /// Handles the TextEntered event of the textEditor_TextArea control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="TextCompositionEventArgs"/> instance containing the event data.</param> + private void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e) + { + if (e.Text == ".") + { + String keyword = textEditor.TextArea.GetJustCurrentWord(); + + if (keyword != null) + { + completionWindow = new CompletionWindow(textEditor.TextArea); + completionWindow.WindowStyle = WindowStyle.None; + completionWindow.AllowsTransparency = true; + completionWindow.ResizeMode = ResizeMode.NoResize; + + IList<ICompletionData> data = completionWindow.CompletionList.CompletionData; + + bool ok = false; + + List<KeyValuePair<String, Type>> types = new List<KeyValuePair<String, Type>>(); + + types.AddRange(IntellisenseTypes); + + + if (IntellisenseTypes != null) + { + ScriptParser parser = new ScriptParser(); + + try + { + var variables = parser.ParseScript(textEditor.Text); + + foreach (var v in variables) + { + var hT = IntellisenseTypes.SingleOrDefault(x => x.Key == v.Type); + + if (hT.Value != null) + { + types.Add(new KeyValuePair<string, Type>(v.Name, hT.Value)); + } + } + + } + catch { } + } + + KeyValuePair<String, Type> type = types.LastOrDefault(x => keyword == x.Key); + + if (type.Key != null) + { + ok = true; + FillType(type.Value, data); + } + + if (ok) + { + completionWindow.Show(); + completionWindow.Closed += delegate + { + completionWindow = null; + }; + } + } + } + } + + /// <summary> + /// Handles the TextEntering event of the textEditor_TextArea control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="TextCompositionEventArgs"/> instance containing the event data.</param> + private void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e) + { + if (e.Text.Length > 0 && completionWindow != null) + { + if (!char.IsLetterOrDigit(e.Text[0])) + { + // Whenever a non-letter is typed while the completion window is open, + // insert the currently selected element. + completionWindow.CompletionList.RequestInsertion(e); + } + } + } + + /// <summary> + /// Handles the TextChanged event of the textEditor control. + /// </summary> + /// <param name="sender">The source of the event.</param> + /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> + private void textEditor_TextChanged(object sender, EventArgs e) + { + Text = textEditor.Text; + } + + private void ScriptEditorControl_Loaded(object sender, RoutedEventArgs e) + { + if (HighlightTypes != null) + { + Stream xshd_stream = typeof(ScriptEditorControl).Assembly.GetManifestResourceStream("Tango.Stubs.CSharp-Mode.xshd"); + + String text = String.Empty; + + using (StreamReader reader = new StreamReader(xshd_stream)) + { + text = reader.ReadToEnd(); + } + + String code = String.Empty; + + + + foreach (var name in HighlightTypes.Select(x => x.Key)) + { + code += String.Format("<Word>{0}</Word>", name) + Environment.NewLine; + } + + text = text.Replace("@CUSTOM_TYPES@", code); + + using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text))) + { + XmlTextReader xshd_reader = new XmlTextReader(ms); + textEditor.SyntaxHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(xshd_reader, ICSharpCode.AvalonEdit.Highlighting.HighlightingManager.Instance); + xshd_reader.Close(); + } + } + } + + #endregion + + #region Private Methods + + /// <summary> + /// Fills the type. + /// </summary> + /// <param name="type">The type.</param> + /// <param name="data">The data.</param> + private void FillType(Type type, IList<ICompletionData> data) + { + List<CompletionData> items = new List<CompletionData>(); + + foreach (var method in type.GetMethods().Where(x => x.IsPublic && !x.IsSpecialName)) + { + String desc = method.ReturnType.Name + " " + method.Name + "(" + String.Join(", ", method.GetParameters().Select(x => x.ParameterType.Name + " " + x.Name).ToArray()) + ")"; + items.Add(new CompletionData(method.Name, desc) { Source = ResourceHelper.GetImageFromResources("Images/pubmethod.gif") }); + } + foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + String desc = property.PropertyType.Name + " " + property.Name; + items.Add(new CompletionData(property.Name, desc) { Source = ResourceHelper.GetImageFromResources("Images/pubproperty.gif") }); + } + foreach (var ev in type.GetEvents(BindingFlags.Instance | BindingFlags.Public)) + { + try + { + String desc = ev.Name + " " + "(" + String.Join(", ", ev.EventHandlerType.GetMethod("Invoke").GetParameters().Select(x => x.ParameterType.Name + " " + x.Name).ToArray()) + ")"; + items.Add(new CompletionData(ev.Name, desc) { Source = ResourceHelper.GetImageFromResources("Images/pubevent.gif") }); + } + catch { } + } + + foreach (var item in items.OrderBy(x => x.Text)) + { + data.Add(item); + } + } + + /// <summary> + /// Fills the assembly. + /// </summary> + /// <param name="asm">The asm.</param> + /// <param name="data">The data.</param> + private void FillAssembly(Assembly asm, IList<ICompletionData> data) + { + var q = from t in asm.GetTypes() + where t.IsClass + select t; + + foreach (var type in q) + { + data.Add(new CompletionData(type.Name, "Class") { Source = ResourceHelper.GetImageFromResources("Images/pubclass.gif") }); + } + } + + #endregion + + #region Properties + + /// <summary> + /// Gets or sets the text. + /// </summary> + public String Text + { + get { return (String)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(String), typeof(ScriptEditorControl), new PropertyMetadata(null, (d, e) => (d as ScriptEditorControl).OnTextChanged())); + + /// <summary> + /// Gets or sets the highlight types. + /// </summary> + public ObservableCollection<KeyValuePair<string, Type>> HighlightTypes + { + get { return (ObservableCollection<KeyValuePair<string, Type>>)GetValue(HighlightTypesProperty); } + set { SetValue(HighlightTypesProperty, value); } + } + public static readonly DependencyProperty HighlightTypesProperty = + DependencyProperty.Register("HighlightTypes", typeof(ObservableCollection<KeyValuePair<string, Type>>), typeof(ScriptEditorControl), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the intellisense types. + /// </summary> + public ObservableCollection<KeyValuePair<String,Type>> IntellisenseTypes + { + get { return (ObservableCollection<KeyValuePair<String,Type>>)GetValue(IntellisenseTypesProperty); } + set { SetValue(IntellisenseTypesProperty, value); } + } + public static readonly DependencyProperty IntellisenseTypesProperty = + DependencyProperty.Register("IntellisenseTypes", typeof(ObservableCollection<KeyValuePair<String,Type>>), typeof(ScriptEditorControl), new PropertyMetadata(null)); + + + #endregion + + #region Virtual Methods + + /// <summary> + /// Called when the text has changed. + /// </summary> + protected virtual void OnTextChanged() + { + if (textEditor.Text != Text) + { + textEditor.Text = Text; + } + } + + /// <summary> + /// Called when the insert script command has changed. + /// </summary> + protected virtual void OnInsertScriptCommandChanged() + { + if (InsertSnippetCommand != null) + { + InsertSnippetCommand.Executed += (x, snippet) => + { + textEditor.Document.Insert(textEditor.TextArea.Caret.Offset, snippet); + }; + } + } + + #endregion + + #region Commands + + /// <summary> + /// Gets or sets the run command. + /// </summary> + public RelayCommand RunCommand + { + get { return (RelayCommand)GetValue(RunCommandProperty); } + set { SetValue(RunCommandProperty, value); } + } + public static readonly DependencyProperty RunCommandProperty = + DependencyProperty.Register("RunCommand", typeof(RelayCommand), typeof(ScriptEditorControl), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the stop command. + /// </summary> + public RelayCommand StopCommand + { + get { return (RelayCommand)GetValue(StopCommandProperty); } + set { SetValue(StopCommandProperty, value); } + } + public static readonly DependencyProperty StopCommandProperty = + DependencyProperty.Register("StopCommand", typeof(RelayCommand), typeof(ScriptEditorControl), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the save command. + /// </summary> + public RelayCommand SaveCommand + { + get { return (RelayCommand)GetValue(SaveCommandProperty); } + set { SetValue(SaveCommandProperty, value); } + } + public static readonly DependencyProperty SaveCommandProperty = + DependencyProperty.Register("SaveCommand", typeof(RelayCommand), typeof(ScriptEditorControl), new PropertyMetadata(null)); + + /// <summary> + /// Gets or sets the insert snippet command. + /// </summary> + public RelayCommand<String> InsertSnippetCommand + { + get { return (RelayCommand<String>)GetValue(InsertSnippetCommandProperty); } + set { SetValue(InsertSnippetCommandProperty, value); } + } + public static readonly DependencyProperty InsertSnippetCommandProperty = + DependencyProperty.Register("InsertSnippetCommand", typeof(RelayCommand<String>), typeof(ScriptEditorControl), new PropertyMetadata(null, (d, e) => (d as ScriptEditorControl).OnInsertScriptCommandChanged())); + + #endregion + } + + internal static class DocumentUtils + { + private static Regex _wordRegex = new Regex(@"[^\W\d][\w]*(?<=\w)", RegexOptions.Compiled); + + public static string GetJustCurrentWord(this TextArea textArea) + { + try + { + DocumentLine line = textArea.Document.GetLineByNumber(textArea.Caret.Line); + if (line.Length == 0) + return null; + + int lineCaretPosition = textArea.Caret.Offset - line.Offset; + String l = textArea.Document.GetText(line); + + String trimmed = l.Remove(lineCaretPosition, l.Length - lineCaretPosition); + + return SplitToWords(trimmed).LastOrDefault(x => !String.IsNullOrWhiteSpace(x)); + } + catch + { + return null; + } + } + + public static List<String> SplitToWords(String text) + { + text = text.Replace(".", " "); + text = text.Replace("(", " "); + text = text.Replace(")", " "); + text = text.Replace(",", " "); + var punctuation = text.Where(Char.IsPunctuation).Distinct().ToArray(); + var words = text.Split().Select(x => x.Trim(punctuation)); + return words.ToList(); + } + } +} diff --git a/Software/Visual_Studio/Tango.Stubs/Tango.Stubs.csproj b/Software/Visual_Studio/Tango.Stubs/Tango.Stubs.csproj index 828248c9b..80c63b5d4 100644 --- a/Software/Visual_Studio/Tango.Stubs/Tango.Stubs.csproj +++ b/Software/Visual_Studio/Tango.Stubs/Tango.Stubs.csproj @@ -96,12 +96,16 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="ConnectionMode.cs" /> + <Compile Include="Controls\ScriptEditorControl.xaml.cs"> + <DependentUpon>ScriptEditorControl.xaml</DependentUpon> + </Compile> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\Resources.Designer.cs"> <AutoGen>True</AutoGen> <DesignTime>True</DesignTime> <DependentUpon>Resources.resx</DependentUpon> </Compile> + <EmbeddedResource Include="CSharp-Mode.xshd" /> <None Include="Resources\CodeTabTemplate.cs" /> <Compile Include="ViewModels\CodeTabVM.cs" /> <Compile Include="ViewModels\CreateGroupVM.cs" /> @@ -124,6 +128,10 @@ </EmbeddedResource> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\SideChains\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj"> + <Project>{6c55b776-26d4-4db3-a6ab-87e783b2f3d1}</Project> + <Name>ICSharpCode.AvalonEdit</Name> + </ProjectReference> <ProjectReference Include="..\Tango.BL\Tango.BL.csproj"> <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> <Name>Tango.BL</Name> @@ -174,6 +182,10 @@ <None Include="packages.config" /> </ItemGroup> <ItemGroup> + <Page Include="Controls\ScriptEditorControl.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Views\StubsView.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> @@ -186,7 +198,7 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.Stubs/Views/StubsView.xaml b/Software/Visual_Studio/Tango.Stubs/Views/StubsView.xaml index 456a6718f..00dc806e3 100644 --- a/Software/Visual_Studio/Tango.Stubs/Views/StubsView.xaml +++ b/Software/Visual_Studio/Tango.Stubs/Views/StubsView.xaml @@ -11,6 +11,7 @@ xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:localControls="clr-namespace:Tango.Stubs.Controls" xmlns:transport="clr-namespace:Tango.Transport.Adapters;assembly=Tango.Transport" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" Background="#202020" Foreground="Gainsboro" d:DataContext="{d:DesignInstance Type=vm:StubsViewVM, IsDesignTimeCreatable=False}"> @@ -82,7 +83,7 @@ <RowDefinition Height="1*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> - <controls:ScriptEditorControl Text="{Binding Code,Mode=TwoWay}" InsertSnippetCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.InsertSnippetCommand,Mode=TwoWay}" SaveCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.SaveCommand}" HighlightTypes="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.HighlightTypes}" IntellisenseTypes="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.IntellisenseTypes}" RunCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RunCommand}" StopCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.StopCommand}" /> + <localControls:ScriptEditorControl Text="{Binding Code,Mode=TwoWay}" InsertSnippetCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.InsertSnippetCommand,Mode=TwoWay}" SaveCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.SaveCommand}" HighlightTypes="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.HighlightTypes}" IntellisenseTypes="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.IntellisenseTypes}" RunCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RunCommand}" StopCommand="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.StopCommand}" /> <Grid Grid.Row="1"> <Grid.Style> |
