Home

LINQPad Plugins?

Ever considered allowing developers to extend LINQPad via Plugins?

Comments

  • What sort of things would you want to extend?
  • Right click to push to the git repository

    Right-click to pack

  • Right-click to create gist

  • Yes, I like this function, how about like this, LINQPad allow user create a special .linq file called Plugins.linq, which can write:

    IEnumerable<(string, Action)> GetContextMenuButtons()
    {
        yield return ("Upload to My Github", () => 
        {
            Util.Cmd("git commit -m update....");
            MessageBox.Show(Util.Cmd("git push"));
        };
    }
    
  • There is a dark feature in LINQPad that you might like to try. Create and save a query to My Queries called Automator.linq, with the following code:

    void Main (System.Windows.Forms.Keys key, string queryPath)
    {
       MessageBox.Show (key + " " + queryPath);
    }
    

    This will activate when you press Alt+Ctrl+Shift with a function key.

  • I like this feature.

    My first attempt is to run git diff on the current file. It works but I have git configured to run beyond compare as my difftool , so I don't know if this works as standard.

    void Main (Keys key, string queryPath)
    {
        if (key == (Keys.F2 |  Keys.Control | Keys.Alt | Keys.Shift))
        {
            var path = System.IO.Path.GetDirectoryName(queryPath);  
            Util.Cmd($"cd \"{path}\" & git difftool -y \"{queryPath}\"") ;
       }
    }
    
  • Hi @sgmoore , here is my proposal:

    void Main(System.Windows.Forms.Keys key, string queryPath)
    {
        string lpQueryPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\LINQPad Queries";
    
        if (key == (Keys.F1 | Keys.Control | Keys.Alt | Keys.Shift))
        {
            Run("git", "status", lpQueryPath);
        }
        else if (key == (Keys.F2 | Keys.Control | Keys.Alt | Keys.Shift))
        {
            Run("git", "add .", lpQueryPath);
        }
        else if (key == (Keys.F3 | Keys.Control | Keys.Alt | Keys.Shift))
        {
            Run("git", "commit -m \"updated by Automator\"", lpQueryPath);
        }
        else if (key == (Keys.F4 | Keys.Control | Keys.Alt | Keys.Shift))
        {
            Run("git", "push", lpQueryPath);
        }
    }
    
    void Run(string cmd, string args, string workingDir)
    {
        using var ps = new Process
        {
            StartInfo = new ProcessStartInfo(cmd, args)
            {
                WorkingDirectory = workingDir,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true, 
            },
        };
    
        StringBuilder output = new();
        StringBuilder error = new();
        ps.OutputDataReceived += (sender, args) =>
        {
            if (args.Data != null)
            {
                output.AppendLine(args.Data);
            }
        };
        ps.ErrorDataReceived += (sender, args) =>
        {
            if (args.Data != null)
            {
                error.AppendLine(args.Data);
            }
        };
        ps.Start();
        ps.BeginErrorReadLine();
        ps.BeginOutputReadLine();
    
        ps.WaitForExit();
    
        if (error.Length > 0)
        {
            MessageBox.Show(error.ToString(), cmd + " " + args, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    
        if (output.Length > 0)
        {
            MessageBox.Show(output.ToString(), cmd + " " + args, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
    
  • Hi @sdflysha.

    Thanks. You've got further than me. I tried your plugins, but to honest there are a few things I am not happy with.
    I don't like the way windows displays message boxes (ie does not support scroll bars and it can have ugly and unnecessary wrapping.)

    Also don't like the idea of having the same commit message for every commit.

    So I think I will try a simple Automator which just opens and runs another query, eg

    void Main(Keys key, string queryPath)
    {
        Util.OpenQuery("Automator2.linq", run:true, hideEditor:false , key , queryPath);
    }
    

    and move all the logic into Automator2.linq

    The disadvantage is that this switches to another query, but the big advantage is that I can use the full LinqPad experience including Util.ReadLine to prompt for a commit message and I don't need to worry about the output being too long to display on my screen.

  • What about being able to access the UI itself ? eg. add custom menus (either context or menubar), add additional tabs with custom content to the my queries tabcontrol ?
    I'm working on a project where I want LP to be the client UI, but I need to extend the UI to have some custom displays and behaviours over the default.
    Whilst I can get the Ctrl+Shift+Alt feature to work, a UI plugin system would be super neat. The old windows Fiddler had a winforms mechanism that allowed for UI customisation. Given LP is essentially WinForms it is a possibility to provide some hooks ? (even beta unofficial ones ;)

  • I know you called this a dark feature (which I presume means unsupported), but has it been dropped from LP8?

    It works in LP7 but not in LP8 and the location of the queries folder (and hence the location of Automator.linq) is the same with both versions.

    It may be a coincidence, but there are also a few entries in the log file which appear to be from the times I tried this.

    8.0.0 (X64) 2023-10-20T10:28:44.0141951+01:00 UnobservedTaskException
    AggregateException - A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. (Object reference not set to an instance of an object.)
    
    (no stack trace)
    
       INNER: NullReferenceException - Object reference not set to an instance of an object.
       Source=LINQPad.Runtime
    
        -LINQPad.ExecutionModel.FastChannel Void SendReply(Int32, System.Object, System.Exception, Boolean) offset: 0x4B
        -LINQPad.ExecutionModel.FastChannel+<>c__DisplayClass37_0 Void <ReceiveMethodCall>b__0() offset: 0xC4
        -System.Threading.ExecutionContext Void RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) offset: 0x4C
        -System.Runtime.ExceptionServices.ExceptionDispatchInfo Void Throw() offset: 0x11
        -System.Threading.ExecutionContext Void RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) offset: 0x4C
        -System.Threading.Tasks.Task Void ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) offset: 0x12E
    
    
  • It should still work. What's in your automation script?

  • Currently for debugging automation.linq is

    void Main(System.Windows.Forms.Keys key, string queryPath)
    {
        System.Windows.Forms.MessageBox.Show("A");
        Util.OpenQuery("Automator2.linq", run:true, hideEditor:false , key , queryPath);
        System.Windows.Forms.MessageBox.Show("C");
    }
    

    where Automator2.linq is currently

    void Main(Keys key, string queryPath)
    {
        System.Windows.Forms.MessageBox.Show("B");
    }
    

    This displays A and C but not B. so it looks like the problem is with Util.OpenQuery.

  • Thanks - this is related to the changes in the serialization engine. Will get a fix out soon.

  • Looks like this is fixed now, so thank you.

Sign In or Register to comment.