Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3010 from VsVim/dev/nosami/csharp-scripting
Adds C# scripting capability to VSMac
- Loading branch information
Showing
7 changed files
with
171 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
using Vim.Interpreter; | ||
|
||
namespace Vim.VisualStudio.Implementation.CSharpScript | ||
{ | ||
using Microsoft.CodeAnalysis.CSharp.Scripting; | ||
using Microsoft.CodeAnalysis.Scripting; | ||
using CSharpScript = Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript; | ||
|
||
[Export(typeof(ICSharpScriptExecutor))] | ||
internal sealed partial class CSharpScriptExecutor : ICSharpScriptExecutor | ||
{ | ||
private const string ScriptFolder = "vsvimscripts"; | ||
private Dictionary<string, Script<object>> _scripts = new Dictionary<string, Script<object>>(StringComparer.OrdinalIgnoreCase); | ||
private ScriptOptions _scriptOptions = null; | ||
|
||
[ImportingConstructor] | ||
public CSharpScriptExecutor() | ||
{ | ||
|
||
} | ||
|
||
private async Task ExecuteAsync(IVimBuffer vimBuffer, CallInfo callInfo, bool createEachTime) | ||
{ | ||
try | ||
{ | ||
Script<object> script; | ||
if (!TryGetScript(vimBuffer, callInfo.Name, createEachTime, out script)) | ||
return; | ||
|
||
var globals = new CSharpScriptGlobals(callInfo, vimBuffer); | ||
var scriptState = await script.RunAsync(globals); | ||
} | ||
catch (CompilationErrorException ex) | ||
{ | ||
if (_scripts.ContainsKey(callInfo.Name)) | ||
_scripts.Remove(callInfo.Name); | ||
|
||
vimBuffer.VimBufferData.StatusUtil.OnError(string.Join(Environment.NewLine, ex.Diagnostics)); | ||
} | ||
catch (Exception ex) | ||
{ | ||
vimBuffer.VimBufferData.StatusUtil.OnError(ex.Message); | ||
} | ||
} | ||
|
||
private static ScriptOptions GetScriptOptions(string scriptPath) | ||
{ | ||
var ssr = ScriptSourceResolver.Default.WithBaseDirectory(scriptPath); | ||
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; | ||
|
||
var searchPaths = new string[] | ||
{ | ||
baseDirectory, | ||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) | ||
}; | ||
|
||
var smr = ScriptMetadataResolver.Default | ||
.WithBaseDirectory(scriptPath) | ||
.WithSearchPaths(searchPaths); | ||
|
||
var asm = new Assembly[] | ||
{ | ||
typeof(MonoDevelop.Core.Runtime).Assembly, | ||
typeof(Vim.IVim).Assembly, // VimCore.dll | ||
typeof(Vim.Mac.VimCocoaHost).Assembly // Vim.VisualStudio.Shared.dll | ||
}; | ||
|
||
var so = ScriptOptions.Default | ||
.WithSourceResolver(ssr) | ||
.WithMetadataResolver(smr) | ||
.WithReferences(asm); | ||
|
||
return so; | ||
} | ||
|
||
private bool TryGetScript(IVimBuffer vimBuffer, string scriptName, bool createEachTime, out Script<object> script) | ||
{ | ||
if (!createEachTime && _scripts.TryGetValue(scriptName, out script)) | ||
return true; | ||
|
||
string scriptPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | ||
scriptPath = Path.Combine(scriptPath, ScriptFolder); | ||
|
||
string scriptFilePath = Path.Combine(scriptPath, $"{scriptName}.csx"); | ||
|
||
if (!File.Exists(scriptFilePath)) | ||
{ | ||
vimBuffer.VimBufferData.StatusUtil.OnError("script file not found."); | ||
script = null; | ||
return false; | ||
} | ||
|
||
if (_scriptOptions == null) | ||
_scriptOptions = GetScriptOptions(scriptPath); | ||
|
||
script = CSharpScript.Create(File.ReadAllText(scriptFilePath), _scriptOptions, typeof(CSharpScriptGlobals)); | ||
_scripts[scriptName] = script; | ||
return true; | ||
} | ||
|
||
#region ICSharpScriptExecutor | ||
|
||
void ICSharpScriptExecutor.Execute(IVimBuffer vimBuffer, CallInfo callInfo, bool createEachTime) | ||
{ | ||
var task = ExecuteAsync(vimBuffer, callInfo, createEachTime); | ||
VimTrace.TraceInfo("CSharptScript:Execute {0}", callInfo.Name); | ||
} | ||
|
||
#endregion | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using Vim.Interpreter; | ||
|
||
namespace Vim.VisualStudio.Implementation.CSharpScript | ||
{ | ||
public class CSharpScriptGlobals | ||
{ | ||
public string Name { get; } = string.Empty; | ||
public string Arguments { get; } = string.Empty; | ||
public LineRangeSpecifier LineRange { get; } | ||
public bool IsScriptLocal { get; } = false; | ||
public IVim Vim { get; } = null; | ||
public IVimBuffer VimBuffer { get; } = null; | ||
|
||
public CSharpScriptGlobals(CallInfo callInfo, IVimBuffer vimBuffer) | ||
{ | ||
Name = callInfo.Name; | ||
Arguments = callInfo.Arguments; | ||
LineRange = callInfo.LineRange; | ||
IsScriptLocal = callInfo.IsScriptLocal; | ||
Vim = vimBuffer.Vim; | ||
VimBuffer = vimBuffer; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using Vim.Interpreter; | ||
|
||
namespace Vim.VisualStudio | ||
{ | ||
public interface ICSharpScriptExecutor | ||
{ | ||
void Execute(IVimBuffer vimBuffer, CallInfo callInfo, bool createEachTime); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters