-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scripting revamp #659
Scripting revamp #659
Conversation
This PR also - from the scripting perspective - removes Omnisharp's dependency on full desktop framework |
I am in favor of this change! Will see if I have time to look at it before summit... if not we'll sit down at summit and talk about it :) |
IOmnisharpEnvironment Env { get; } | ||
ScriptCsContext Context { get; } | ||
ILogger Logger { get; } | ||
private CSharpParseOptions CsxParseOptions { get; } = new CSharpParseOptions(LanguageVersion.CSharp6, DocumentationMode.Parse, SourceCodeKind.Script); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use LanguageVersion.Default
to ensure that the latest version of the language is used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Thanks for making this change @filipw! I definitely agree it's a step in the right direction. |
var localScriptServices = baseBuilder.ScriptName(csxPath).Build(); | ||
var processResult = localScriptServices.FilePreProcessor.ProcessFile(csxPath); | ||
|
||
var fileParser = new FileParser(Context.RootPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just parse the file with Roslyn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be honest I would love to, and I tried but couldn't find the right APIs. In fact - unless I am mistaken - the necessary APIs (this?) are not available publicly. What we need here is to walk the dependency tree of #load
directives and gather all the files and their using statements and so on so that we can construct ProjectInfo
correctly. It seems the only way to publicly get there with Roslyn scripting APIs at the moment is to manually create a script compilation which I wanted to avoid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done syntactically, correct? If so, SyntaxTree.ParseText(...) is what you're looking for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah. The only "hurdle" is if I encounter a #load foo.csx
directive, I need to follow it and pick up the foo.csx
and that one might have it's own #loads
and so on.
Scripting APIs would use this to resolve that whole dependency tree so maybe that would work, to parse the entry file and then follow it's #loads
using ScriptSourceResolver
recursively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but that would be better than manual parsing, definitely
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'm not seeing that as much of a hurdle. You could still have the file parser but use the SyntaxTree to find the using's, #load's, and #r's. You could keep the logic where it continues processing #load's. The real issue is that the simple text "parsing" isn't going to do all that good of a job. For example, it looks like it would return a weird malformed using if it countered a using static.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right I see what you mean now. Of course, let me pluck the naive syntax parsing 👍
great! I also had a chat with Tomas yesterday and he suggested that it might be a better idea to treat all CSX files as single project, rather than each of them as a separate 1-file project (which is how it is implemented at the moment). I will try to incorporate this change too. |
How is this going @filipw? |
It's coming! On Nov 23, 2016 5:58 AM, "Dustin Campbell" [email protected] wrote:
|
022fb27
to
f1e2491
Compare
I've rebased this and introduced better parsing of files (no more naive parser, instead use Tested in the following scenarios:
This is still a simple approach to the problem, but it's definitely an improvement over what's there at the moment. My suggestion would be to go ahead with this merge and I can progressively make this better as we go forward (for example I'd like to include this in the future, though behaviorally things are OK already). Finally, this solution works best on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! I had just a couple of questions.
var scriptCode = File.ReadAllText(fullPath); | ||
|
||
var syntaxTree = CSharpSyntaxTree.ParseText(scriptCode, CSharpParseOptions.Default. | ||
WithPreprocessorSymbols("load", "r"). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this line necessary? This would have the effect of implicitly adding the following code at that top of the tree:
#define load
#define r
Is that what you meant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah my mistake I thought I needed to use this to make the parser be aware of #load
and #r
as valid code. will remove
var loads = syntaxTree.GetCompilationUnitRoot().GetLoadDirectives().Select(x => x.File.ToString()); | ||
foreach (var load in loads) | ||
{ | ||
var filePath = load.Replace("\"", string.Empty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work on OSX/Linux?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this just strips away the quotes, tested on Mac too. when I have i.e. #load "bar.csx"
in my CSX and I use GetXXXDirectives()
method on the compilation root, the result string comes back with quotes inside i.e."bar.csx"
not bar.csx
and I want to strip it away to be able to concat the relative path and traverse these resources
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry. I misread the slash in there. :-) I glanced at it and read the slash, not the double-quote. 😄
LoadedScripts = new HashSet<string>(); | ||
} | ||
|
||
public HashSet<string> Namespaces { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI that read-only auto-props can have initializers. So you could just have this with no constructor:
public HashSet<string> Namespaces { get; } = new HashSet<string>();
public HashSet<string> References { get; } = new HashSet<string>();
public HashSet<string> LoadedScripts { get; } = new HashSet<string>();
Your choice.
|
||
namespace OmniSharp.ScriptCs | ||
namespace OmniSharp.Script | ||
{ | ||
[Export(typeof(IProjectSystem))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add Shared
attribute so that MEF creates this as a singleton.
|
||
var scriptServices = baseScriptServicesBuilder.Build(); | ||
var runtimeContexts = File.Exists(Path.Combine(Env.Path, "project.json")) ? ProjectContext.CreateContextForEachTarget(Env.Path) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand what this is doing, it'll probably need to change in the future for csproj .NET Core. I might not understand though. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes correct I will want to change it in the future. There is no real official project model for scripting so at the moment the idea is that if you have a project.json
it will be used to determine your dependencies and we can load them in for you to provide language services. We will in the future switch to csproj so that you can have <packagereference>
there.
In all other cases, you get a no-frills service with mscorlib
/system.runtime
only and all your needed assemblies must be #r
-ed manually by you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
// if we have no context, then we also have no dependencies | ||
// we can assume desktop framework | ||
// and add mscorlib | ||
if (runtimeContexts == null || !runtimeContexts.Any()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (runtimeContexts?.Any() == false)
|
||
Context.ScriptPacks.UnionWith(scriptPackSession.Contexts.Select(pack => pack.GetType().ToString())); | ||
// inject all inherited assemblies | ||
//#if NET46 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be deleted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops
e8e99d2
to
11f9e10
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great with your latest changes.
@DustinCampbell everything should be OK now, all the review feedback applied - thanks! |
Merging! 😄 |
yay - thanks 😄 |
Sounds great ! what should I put in project.json to get started with something simple like the project in your gif ? |
If you use CSI to execute your scripts, the If you use a .NET Core script runner (CSI is not .NET Core compatible at the moment) like https://github.com/filipw/dotnet-script, then you can put any package references you need into the |
Thanks a lot filipw, I got some of the frustation out with dotnet-script running .NET Core
So the 'regular CSI experience' is running on regular .net46 ? |
If I'm understanding you correctly, the platforms that the debugger in VS Code supports (which is just CoreCLR) is completely orthogonal to what environment your scripts run in. |
no, at the moment that runner only exists to run .NET Core scripts.
correct, CSI is for running scripts as net46 only. It runs on mono (with some hiccups) too.
yep, as Dustin said, the F5 debugging in VS Code only works with CoreCLR, so you can use it to work with scripts running with dotnet-script, but not running with CSI. |
Got it now, Thanks guys. This attempt to normalize the C# scripting support in Omnisharp is much welcomed. |
This PR is an attempt to revamp/normalize the C# scripting support in Omnisharp.
Here is what is done:
ScriptCsProjectContext
toScriptProjectContext
etc etcInteractiveScriptGlobals
- same as used bycsi.exe
. This gives us same set of global properties as there, i.e.Args
.scripting is (for now) supported only as .NET Core scriptingupdate: you can specifynet46
target inproject.json
or use noproject.json
at all to force "net46
scripting mode". If yourproject.json
contains a target fornetcoreapp1.0
, then .NET Core language services will be usedpackages.config
, instead they are pulled fromproject.json
System
namespace,mscorlib
andSystem.Runtime
(if needed).CS8099
&CS1701
This PR is in line with my proposal here dotnet/vscode-csharp#23 (comment)
This is a breaking change of course for scripting story in Omnisharp, but I believe it was never really officially supported but more of an experimental stuff. I believe trying to normalize to "pure" Roslyn scripting is a step in a right direction here, especially as we can easily align with runners like
csi.exe
then or dotnet-script