Browse Source

Improved F# interactive pad.

Add InitiallyFocusedControl to pads.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5498 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Daniel Grunwald 16 years ago
parent
commit
3c212c5839
  1. 2
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/InteractiveInterpreter.cs
  2. 3
      src/AddIns/BackendBindings/FSharpBinding/FSharpBinding.addin
  3. 99
      src/AddIns/BackendBindings/FSharpBinding/FSharpInteractive.cs
  4. 4
      src/AddIns/Misc/StartPage/Project/Src/RecentProjectsControl.xaml
  5. 1
      src/AddIns/Misc/StartPage/Project/Src/RecentProjectsControl.xaml.cs
  6. 2
      src/AddIns/Misc/StartPage/Project/Src/StartPageControl.xaml
  7. 8
      src/Main/Base/Project/Src/Gui/AbstractPadContent.cs
  8. 2
      src/Main/Base/Project/Src/Gui/AbstractViewContent.cs
  9. 9
      src/Main/Base/Project/Src/Gui/IPadContent.cs
  10. 33
      src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs
  11. 6
      src/Main/Base/Project/Src/Gui/Pads/FileScout.cs
  12. 12
      src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs

2
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/InteractiveInterpreter.cs

@ -95,7 +95,7 @@ namespace Grunwald.BooBinding
if (processing) if (processing)
AppendLine(text.ToString()); AppendLine(text.ToString());
else else
InsertLineBeforePrompt(text.ToString()); InsertBeforePrompt(text.ToString() + Environment.NewLine);
} }
} }

3
src/AddIns/BackendBindings/FSharpBinding/FSharpBinding.addin

@ -101,7 +101,8 @@
category = "Main" category = "Main"
title = "F# Interactive" title = "F# Interactive"
icon = "F#.ProjectIcon" icon = "F#.ProjectIcon"
class = "FSharpBinding.FSharpInteractive"/> class = "FSharpBinding.FSharpInteractive"
defaultPosition = "Bottom, Hidden" />
</Path> </Path>
<Path name = "/SharpDevelop/ViewContent/DefaultTextEditor/ContextMenu"> <Path name = "/SharpDevelop/ViewContent/DefaultTextEditor/ContextMenu">

99
src/AddIns/BackendBindings/FSharpBinding/FSharpInteractive.cs

@ -5,54 +5,37 @@
// <version>$Revision$</version> // <version>$Revision$</version>
// </file> // </file>
using ICSharpCode.SharpDevelop.Editor;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Configuration; using System.Configuration;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
namespace FSharpBinding namespace FSharpBinding
{ {
public class FSharpInteractive : AbstractPadContent public class FSharpInteractive : AbstractConsolePad
{ {
Queue<string> outputQueue = new Queue<string>(); Queue<string> outputQueue = new Queue<string>();
internal readonly Process fsiProcess = new Process(); internal readonly Process fsiProcess = new Process();
Panel panel = new Panel();
TextBox input, output;
internal readonly bool foundCompiler; internal readonly bool foundCompiler;
public FSharpInteractive() public FSharpInteractive()
{ {
input = new TextBox {
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
Width = panel.Width
};
output = new TextBox {
Multiline = true,
Top = input.Height,
Height = panel.Height - input.Height,
Width = panel.Width,
ReadOnly = true,
ScrollBars = ScrollBars.Both,
WordWrap = false,
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom
};
panel.Controls.Add(input);
panel.Controls.Add(output);
if (Array.Exists(ConfigurationManager.AppSettings.AllKeys, x => x == "alt_fs_bin_path")) { if (Array.Exists(ConfigurationManager.AppSettings.AllKeys, x => x == "alt_fs_bin_path")) {
string path = Path.Combine(ConfigurationManager.AppSettings["alt_fs_bin_path"], "fsi.exe"); string path = Path.Combine(ConfigurationManager.AppSettings["alt_fs_bin_path"], "fsi.exe");
if (File.Exists(path)) { if (File.Exists(path)) {
fsiProcess.StartInfo.FileName = path; fsiProcess.StartInfo.FileName = path;
foundCompiler = true; foundCompiler = true;
} else { } else {
output.Text = "you are trying to use the app setting alt_fs_bin_path, but fsi.exe is not localed in the given directory"; AppendLine("you are trying to use the app setting alt_fs_bin_path, but fsi.exe is not localed in the given directory");
foundCompiler = false; foundCompiler = false;
} }
} else { } else {
@ -68,37 +51,26 @@ namespace FSharpBinding
foundCompiler = true; foundCompiler = true;
} else { } else {
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
var possibleFiles = from fsdir in Directory.GetDirectories(programFiles, "FSharp*") path = Path.Combine(programFiles, @"Microsoft F#\v4.0\Fsi.exe");
//LoggingService.Debug("Trying to find fsi in '" + fsdir + "'"); if (File.Exists(path)) {
let fileInfo = new FileInfo(Path.Combine(fsdir, "bin\\fsi.exe")) fsiProcess.StartInfo.FileName = path;
where fileInfo.Exists
orderby fileInfo.CreationTime
select fileInfo;
FileInfo file = possibleFiles.FirstOrDefault();
if (file != null) {
fsiProcess.StartInfo.FileName = file.FullName;
foundCompiler = true; foundCompiler = true;
} else { } else {
output.Text = "Can not find the fsi.exe, ensure a version of the F# compiler is installed." + Environment.NewLine + AppendLine("Can not find the fsi.exe, ensure a version of the F# compiler is installed." + Environment.NewLine +
"Please see http://research.microsoft.com/fsharp for details of how to install the compiler"; "Please see http://research.microsoft.com/fsharp for details of how to install the compiler");
foundCompiler = false; foundCompiler = false;
} }
} }
} }
if (foundCompiler) { if (foundCompiler) {
input.KeyUp += delegate(object sender, KeyEventArgs e) {
if (e.KeyData == Keys.Return) {
fsiProcess.StandardInput.WriteLine(input.Text);
input.Text = "";
}
};
//fsiProcess.StartInfo.Arguments <- "--fsi-server sharpdevelopfsi"; //fsiProcess.StartInfo.Arguments <- "--fsi-server sharpdevelopfsi";
fsiProcess.StartInfo.UseShellExecute = false; fsiProcess.StartInfo.UseShellExecute = false;
fsiProcess.StartInfo.CreateNoWindow = true; fsiProcess.StartInfo.CreateNoWindow = true;
fsiProcess.StartInfo.RedirectStandardError = true; fsiProcess.StartInfo.RedirectStandardError = true;
fsiProcess.StartInfo.RedirectStandardInput = true; fsiProcess.StartInfo.RedirectStandardInput = true;
fsiProcess.StartInfo.RedirectStandardOutput = true; fsiProcess.StartInfo.RedirectStandardOutput = true;
fsiProcess.EnableRaisingEvents = true;
fsiProcess.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) { fsiProcess.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) {
lock (outputQueue) { lock (outputQueue) {
outputQueue.Enqueue(e.Data); outputQueue.Enqueue(e.Data);
@ -117,31 +89,52 @@ namespace FSharpBinding
outputQueue.Enqueue("restarting ..."); outputQueue.Enqueue("restarting ...");
} }
WorkbenchSingleton.SafeThreadAsyncCall(ReadAll); WorkbenchSingleton.SafeThreadAsyncCall(ReadAll);
fsiProcess.Start(); WorkbenchSingleton.SafeThreadAsyncCall(StartFSharp);
};
fsiProcess.Start();
fsiProcess.BeginErrorReadLine();
fsiProcess.BeginOutputReadLine();
} else {
input.KeyUp += delegate(object sender, KeyEventArgs e) {
if (e.KeyData == Keys.Return) {
output.AppendText(Environment.NewLine + "F# not installed - could not execute command");
input.Text = "";
}
}; };
StartFSharp();
} }
} }
void StartFSharp()
{
fsiProcess.Start();
fsiProcess.BeginErrorReadLine();
fsiProcess.BeginOutputReadLine();
}
int expectedPrompts;
void ReadAll() void ReadAll()
{ {
StringBuilder b = new StringBuilder();
lock (outputQueue) { lock (outputQueue) {
while (outputQueue.Count > 0) while (outputQueue.Count > 0)
output.AppendText(outputQueue.Dequeue() + Environment.NewLine); b.AppendLine(outputQueue.Dequeue());
}
int offset = 0;
// ignore prompts inserted by fsi.exe (we only see them too late as we're reading line per line)
for (int i = 0; i < expectedPrompts; i++) {
if (offset + 1 < b.Length && b[offset] == '>' && b[offset + 1] == ' ')
offset += 2;
else
break;
} }
expectedPrompts = 0;
InsertBeforePrompt(b.ToString(offset, b.Length - offset));
} }
public override object Control { protected override string Prompt {
get { return panel; } get { return "> "; }
}
protected override bool AcceptCommand(string command)
{
if (command.TrimEnd().EndsWith(";;", StringComparison.Ordinal)) {
expectedPrompts++;
fsiProcess.StandardInput.WriteLine(command);
return true;
}
return false;
} }
} }

4
src/AddIns/Misc/StartPage/Project/Src/RecentProjectsControl.xaml

@ -7,6 +7,7 @@
Name="lastProjectsListView" Name="lastProjectsListView"
SelectionMode="Single" SelectionMode="Single"
core:SortableGridViewColumn.SortMode="Automatic" core:SortableGridViewColumn.SortMode="Automatic"
Margin="0,0,0,20"
MouseDoubleClick="lastProjectsDoubleClick" MouseDoubleClick="lastProjectsDoubleClick"
KeyDown="lastProjectsKeyDown"> KeyDown="lastProjectsKeyDown">
<ListView.Resources> <ListView.Resources>
@ -38,8 +39,7 @@
</ListView.View> </ListView.View>
</ListView> </ListView>
<StackPanel <StackPanel
Orientation="Horizontal" Orientation="Horizontal">
Margin="0,20,0,0">
<Button <Button
Content="{core:Localize StartPage.StartMenu.OpenCombineButton}" Content="{core:Localize StartPage.StartMenu.OpenCombineButton}"
Click="openSolutionClick" /> Click="openSolutionClick" />

1
src/AddIns/Misc/StartPage/Project/Src/RecentProjectsControl.xaml.cs

@ -54,6 +54,7 @@ namespace ICSharpCode.StartPage
} }
} }
lastProjectsListView.ItemsSource = items; lastProjectsListView.ItemsSource = items;
lastProjectsListView.Visibility = items.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
} }
class RecentOpenItem class RecentOpenItem

2
src/AddIns/Misc/StartPage/Project/Src/StartPageControl.xaml

@ -5,7 +5,7 @@
<ScrollViewer <ScrollViewer
VerticalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Disabled"> HorizontalScrollBarVisibility="Disabled">
<Grid> <Grid MinWidth="200"> <!-- use minimum width to avoid the text wrapping from getting ridiculous -->
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition <RowDefinition
Height="72" /> Height="72" />

8
src/Main/Base/Project/Src/Gui/AbstractPadContent.cs

@ -12,10 +12,18 @@ namespace ICSharpCode.SharpDevelop.Gui
{ {
public abstract class AbstractPadContent : IPadContent public abstract class AbstractPadContent : IPadContent
{ {
/// <inheritdoc/>
public abstract object Control { public abstract object Control {
get; get;
} }
/// <inheritdoc/>
public virtual object InitiallyFocusedControl {
get {
return null;
}
}
public virtual void Dispose() public virtual void Dispose()
{ {
} }

2
src/Main/Base/Project/Src/Gui/AbstractViewContent.cs

@ -53,7 +53,7 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
public virtual object InitiallyFocusedControl { public virtual object InitiallyFocusedControl {
get { return this.Control; } get { return null; }
} }
IWorkbenchWindow workbenchWindow; IWorkbenchWindow workbenchWindow;

9
src/Main/Base/Project/Src/Gui/IPadContent.cs

@ -8,7 +8,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace ICSharpCode.SharpDevelop.Gui namespace ICSharpCode.SharpDevelop.Gui
{ {
/// <summary> /// <summary>
/// The IPadContent interface is the basic interface to all "tool" windows /// The IPadContent interface is the basic interface to all "tool" windows
@ -23,5 +23,12 @@ namespace ICSharpCode.SharpDevelop.Gui
object Control { object Control {
get; get;
} }
/// <summary>
/// Gets the control which has focus initially.
/// </summary>
object InitiallyFocusedControl {
get;
}
} }
} }

33
src/Main/Base/Project/Src/Gui/Pads/AbstractConsolePad.cs

@ -71,6 +71,10 @@ namespace ICSharpCode.SharpDevelop.Gui
get { return panel; } get { return panel; }
} }
public override object InitiallyFocusedControl {
get { return console.editor; }
}
string GetText() string GetText()
{ {
return this.TextEditor.Document.Text; return this.TextEditor.Document.Text;
@ -130,6 +134,8 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
return false; return false;
case Key.Down: case Key.Down:
if (console.CommandText.Contains("\n"))
return false;
this.historyPointer = Math.Min(this.historyPointer + 1, this.history.Count); this.historyPointer = Math.Min(this.historyPointer + 1, this.history.Count);
if (this.historyPointer == this.history.Count) if (this.historyPointer == this.history.Count)
console.CommandText = ""; console.CommandText = "";
@ -138,6 +144,8 @@ namespace ICSharpCode.SharpDevelop.Gui
console.editor.ScrollToEnd(); console.editor.ScrollToEnd();
return true; return true;
case Key.Up: case Key.Up:
if (console.CommandText.Contains("\n"))
return false;
this.historyPointer = Math.Max(this.historyPointer - 1, 0); this.historyPointer = Math.Max(this.historyPointer - 1, 0);
if (this.historyPointer == this.history.Count) if (this.historyPointer == this.history.Count)
console.CommandText = ""; console.CommandText = "";
@ -148,19 +156,24 @@ namespace ICSharpCode.SharpDevelop.Gui
case Key.Return: case Key.Return:
if (Keyboard.Modifiers == ModifierKeys.Shift) if (Keyboard.Modifiers == ModifierKeys.Shift)
return false; return false;
int caretOffset = this.console.TextEditor.Caret.Offset;
string commandText = console.CommandText; string commandText = console.CommandText;
this.console.TextEditor.Document.Insert(this.console.TextEditor.Document.TextLength, "\n"); cleared = false;
if (AcceptCommand(commandText)) { if (AcceptCommand(commandText)) {
if (!cleared) if (!cleared) {
console.TextEditor.Document.Insert(console.TextEditor.Document.TextLength, Environment.NewLine);
AppendPrompt(); AppendPrompt();
else console.TextEditor.Select(console.TextEditor.Document.TextLength, 0);
} else {
console.CommandText = ""; console.CommandText = "";
}
cleared = false; cleared = false;
this.history.Add(commandText); this.history.Add(commandText);
this.historyPointer = this.history.Count; this.historyPointer = this.history.Count;
console.editor.ScrollToEnd();
return true;
} }
console.editor.ScrollToEnd(); return false;
return true;
default: default:
return false; return false;
} }
@ -224,11 +237,13 @@ namespace ICSharpCode.SharpDevelop.Gui
console.Append(text); console.Append(text);
} }
protected void InsertLineBeforePrompt(string text) protected void InsertBeforePrompt(string text)
{ {
text += Environment.NewLine; int endOffset = this.console.readOnlyRegion.EndOffset;
this.console.editor.Document.Insert(this.console.readOnlyRegion.EndOffset - Prompt.Length, text); bool needScrollDown = this.console.editor.CaretOffset >= endOffset;
this.console.SetReadonly(this.console.readOnlyRegion.EndOffset + text.Length); this.console.editor.Document.Insert(endOffset - Prompt.Length, text);
this.console.editor.ScrollToEnd();
this.console.SetReadonly(endOffset + text.Length);
} }
protected virtual void Clear() protected virtual void Clear()

6
src/Main/Base/Project/Src/Gui/Pads/FileScout.cs

@ -331,6 +331,12 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
} }
public object InitiallyFocusedControl {
get {
return null;
}
}
Splitter splitter1 = new Splitter(); Splitter splitter1 = new Splitter();
FileList filelister = new FileList(); FileList filelister = new FileList();

12
src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs

@ -46,6 +46,9 @@ namespace ICSharpCode.SharpDevelop.Gui
protected override void FocusContent() protected override void FocusContent()
{ {
IInputElement activeChild = CustomFocusManager.GetFocusedChild(this); IInputElement activeChild = CustomFocusManager.GetFocusedChild(this);
if (activeChild == null && padInstance != null) {
activeChild = padInstance.InitiallyFocusedControl as IInputElement;
}
if (activeChild != null) { if (activeChild != null) {
LoggingService.Debug("Will move focus to: " + activeChild); LoggingService.Debug("Will move focus to: " + activeChild);
Dispatcher.BeginInvoke(DispatcherPriority.Background, Dispatcher.BeginInvoke(DispatcherPriority.Background,
@ -82,8 +85,17 @@ namespace ICSharpCode.SharpDevelop.Gui
placeholder.IsVisibleChanged -= AvalonPadContent_IsVisibleChanged; placeholder.IsVisibleChanged -= AvalonPadContent_IsVisibleChanged;
padInstance = descriptor.PadContent; padInstance = descriptor.PadContent;
if (padInstance != null) { if (padInstance != null) {
bool isFocused = this.IsKeyboardFocused;
this.SetContent(padInstance.Control, padInstance); this.SetContent(padInstance.Control, padInstance);
placeholder = null; placeholder = null;
if (isFocused) {
IInputElement initialFocus = padInstance.InitiallyFocusedControl as IInputElement;
if (initialFocus != null) {
Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(delegate { Keyboard.Focus(initialFocus); }));
}
}
} }
} }
} }

Loading…
Cancel
Save