123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Threading;
- using ICSharpCode.AvalonEdit.Highlighting;
- using InABox.Core;
- using InABox.Scripting;
- using InABox.WPF;
- using InABox.Wpf;
- using Microsoft.CodeAnalysis;
- using RoslynPad.Editor;
- using RoslynPad.Roslyn;
- using Syncfusion.Data.Extensions;
- using Image = System.Windows.Controls.Image;
- namespace InABox.DynamicGrid
- {
- /// <summary>
- /// Interaction logic for ScriptEditor.xaml
- /// </summary>
- public partial class ScriptEditor : ThemableWindow
- {
- public static RoutedCommand SaveCommand = new();
- private bool _bChanged;
- private string _editorTitle = "ScriptEditor";
- public string EditorTitle
- {
- get => _editorTitle;
- set {
- _editorTitle = value;
- UpdateTitle();
- }
- }
- private RoslynHost _host;
- private readonly SyntaxLanguage _language = SyntaxLanguage.CSharp;
- private readonly string _script = "";
- private Dictionary<string, string[]> _snippets = new();
- private bool bCompiled;
- private readonly Dictionary<bool, Image> compile = SetupImage(Properties.Resources.tick);
- private readonly Dictionary<bool, Image> copy = SetupImage(Properties.Resources.copy);
- private readonly Dictionary<bool, Image> cut = SetupImage(Properties.Resources.cut);
- private readonly Dictionary<bool, Image> paste = SetupImage(Properties.Resources.paste);
- private readonly Dictionary<bool, Image> print = SetupImage(Properties.Resources.print);
- private readonly Dictionary<bool, Image> redo = SetupImage(Properties.Resources.redo);
- private readonly Dictionary<bool, Image> run = SetupImage(Properties.Resources.run);
- private readonly Dictionary<bool, Image> save = SetupImage(Properties.Resources.disk);
- private readonly Dictionary<bool, Image> undo = SetupImage(Properties.Resources.undo);
- static ScriptEditor()
- {
- SaveCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
- }
- public ScriptEditor(string script, SyntaxLanguage language = SyntaxLanguage.CSharp, string scriptTitle = "ScriptEditor")
- {
- _language = language;
- _script = script;
- EditorTitle = scriptTitle;
- InitializeComponent();
- // Not Sure if we need Roslyn for XAML - need to research this
- if (language == SyntaxLanguage.CSharp || language == SyntaxLanguage.XAML)
- try
- {
- if (ScriptDocument.Host == null)
- ScriptDocument.Initialize();
- }
- catch (Exception e)
- {
- MessageBox.Show("Unable to initialize Script Editor!\nPlease try again.\n\n" + e.Message);
- }
- Roslyn.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition(
- language == SyntaxLanguage.HTML
- ? "HTML"
- : language == SyntaxLanguage.XAML
- ? "XML"
- : language == SyntaxLanguage.CSS
- ? "CSS"
- : "C#"
- );
- Roslyn.TextArea.TextEntering += TextArea_TextEntering;
- CheckButton(SaveButton, true, save);
- CheckButton(CopyButton, false, copy);
- CheckButton(CutButton, false, cut);
- CheckButton(PasteButton, false, paste);
- CheckButton(UndoButton, false, undo);
- CheckButton(RedoButton, false, redo);
- CheckButton(PrintButton, true, print);
- CheckButton(CompileButton, language == SyntaxLanguage.CSharp || language == SyntaxLanguage.XAML, compile);
- CheckButton(RunButton, false, run);
- var timer = new DispatcherTimer();
- timer.Interval = TimeSpan.FromMilliseconds(500);
- timer.Tick += Timer_Tick;
- timer.Start();
- bChanged = false;
- }
- public string Script => Roslyn.Text;
- public Dictionary<string, string[]> Snippets
- {
- get => _snippets;
- set
- {
- _snippets = value;
- if (_snippets != null && _snippets.Any())
- {
- SnippetPanel.Visibility = Visibility.Visible;
- SnippetSection.ItemsSource = _snippets.Keys;
- SnippetSection.SelectedValue = _snippets.Keys.First();
- }
- else
- {
- SnippetPanel.Visibility = Visibility.Collapsed;
- }
- }
- }
- private bool bChanged
- {
- get => _bChanged;
- set
- {
- _bChanged = value;
- UpdateTitle();
- }
- }
- private static Dictionary<bool, Image> SetupImage(Bitmap bitmap)
- {
- return new Dictionary<bool, Image>
- {
- { true, new Image { Source = bitmap.AsBitmapImage(), MaxHeight = 32, MaxWidth = 32 } },
- { false, new Image { Source = bitmap.AsGrayScale().AsBitmapImage(), MaxHeight = 32, MaxWidth = 32 } }
- };
- }
- private event EventHandler _onSave;
- public event EventHandler OnSave
- {
- add
- {
- _onSave += value;
- SaveButton.ToolTip = "Save";
- }
- remove
- {
- _onSave -= value;
- if (_onSave == null) SaveButton.ToolTip = "Save & Close";
- }
- }
- private event EventHandler _onCompile;
- public event EventHandler OnCompile
- {
- add
- {
- _onCompile += value;
- CheckButton(CompileButton, true, compile);
- }
- remove => _onCompile -= value;
- }
- private void CheckButton(Button button, bool condition, Dictionary<bool, Image> images)
- {
- if (button.Visibility != Visibility.Visible)
- button.Visibility = Visibility.Visible;
- if (condition != button.IsEnabled)
- {
- button.IsEnabled = condition;
- button.Content = images[condition];
- }
- }
- private void UpdateTitle()
- {
- if (bChanged)
- {
- Title = _editorTitle + "*";
- }
- else
- {
- Title = _editorTitle;
- }
- }
- #region Public Interface
- public ScriptEditor ClearErrors()
- {
- Errors.Items.Clear();
- return this;
- }
- public ScriptEditor AddError(string error)
- {
- Errors.Items.Add(error);
- return this;
- }
- public void Save()
- {
- bChanged = false;
- if (_onSave != null)
- {
- _onSave?.Invoke(this, EventArgs.Empty);
- }
- else
- {
- DialogResult = true;
- Close();
- }
- }
- #endregion
- #region Event Handlers
- private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
- {
- if (string.Equals(e.Text, "\r"))
- e.Handled = true;
- }
- private void OnLoaded(object sender, RoutedEventArgs e)
- {
- if (_language == SyntaxLanguage.CSharp || _language == SyntaxLanguage.XAML)
- {
- Roslyn.DataContext = new ScriptDocument(_script);
- }
- else
- {
- Roslyn.Text = _script;
- bChanged = false;
- }
- //Roslyn.Text = _script;
- //Changed = DateTime.MinValue;
- }
- private void Roslyn_Loaded(object sender, RoutedEventArgs e)
- {
- var editor = (RoslynCodeEditor)sender;
- editor.Focus();
- if (_language == SyntaxLanguage.CSharp || _language == SyntaxLanguage.XAML)
- {
- var changed = bChanged;
- var script = (ScriptDocument)editor.DataContext;
- script.Id = editor.Initialize(
- ScriptDocument.Host,
- new ClassificationHighlightColors(),
- Directory.GetCurrentDirectory(),
- _script,
- SourceCodeKind.Regular
- );
- bChanged = changed;
- }
- }
- private void Roslyn_PreviewKeyDown(object sender, KeyEventArgs e)
- {
- if (bCompiled)
- {
- bCompiled = false;
- CheckButton(RunButton, false, run);
- }
- }
- private void Roslyn_TextChanged(object sender, EventArgs e)
- {
- bChanged = true;
- if (bCompiled)
- {
- bCompiled = false;
- CheckButton(RunButton, false, run);
- }
- }
- private void Timer_Tick(object sender, EventArgs e)
- {
- CheckButton(CopyButton, !string.IsNullOrEmpty(Roslyn.SelectedText), copy);
- CheckButton(CutButton, !string.IsNullOrEmpty(Roslyn.SelectedText), cut);
- CheckButton(PasteButton, Clipboard.ContainsText(), paste);
- CheckButton(UndoButton, Roslyn.CanUndo, undo);
- CheckButton(RedoButton, Roslyn.CanRedo, redo);
- }
- private void OKButton_Click(object sender, RoutedEventArgs e)
- {
- DialogResult = true;
- Close();
- }
- private void CancelButton_Click(object sender, RoutedEventArgs e)
- {
- DialogResult = false;
- Close();
- }
- private void CompileButton_Click(object sender, RoutedEventArgs e)
- {
- CheckButton(RunButton, false, run);
- if (_onCompile != null)
- {
- _onCompile.Invoke(this, EventArgs.Empty);
- }
- else
- {
- var viewModel = (ScriptDocument)Roslyn.DataContext;
- viewModel.Text = Roslyn.Text;
- Errors.Items.Clear();
- Errors.Items.Add("Compiling Script... ");
- Task.Run(() =>
- {
- bCompiled = viewModel.Compile();
- Dispatcher.Invoke(() =>
- {
- Errors.Items.Clear();
- if (bCompiled)
- {
- Errors.Items.Add("Script Compiled Successfully!");
- }
- else
- {
- var errors = viewModel.Result.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
- errors.ForEach(x => Errors.Items.Add(x));
- }
- CheckButton(RunButton, bCompiled, run);
- });
- });
- }
- }
- private void RunButton_Click(object sender, RoutedEventArgs e)
- {
- var viewModel = (ScriptDocument)Roslyn.DataContext;
- try
- {
- var result = viewModel.Execute();
- }
- catch (Exception err)
- {
- MessageBox.Show(CoreUtils.FormatException(err));
- }
- }
- private void GotoLine(string line)
- {
- if (line.StartsWith("("))
- {
- var sLine = line.Substring(1).Split(',')[0];
- var iLine = int.Parse(sLine);
- Roslyn.ScrollToLine(iLine);
- }
- }
- private void Errors_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (e.AddedItems.Count == 1) GotoLine(e.AddedItems[0].ToString());
- }
- private void Errors_PreviewMouseDown(object sender, MouseButtonEventArgs e)
- {
- if (Errors.SelectedItems.Count == 1) GotoLine(Errors.SelectedItems[0].ToString());
- }
- private void Window_Closing(object sender, CancelEventArgs e)
- {
- if (bChanged)
- {
- var bRes = MessageBox.Show("Script has changed. Do you wish to save this script before closing?", "Save Changes",
- MessageBoxButton.YesNoCancel);
- if (bRes == MessageBoxResult.Cancel)
- {
- e.Cancel = true;
- return;
- }
- if (bRes == MessageBoxResult.Yes) _onSave?.Invoke(this, EventArgs.Empty);
- try
- {
- DialogResult = bRes == MessageBoxResult.Yes;
- }
- catch (InvalidOperationException)
- {
- // Do nothing, just avoids a crash when closing a script editor which was opened by Show();
- }
- }
- }
- private void SaveButton_Click(object sender, RoutedEventArgs e)
- {
- Save();
- }
- private void CopyButton_Click(object sender, RoutedEventArgs e)
- {
- Roslyn.Copy();
- }
- private void CutButton_Click(object sender, RoutedEventArgs e)
- {
- Roslyn.Cut();
- }
- private void PasteButton_Click(object sender, RoutedEventArgs e)
- {
- Roslyn.Paste();
- }
- private void UndoButton_Click(object sender, RoutedEventArgs e)
- {
- Roslyn.Undo();
- }
- private void RedoButton_Click(object sender, RoutedEventArgs e)
- {
- Roslyn.Redo();
- }
- private void PrintButton_Click(object sender, RoutedEventArgs e)
- {
- //Syncfusion.Windows.Edit.EditCommands.PrintPreview.Execute(null, Edit1);
- }
- private void Snippets_MouseDoubleClick(object sender, MouseButtonEventArgs e)
- {
- Roslyn.SelectedText = SnippetList.SelectedValue.ToString();
- }
- private void SnippetSection_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- if (e.AddedItems.Count == 1)
- SnippetList.ItemsSource = _snippets[e.AddedItems[0].ToString()];
- else
- SnippetList.ItemsSource = null;
- }
- private void SaveCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
- {
- if (_onSave != null)
- {
- bChanged = false;
- _onSave?.Invoke(this, EventArgs.Empty);
- }
- }
- private void SaveCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
- {
- e.CanExecute = _onSave != null;
- }
- #endregion
- }
- }
|