REPLParser Multiline Support

@bdw429s Wondering if you happen to remember why this is commented out. It looks like it was from 2014 so totally understand if not.

I was curious about possibly adding support for things like this in the REPL and noticed it so thought I would ask.

mvar = "
    select *
    from mytable
";

And possibly adding support for this.

myarray = [
    ....
];

I can possibly submit a PR for it unless you see a reason not to. Thanks!

@jason_steinshouer that logic was actually all provided by @gcopley , I’d check with him. That feature allows you to hit enter but the enter is ignored if the statement doesn’t seem complete. You can also just type a line break, but the shortcut keys to do that differs pet terminal app.

@jason_steinshouer I don’t remember why I commented it out. My contributions to the REPL early on were tinkering at best, so if you need to put those lines back and it works I say go for it :slight_smile:

I will add that in the early days, if the REPL didn’t think you were “done”, you could get “stuck” where it wouldn’t ever let you run your code. A long time ago, I added in a check where if you just hit “enter” twice, it would just run whatever you had entered. I have a feeling those lines of code were commented out perhaps back when you could get “stuck” in the REPL. You could try uncommenting them locally to see what happens now.

And just to reiterate my suggestion above so it doesn’t get lost-- most terminal apps have a keyboard shortcut to an actual line break. For example, in my Windows 10 CMD terminal, I can press Ctrl-v followed by Ctrl-j to type a line break that doesn’t actually “enter” the line. Or in my ConEMU terminal app, it’s Ctrl+Shift+v followed by Ctrl+J. Here’s an example I run ran in the REPL using this trick:

CFSCRIPT-REPL: [1,2,3].each( (i)=>{
> echo( i )
> })
123

And for comparison, here is the same example where I just hit Enter and the REPL is smart enough in this case to wait

CFSCRIPT-REPL: [1,2,3].each( (i)=>{
.............: echo(i)
.............: })
123

The main difference, and what makes the first option much more desirable is

  • the first option lets me use the “up” and “down” keys to move freely between the lines to continue editing them until I decide to hit “enter” and send the entire string
  • The first option remembers the entire multi-line string as a single item in the history so I can hit “up” arrow in the REPL and recall the entire thing at once, whereas the other trick stores separate entries in the REPL history.

And, just to clarify, you can enter a line break that doesn’t actually submit the line anywhere in the CommandBox shell, not just the REPL. The REPL is simply the place where it seems to have the most utility. BTW, this is covered in the docs here

Thanks for the input! I created a PR to for double quotes and brackets if you are interested. If not, I can just close it. I tried single quotes but experieced some strange behavior like Brad described with the REPL not responding.

For added context I am interacting with the REPL via a Jupyter notebook. Currently I am passing the code into the REPL one line at a time. I have tried passing the entire code into it at once but is still seems to be processed a line at a time so will need to play around with it some more and see if I can figure that out. Thanks for your help.

If it works, I’m intersted. The real problem is, while you can “guess” how many quote there are, it’s very easy to break the logic without actual real proper char-by-char parsing of the string. Regex simply won’t do

myVar = "test" & 'brad " wood'

:point_up: This is a syntactically complete CFML expression, but a simple count of the quotes will thing there is an unmatched double quote.

It’s not that it’s “not responding” per se- it just doesn’t think the expression is done. You just need to press “enter” again and it will force the REPL to run the expression. Now, I understand that may or may not be easy to do with your programmatic interaction with the REPL.

Hmm, yes. Let me take a look at this-- there’s a good chance that’s exactly how the REPL works and perhaps I can help improve on it :thinking:

Ok, so I just tried a quick test. I created the following file test.txt which contains these lines

loop times=2 {
    echo( 'foo' )
}

Then I piped those lines into the REPL like so:

cat test.txt | repl

and the output was correct

foofoo

Let me know if you can reproduce that behavior and how it differs from what your Jypiter stuff is doing.

@bdw429s Thanks Brad. Sorry for not catching that. I added a commit to parse it a character at a time. It seems to work with all the scenerios I tested with. Let me know what you think.