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

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

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

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

@ -5,54 +5,37 @@ @@ -5,54 +5,37 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
namespace FSharpBinding
{
public class FSharpInteractive : AbstractPadContent
public class FSharpInteractive : AbstractConsolePad
{
Queue<string> outputQueue = new Queue<string>();
internal readonly Process fsiProcess = new Process();
Panel panel = new Panel();
TextBox input, output;
internal readonly bool foundCompiler;
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")) {
string path = Path.Combine(ConfigurationManager.AppSettings["alt_fs_bin_path"], "fsi.exe");
if (File.Exists(path)) {
fsiProcess.StartInfo.FileName = path;
foundCompiler = true;
} 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;
}
} else {
@ -68,37 +51,26 @@ namespace FSharpBinding @@ -68,37 +51,26 @@ namespace FSharpBinding
foundCompiler = true;
} else {
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
var possibleFiles = from fsdir in Directory.GetDirectories(programFiles, "FSharp*")
//LoggingService.Debug("Trying to find fsi in '" + fsdir + "'");
let fileInfo = new FileInfo(Path.Combine(fsdir, "bin\\fsi.exe"))
where fileInfo.Exists
orderby fileInfo.CreationTime
select fileInfo;
FileInfo file = possibleFiles.FirstOrDefault();
if (file != null) {
fsiProcess.StartInfo.FileName = file.FullName;
path = Path.Combine(programFiles, @"Microsoft F#\v4.0\Fsi.exe");
if (File.Exists(path)) {
fsiProcess.StartInfo.FileName = path;
foundCompiler = true;
} else {
output.Text = "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";
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");
foundCompiler = false;
}
}
}
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.UseShellExecute = false;
fsiProcess.StartInfo.CreateNoWindow = true;
fsiProcess.StartInfo.RedirectStandardError = true;
fsiProcess.StartInfo.RedirectStandardInput = true;
fsiProcess.StartInfo.RedirectStandardOutput = true;
fsiProcess.EnableRaisingEvents = true;
fsiProcess.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) {
lock (outputQueue) {
outputQueue.Enqueue(e.Data);
@ -117,31 +89,52 @@ namespace FSharpBinding @@ -117,31 +89,52 @@ namespace FSharpBinding
outputQueue.Enqueue("restarting ...");
}
WorkbenchSingleton.SafeThreadAsyncCall(ReadAll);
fsiProcess.Start();
};
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 = "";
}
WorkbenchSingleton.SafeThreadAsyncCall(StartFSharp);
};
StartFSharp();
}
}
void StartFSharp()
{
fsiProcess.Start();
fsiProcess.BeginErrorReadLine();
fsiProcess.BeginOutputReadLine();
}
int expectedPrompts;
void ReadAll()
{
StringBuilder b = new StringBuilder();
lock (outputQueue) {
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 {
get { return panel; }
protected override string Prompt {
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 @@ @@ -7,6 +7,7 @@
Name="lastProjectsListView"
SelectionMode="Single"
core:SortableGridViewColumn.SortMode="Automatic"
Margin="0,0,0,20"
MouseDoubleClick="lastProjectsDoubleClick"
KeyDown="lastProjectsKeyDown">
<ListView.Resources>
@ -38,8 +39,7 @@ @@ -38,8 +39,7 @@
</ListView.View>
</ListView>
<StackPanel
Orientation="Horizontal"
Margin="0,20,0,0">
Orientation="Horizontal">
<Button
Content="{core:Localize StartPage.StartMenu.OpenCombineButton}"
Click="openSolutionClick" />

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

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

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

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

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

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

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

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

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

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

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

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

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

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