LIPS-scheme / lips

Scheme based powerful lisp interpreter in JavaScript
https://lips.js.org
Other
411 stars 33 forks source link

Usage of `lips.Formatter` #370

Open dragoncoder047 opened 1 month ago

dragoncoder047 commented 1 month ago

I am trying to build a block-based Scheme editor -- sort of like Edublocks but for Scheme instead of Python.

I'm able to turn each parentheses-enclosed form (i.e. the Pair objects returned by lips.parse) into an element, but as for deciding where to insert line breaks and make the elements flow downwards instead of to the right, it looks like the Formatter should be about to do that, but I can't figure out how to do that -- seeing that the Formatter isn't documented well (if at all).

jcubic commented 1 month ago

You can see the usage of it in the lib/js/terminal.js file:

var formatter = new lips.Formatter(code);
if (!code.match(/\n/)) {
    formatter.break();
}
output = formatter.format({
    offset: prompt.length
});

break()will insert newlines and format() add indentation, offset is only used for first line in the REPL (where prompt is).

Note that it's not 100% working, that's why I didn't add a Scheme formatting tool that is available online. One known issue is that it doesn't add an extra newline between top level S-expressions.

If you find some bugs in indentation or line breaking, you can report them.

I will keep the issue open to add docs.

dragoncoder047 commented 1 month ago

No, I was asking about determining where to insert line breaks when you have a lips.Pair (which is the code), and you don't want to stringify the code

Anyway, I have to parse the code with lips.parse and then walk the tree to convert it into DOM elements, and even if I did run the code through the Formatter before parsing it, the parser obliterates the positions of the line breaks (or does it?)

jcubic commented 1 month ago

If you have lips.Pair objects, the information about indentation is long gone. But I was thinking to somehow expose that information so you can have better error messages.

the meta tags are returned by the lips.tokenize(code, true). This is what lips.Formatter is using.

Formatter only work on strings, if you have code you can only evaluate it or stringify the code and then reformat.

Can I ask why you exactly need lips.Pair in code editor?

dragoncoder047 commented 1 month ago

maybe a screenshot of what I have so far would help.

This code:

(define hello (lambda (x . args) (apply format #t x args))) (begin (display (foo "hello\n")) (newline))

is processed into this: image

Each of the elements has a reference to the LIPS object that it is contained by, so when I add the ability to edit the code in-place (i.e. dragging around each of the forms) it will update the actual syntax tree without having to re-parse it every time.

But I was thinking to somehow expose that information so you can have better error messages.

Definitely do! Once that is implemented, my problem has a simple solution: format the code, then parse it, and then while walking the tree if two forms' line numbers are different, welp, insert a <br> there.