Пример #1
0
    bool Initialize()
    {
        if (DocumentId == null)
        {
            var dte            = Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
            var activeDocument = dte?.ActiveDocument; // sometimes we're constructed/invoked before ActiveDocument has been set
            if (activeDocument != null)
            {
                DocumentId = Workspace.CurrentSolution.GetDocumentIdsWithFilePath(activeDocument.FullName).FirstOrDefault();
            }
            if (DocumentId == null)
            {
                return(false);
            }
        }

        var document = Workspace.CurrentSolution.GetDocument(DocumentId);
        var project  = document?.Project;

        if (project == null)
        {
            return(false);
        }

        if (ReplayHost == null)
        {
            lock (ReplayHosts)
            {
                Tuple <ReplayHost, int> t;
                if (ReplayHosts.TryGetValue(project.OutputFilePath, out t))
                {
                    t = Tuple.Create(t.Item1, t.Item2 + 1);
                }
                else
                {
                    t = Tuple.Create(new ReplayHost(false), 1);
                }
                ReplayHosts[project.OutputFilePath] = t;
                ReplayHost = t.Item1;
            }
            ReplayHost.AdornmentChanged += ReplayHostAdornmentChanged;
            ReplayHost.Erred            += ReplayHostErred;
            var dummy = ReplayHost.ChangeDocumentAsync(Project, null, -1, -1, -1);
        }

        return(true);
    }
Пример #2
0
 async void OnTextBufferChanged(object sender, TextContentChangedEventArgs e)
 {
     if (!Initialize())
     {
         return;
     }
     foreach (var change in e.Changes)
     {
         var start    = e.Before.GetLineNumberFromPosition(change.OldPosition);
         var count    = e.Before.GetLineNumberFromPosition(change.OldPosition + change.OldLength) - start;
         var start2   = e.After.GetLineNumberFromPosition(change.NewPosition);
         var newcount = e.After.GetLineNumberFromPosition(change.NewPosition + change.NewLength) - start2;
         if (start != start2)
         {
             Debug.WriteLine("oops!");
         }
         await ReplayHost.ChangeDocumentAsync(Project, Document.FilePath, start, count, newcount);
     }
 }
Пример #3
0
    static async Task TestHostAsync(string projectName)
    {
        Project project;

        if (projectName == "ConsoleApp1")
        {
            var workspace = new Microsoft.DotNet.ProjectModel.Workspaces.ProjectJsonWorkspace(SampleProjectsDirectory + "/ConsoleApp1");
            var solution  = workspace.CurrentSolution;
            project = solution.Projects.Single();
            var txt      = "int x = 15;\r\nint y = x+2;\r\nSystem.Console.WriteLine(y);\r\n";
            var document = project.AddDocument("a.csx", txt, null, "c:\\a.csx").WithSourceCodeKind(SourceCodeKind.Script);
            project = document.Project;
        }
        else if (projectName == "Methods")
        {
            project = await ScriptWorkspace.FromDirectoryScanAsync(SampleProjectsDirectory + "/Methods");
        }
        else
        {
            throw new ArgumentException("Projects 'ConsoleApp1' and 'Methods' both work", nameof(projectName));
        }


        var host = new ReplayHost(false);

        host.DiagnosticChanged += (isAdd, tag, diagnostic, deferrable, cancel) =>
        {
            if (isAdd)
            {
                Console.WriteLine($"+D{tag}: {diagnostic.GetMessage()}");
            }
            else
            {
                Console.WriteLine($"-D{tag}");
            }
        };
        host.AdornmentChanged += (isAdd, tag, file, line, content, deferrable, cancel) =>
        {
            if (isAdd)
            {
                Console.WriteLine($"+A{tag}: {Path.GetFileName(file)}({line}) {content}");
            }
            else
            {
                Console.WriteLine($"-A{tag}");
            }
        };
        host.Erred += (error, deferrable, cancel) =>
        {
            Console.WriteLine(error);
        };

        Console.WriteLine("PROJECT");
        await host.ChangeDocumentAsync(project, null, 0, 0, 0);

        Console.WriteLine("VIEW");
        await host.WatchAsync();

        if (projectName == "ConsoleApp1")
        {
            Console.WriteLine("CHANGE");
            var txt      = "int x = 15;\r\nint y = x+2;d\r\nSystem.Console.WriteLine(y);\r\n";
            var document = project.Documents.First(d => d.Name == "a.csx");
            document = document.WithText(SourceText.From(txt));
            project  = document.Project;
            await host.ChangeDocumentAsync(project, "a.csx", 1, 1, 1);
        }
        else if (projectName == "Methods")
        {
            Console.WriteLine("CHANGE MARKDOWN");
            var document = project.Documents.First(d => d.Name == "methods.md");
            var src      = document.GetTextAsync().Result;
            var txt      = src.ToString();
            int i        = src.Lines.FindIndex(line => txt.Substring(line.Span.Start, line.Span.Length) == "Introductory prose");
            txt      = txt.Replace("Introductory prose", "Some\nintroduction.");
            document = document.WithText(SourceText.From(txt));
            project  = document.Project;
            //
            document = project.Documents.First(d => d.Name == "methods.md.csx");
            txt      = ScriptWorkspace.Md2Csx("methods.md", txt);
            document = document.WithText(SourceText.From(txt));
            project  = document.Project;
            await host.ChangeDocumentAsync(project, "methods.md", i, 1, 2);

            Console.WriteLine("VIEW");
            await host.WatchAsync();

            Console.WriteLine("CHANGE CODE");
            document = project.Documents.First(d => d.Name == "methods.md");
            src      = document.GetTextAsync().Result;
            txt      = src.ToString();
            i        = src.Lines.FindIndex(line => txt.Substring(line.Span.Start, line.Span.Length) == "var txt = GetText();");
            txt      = txt.Replace("var txt = GetText();", "var txt = GetText();\n");
            document = document.WithText(SourceText.From(txt));
            project  = document.Project;
            //
            document = project.Documents.First(d => d.Name == "methods.md.csx");
            src      = document.GetTextAsync().Result;
            txt      = src.ToString();
            txt      = txt.Replace("var txt = GetText();", "var txt = GetText();\n");
            document = document.WithText(SourceText.From(txt));
            project  = document.Project;
            //
            await host.ChangeDocumentAsync(project, "methods.md", i, 1, 2);
        }


        Console.WriteLine("DONE");
    }
Пример #4
0
    public static async Task DoSocketAsync(HttpContext http, WebSocket socket)
    {
        Exception _ex = null;

        try
        {
            if (!http.Request.Path.HasValue)
            {
                await socket.SendStringAsync("ERROR\tNo project specified"); return;
            }

            var dir = Directory.GetCurrentDirectory();
            for (; dir != null; dir = Path.GetDirectoryName(dir))
            {
                if (Directory.Exists(dir + "/SampleProjects"))
                {
                    break;
                }
            }
            dir = Path.GetFullPath(dir + "/SampleProjects" + http.Request.Path.Value);
            if (!Directory.Exists(dir))
            {
                await socket.SendStringAsync($"ERROR\tProject doesn't exist '{dir}'"); return;
            }

            // Load the project, and establish the "OK" handshake to show we've done it
            var project = await ScriptWorkspace.FromDirectoryScanAsync(dir);

            await socket.SendStringAsync("OK");

            var cmd = await socket.RecvStringAsync();

            if (cmd != "OK")
            {
                await socket.SendStringAsync($"ERROR\tExpected 'OK' not '{cmd}'"); return;
            }

            // Set up monitoring for diagnostics
            var host = new ReplayHost(true);
            ReplayHost.AdornmentChangedHandler lambdaAdornmentChanged = async(isAdd, tag, file, line, content, deferrable, cancel) =>
            {
                // ADORNMENT remove 7
                // ADORNMENT ADD 7 231 Hello world
                var deferral = deferrable.GetDeferral();
                var msg      = isAdd ? $"ADORNMENT\tadd\t{tag}\t{file}\t{line+1}\t{content}" : $"ADORNMENT\tremove\t{tag}\t{file}";
                if (socket.State != WebSocketState.Closed)
                {
                    await socket.SendStringAsync(msg);
                }
                deferral.Complete();
            };
            ReplayHost.DiagnosticChangedHandler lambdaDiagnosticChanged = async(isAdd, tag, diagnostic, deferrable, cancel) =>
            {
                // DIAGNOSTIC remove 7 file.cs
                // DIAGNOSTIC add 7 file.cs Hidden startLine startCol length msg
                var    deferral = deferrable.GetDeferral();
                string msg;
                if (isAdd)
                {
                    var file = ""; int startLine = -1, startCol = -1, length = 0;
                    if (diagnostic.Location.IsInSource)
                    {
                        var loc = diagnostic.Location.GetMappedLineSpan();
                        file      = loc.HasMappedPath ? loc.Path : diagnostic.Location.SourceTree.FilePath;
                        startLine = loc.StartLinePosition.Line + 1;
                        startCol  = loc.StartLinePosition.Character + 1;
                        length    = diagnostic.Location.SourceSpan.Length;
                    }
                    msg = $"DIAGNOSTIC\tadd\t{tag}\t{file}\t{diagnostic.Severity}\t{startLine}\t{startCol}\t{length}\t{diagnostic.Id}: {diagnostic.GetMessage()}";
                }
                else
                {
                    msg = $"DIAGNOSTIC\tremove\t{tag}";
                }
                if (socket.State != WebSocketState.Closed)
                {
                    await socket.SendStringAsync(msg);
                }
                deferral.Complete();
            };
            ReplayHost.ReplayHostError lambdaErred = async(error, deferrable, cancel) =>
            {
                var deferral = deferrable.GetDeferral();
                if (socket.State != WebSocketState.Closed)
                {
                    await socket.SendStringAsync($"ERROR\tCLIENT: {error}");
                }
                deferral.Complete();
            };

            host.AdornmentChanged  += lambdaAdornmentChanged;
            host.DiagnosticChanged += lambdaDiagnosticChanged;
            host.Erred             += lambdaErred;

            var dummy = host.ChangeDocumentAsync(project, null, -1, -1, -1);

            // Run the conversation!
            while (true)
            {
                cmd = await socket.RecvStringAsync();

                if (cmd == null)
                {
                    host.AdornmentChanged -= lambdaAdornmentChanged; host.DiagnosticChanged -= lambdaDiagnosticChanged; host.Erred -= lambdaErred; return;
                }
                var cmds = cmd.Split(new[] { '\t' });

                if (cmds[0] == "GET")
                {
                    if (cmds.Length != 2)
                    {
                        await socket.SendStringAsync($"ERROR\tExpected 'GET fn', not '{cmd}'"); return;
                    }
                    var document = project.Documents.SingleOrDefault(d => d.Name == cmds[1]);
                    if (document == null)
                    {
                        await socket.SendStringAsync($"ERROR\tFile doesn't exist '{cmds[1]}'"); return;
                    }
                    var s = (await document.GetTextAsync()).ToString().Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n");
                    await socket.SendStringAsync($"GOT\t{cmds[1]}\t{s}");
                }

                else if (cmds[0] == "CHANGE")
                {
                    string file, newContent; int startLine, startCol, oldLineCount, newLineCount, oldLength; Document document;
                    if (cmds.Length != 8 ||
                        (file = cmds[1]) == null ||
                        (document = project.Documents.SingleOrDefault(d => d.Name == file)) == null ||
                        !int.TryParse(cmds[2], out startLine) ||
                        !int.TryParse(cmds[3], out startCol) ||
                        !int.TryParse(cmds[4], out oldLineCount) ||
                        !int.TryParse(cmds[5], out newLineCount) ||
                        !int.TryParse(cmds[6], out oldLength) ||
                        (newContent = cmds[7].Replace("\\n", "\n").Replace("\\r", "\r").Replace("\\\\", "\\")) == null)
                    {
                        await socket.SendStringAsync($"ERROR\tExpected 'CHANGE file startLine startCol oldLineCount newLineCount oldLength newContent', not '{cmd}'");

                        continue;
                    }
                    //
                    var txt = await document.GetTextAsync();

                    var startPosition = txt.Lines[startLine - 1].Start + startCol - 1;
                    var change        = new TextChange(new TextSpan(startPosition, oldLength), newContent);
                    txt      = txt.WithChanges(change);
                    document = document.WithText(txt);
                    project  = document.Project;
                    if (file.EndsWith(".md"))
                    {
                        var csx         = ScriptWorkspace.Md2Csx(file, txt.ToString());
                        var csxDocument = project.Documents.Single(d => d.Name == file + ".csx");
                        csxDocument = csxDocument.WithText(SourceText.From(csx));
                        project     = csxDocument.Project;
                    }
                    //
                    dummy = host.ChangeDocumentAsync(project, document.FilePath, startLine - 1, oldLineCount, newLineCount);
                }

                else if (cmds[0] == "WATCH")
                {
                    string file; int line = -1, count = -1; Document document = null;
                    if ((cmds.Length != 4 && cmds.Length != 2) ||
                        (file = cmds[1]) == null ||
                        (file != "*" && (document = project.Documents.Single(d => d.Name == file)) == null) ||
                        (cmds.Length == 4 && !int.TryParse(cmds[2], out line)) ||
                        (cmds.Length == 4 && !int.TryParse(cmds[3], out count)))
                    {
                        await socket.SendStringAsync($"ERROR\tExpected 'WATCH file line count', got '{cmd}'");

                        continue;
                    }
                    //
                    dummy = host.WatchAsync(file == "*" ? file : document.FilePath, line, count);
                }

                else
                {
                    await socket.SendStringAsync($"ERROR\tServer doesn't recognize command '{cmd}'");
                }
            }
        }
        catch (Exception ex)
        {
            _ex = ex;
        }
        if (_ex != null)
        {
            await socket.SendStringAsync($"ERROR\t{_ex.Message} - {_ex.StackTrace.Replace("\r\n"," || ").Replace("\r"," || ").Replace("\n"," || ")}");
        }
    }