Skip to content
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

Alternative syntax for Stamp language #120

Open
Sarcasm opened this issue Feb 25, 2021 · 14 comments
Open

Alternative syntax for Stamp language #120

Sarcasm opened this issue Feb 25, 2021 · 14 comments

Comments

@Sarcasm
Copy link

Sarcasm commented Feb 25, 2021

Right now the stamp language provides this syntax:

folder myProject
file myProject/index.js
 data
  console.log("Hello world")
file myProject/readme.md
 data
  # My Readme

I'm wondering if it could not be simplified like this:

myProject/
 index.js
  console.log("Hello world")
 readme.md
  # My Readme

Directories can discriminated from files thanks to the final /.
Children of directories are files.
Children of files, is file content.

Would that still qualify as a treenotation language?

@breck7
Copy link
Owner

breck7 commented Feb 25, 2021

Love it! How would you do file permissions?

Also, you could come up with your own name. Building a tree language is cheap so
could build a whole new one.

Happy to team up on a Twitch call and pair program one out.

@breck7
Copy link
Owner

breck7 commented Feb 25, 2021

I guess you could add the restriction to not allow spaces in filenames, then just do index.js Writeable or something. Lots of options

@Sarcasm Sarcasm closed this as completed Feb 25, 2021
@Sarcasm Sarcasm reopened this Feb 25, 2021
@Sarcasm
Copy link
Author

Sarcasm commented Feb 25, 2021

For permission yes, I think it could be specified after the filename.
Maybe a bad idea, but could be in a chmod-like format:

foo.py +x
 #!/usr/bin/env python
 print("hello world")

@breck7
Copy link
Owner

breck7 commented Feb 26, 2021

Here's a quick prototype. I just started it but gotta run to a conference

https://jtree.treenotation.org/designer/#grammar%0A%20tooling%20onsave%20jtree%20build%20produceLang%20stamp%0A%20todo%20File%20permissions%0A%20anyCell%0A%20extraCell%0A%20%20highlightScope%20invalid%0A%20anyCell%0A%20%20highlightScope%20string%0A%20promptWordsCell%0A%20%20highlightScope%20string%0A%20filepathCell%0A%20%20highlightScope%20keyword%0A%20varNameCell%0A%20%20highlightScope%20string%0A%20commentCell%0A%20%20highlightScope%20comment%0A%20inputTypeCell%0A%20%20enum%20string%20int%20any%20lowercase%0A%20keywordCell%0A%20%20highlightScope%20keyword.control%0A%20stampNode%0A%20%20root%0A%20%20description%20A%20prefix%20Tree%20Language%20for%20creating%20distributable%20text%20template%20files%20that%20expand%20to%20folders%20and%20files.%0A%20%20catchAllNodeType%20errorNode%0A%20%20javascript%0A%20%20%20async%20executeSeries(parentDir)%20%7B%0A%20%20%20%20const%20length%20%3D%20this.length%0A%20%20%20%20for%20(let%20index%20%3D%200%3B%20index%20%3C%20length%3B%20index%2B%2B)%20%7B%0A%20%20%20%20%20const%20node%20%3D%20this.nodeAt(index)%0A%20%20%20%20%20await%20node.execute(parentDir)%0A%20%20%20%20%7D%0A%20%20%20%20return%20parentDir%0A%20%20%20%7D%0A%20%20%20async%20execute(parentDir%20%3D%20process.cwd())%20%7B%0A%20%20%20%20await%20this.executeSeries(parentDir)%0A%20%20%20%7D%0A%20%20%20static%20dirToStampWithContents(absPathWithoutEndingSlash)%20%7B%0A%20%20%20%20%20return%20stampNode._dirToStampFn(absPathWithoutEndingSlash%2C%20%22content%22)%0A%20%20%20%7D%0A%20%20%20static%20dirToStamp(absPathWithoutEndingSlash)%20%7B%0A%20%20%20%20%20return%20stampNode._dirToStampFn(absPathWithoutEndingSlash%2C%20%22list%22)%0A%20%20%20%7D%0A%20%20%20static%20_dirToStampFn(absPathWithoutEndingSlash%2C%20output)%20%7B%0A%20%20%20%20const%20fs%20%3D%20require(%22fs%22)%0A%20%20%20%20%2F%2F%20todo%3A%20add%20chmod%2C%20file%20metadata%0A%20%20%20%20if%20(absPathWithoutEndingSlash.startsWith(%22.%22))%20absPathWithoutEndingSlash%20%3D%20jtree.Utils.resolvePath(absPathWithoutEndingSlash%2C%20process.cwd()%20%2B%20%22%2F%22)%0A%20%20%20%20const%20stat%20%3D%20fs.statSync(absPathWithoutEndingSlash)%0A%20%20%20%20if%20(!stat.isDirectory())%20throw%20new%20Error(%60%24%7BabsPath%7D%20is%20a%20file%20not%20a%20directory.%60)%0A%20%20%20%20const%20fns%20%3D%20%7B%0A%20%20%20%20%20list%3A%20(file%2C%20reducedPath)%20%3D%3E%20%7B%0A%20%20%20%20%20%20const%20stat%20%3D%20fs.statSync(file)%0A%20%20%20%20%20%20const%20isDir%20%3D%20stat.isDirectory()%0A%20%20%20%20%20%20if%20(isDir)%20return%20%60folder%20%60%20%2B%20reducedPath%0A%20%20%20%20%20%20return%20%60file%20%60%20%2B%20reducedPath%0A%20%20%20%20%20%7D%2C%0A%20%20%20%20%20content%3A%20(file%2C%20reducedPath)%20%3D%3E%20%7B%0A%20%20%20%20%20%20const%20stat%20%3D%20fs.statSync(file)%0A%20%20%20%20%20%20const%20isDir%20%3D%20stat.isDirectory()%0A%20%20%20%20%20%20if%20(isDir)%20return%20%60folder%20%60%20%2B%20reducedPath%0A%20%20%20%20%20%20const%20content%20%3D%20fs.readFileSync(file%2C%20%22utf8%22)%0A%20%20%20%20%20%20return%20%60file%20%24%7BreducedPath%7D%0A%20%20%20%20data%24%7Bjtree.TreeNode.nest(content%2C%202)%7D%60%0A%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20const%20fn%20%3D%20fns%5Boutput%5D%0A%20%20%20%20return%20this._dirToStamp(absPathWithoutEndingSlash%2C%20fn)%0A%20%20%20%7D%0A%20%20%20static%20_dirToStamp(absPathWithoutEndingSlash%2C%20fileFn)%20%7B%0A%20%20%20%20const%20files%20%3D%20require(%22recursive-readdir-sync%22)(absPathWithoutEndingSlash)%0A%20%20%20%20const%20folderParts%20%3D%20absPathWithoutEndingSlash.split(%22%2F%22)%0A%20%20%20%20const%20rootFolderName%20%3D%20folderParts.pop()%0A%20%20%20%20const%20rootFolderPath%20%3D%20folderParts.join(%22%2F%22)%0A%20%20%20%20const%20pathStartIndex%20%3D%20rootFolderPath.length%20%2B%201%0A%20%20%20%20return%20files.map(file%20%3D%3E%20fileFn(file%2C%20file.substr(pathStartIndex))).join(%22%5Cn%22)%0A%20%20%20%7D%0A%20%20inScope%20hashbangNode%20folderNode%20fileNode%0A%20hashbangNode%0A%20%20crux%20%23!%0A%20%20catchAllCellType%20commentCell%0A%20%20cells%20commentCell%0A%20catchAllAnyLineNode%0A%20%20catchAllCellType%20anyCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20cells%20anyCell%0A%20errorNode%0A%20%20baseNodeType%20errorNode%0A%20fileNode%0A%20%20cells%20filepathCell%0A%20%20javascript%0A%20%20%20compileToBash(parentDir)%20%7B%0A%20%20%20%20const%20filePath%20%3D%20this._getAbsolutePath(parentDir)%0A%20%20%20%20return%20%60touch%20%24%7BfilePath%7D%5Cnecho%20-e%20%22%24%7Bthis.childrenToString()%7D%22%20%3E%3E%20%24%7BfilePath%7D%60%0A%20%20%20%7D%0A%20%20%20_getAbsolutePath(parentDir%20%3D%20process.cwd())%20%7B%0A%20%20%20%20return%20parentDir%20%2B%20%22%2F%22%20%2B%20this.cells.filepathCell%0A%20%20%20%7D%0A%20%20%20execute(parentDir)%20%7B%0A%20%20%20%20const%20fs%20%3D%20require(%22fs%22)%0A%20%20%20%20const%20fullPath%20%3D%20this._getAbsolutePath(parentDir)%0A%20%20%20%20console.log(%60Creating%20file%20%24%7BfullPath%7D%60)%0A%20%20%20%20const%20data%20%3D%20this.getNode(%22data%22)%0A%20%20%20%20const%20content%20%3D%20data%20%3F%20data.childrenToString()%20%3A%20%22%22%0A%20%20%20%20require(%22mkdirp%22).sync(require(%22path%22).dirname(fullPath))%0A%20%20%20%20fs.writeFileSync(fullPath%2C%20content%2C%20%22utf8%22)%0A%20%20%20%20const%20isExecutable%20%3D%20this.has(%22executable%22)%20%2F%2F%20todo%3A%20allow%20for%20all%20file%20permissions%3F%0A%20%20%20%20if%20(isExecutable)%20fs.chmodSync(fullPath%2C%20%22755%22)%0A%20%20%20%7D%0A%20%20inScope%20dataNode%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20folderNode%0A%20%20cells%20filepathCell%0A%20%20catchAllNodeType%20fileNode%0A%20%20pattern%20%5C%2F%0A%20%20javascript%0A%20%20%20compileToBash(parentDir)%20%7B%0A%20%20%20%20return%20%60mkdir%20%24%7Bthis._getAbsolutePath(parentDir)%7D%60%0A%20%20%20%7D%0A%20%20%20_getAbsolutePath(parentDir%20%3D%20process.cwd())%20%7B%0A%20%20%20%20return%20parentDir%20%2B%20%22%2F%22%20%2B%20this.cells.filepathCell%0A%20%20%20%7D%0A%20%20%20execute(parentDir)%20%7B%0A%20%20%20%20const%20path%20%3D%20this._getAbsolutePath(parentDir)%0A%20%20%20%20console.log(%60Creating%20folder%20%24%7Bpath%7D%60)%0A%20%20%20%20require(%22mkdirp%22).sync(path)%0A%20%20%20%7D%0Asample%0A%20myProject%2F%0A%20%20index.js%0A%20%20%20console.log(%22Hello%20world%22)%0A%20%20readme.md%0A%20%20%20%23%20My%20Readme

@Sarcasm
Copy link
Author

Sarcasm commented Feb 26, 2021

Maybe the presence of a shebang is enough to warrant the execution bit.
And like now, other permissions could be omitted.

@breck7
Copy link
Owner

breck7 commented Feb 26, 2021

You know what I only use that execution bit once in a blue moon. This Stamp alternative could
be dead simple (expands to plain vanilla non-executable files) without file permissions.

Just playing with the demo in the Designer I like yours better than mine.

It reminds me of a better https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html

@breck7
Copy link
Owner

breck7 commented Feb 26, 2021

Would you be interested in making your own repo and running with that idea?

I could contribute over there. I'd love to hear how much the experience
currently sucks of building one's own Tree Language (my guess is
very bad).

I think it would be worthwhile and would be a user myself.

@Sarcasm
Copy link
Author

Sarcasm commented Feb 26, 2021

I attempted something (link at the end).
Not sure I will push it further but I was happy to give it a try.

Regarding my experience.

Some nice things:

  • The IDE:
    • Completion in the text editor, although this tree language does not benefit from it, the grammar did.
    • "Explain" was very useful when writing the grammar.
  • The various examples, in the IDE and on Github were useful to understand how to make a grammar.
  • When thinking about Domain-specific language (DSL), I like to give a tree notation representation a try, I like its terseness.

Less nice things:

  • The IDE:
    • Would be nice to have a bigger text editor in the IDE.
    • I understand "Execute" and "Explain", but not "Compile".
      A Tool Tip for these actions could be helpful.
    • The auto-generated Readme has a lot of wasted space, multiple lines between a section title and its content.
    • Typing multiple f in the text editor produce something weird, the fs get smaller / closer to each others (font ligature?).
    • The errors, grammar and language could be better integrated.
      Right now, grammar errors are in the same pane as the auto-generated Readme, it's a bit confusing.
      In my browser (Firefox), the inline errors do not appear immediately, unlike the error lists ("Grammar/Language Errors"). I have to type a whitespace to see the inline error. But if I move the cursor with the mouse I do not see it.
  • Some examples weren't up-to-date / complete.
    For example the Chuck example does not execute, I did not realized initially that it was a todo.
    Maybe "Execute" could be greyed out in this case or an message indicate that execute() isn't implemented.
  • Finishing the grammar with a newline is an error.
    Maybe newlines should not be the separator, but instead something like an imaginary 'startOfLine' character.
    Right now newlines (nodeBreakSymbol) 'separate' nodes, but maybe there should be the possibility to set other modes so that it 'start' a new node.

https://jtree.treenotation.org/designer/#grammar%0A%20anyCell%0A%20%20highlightScope%20string%0A%20filePathCell%0A%20%20highlightScope%20keyword%0A%20stampNode%0A%20%20root%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20javascript%0A%20%20%20execute()%20%7B%0A%20%20%20%20return%20this.map(child%20%3D%3E%20child.execute()).join(%22%5Cn%22)%0A%20%20%20%7D%0A%20%20example%0A%20%20%20empty.txt%0A%20%20%20foo.txt%0A%20%20%20%20foo%0A%20%20%20%20bar%0A%20%20%20%20baz%0A%20%20%20executable.sh%0A%20%20%20%20%23!%2Fbin%2Fsh%0A%20%20%20%20echo%20%22Do%20you%20have%205%24%3F%22%0A%20%20%20foo%2F%0A%20%20%20%20__init__.py%0A%20%20%20%20%20__version__%20%3D%20'0.0.1'%0A%20%20%20%20bar%2F%0A%20%20%20%20%20__init__.py%0A%20directoryNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20pattern%20%5C%2F%24%0A%20%20javascript%0A%20%20%20execute()%20%7B%0A%20%20%20%20%20const%20name%20%3D%20this.getLine()%0A%20%20%20%20%20if%20(name.indexOf('%2F')%20!%3D%20name.length%20-%201)%20%7B%0A%20%20%20%20%20%20%20throw%20%60Invalid%20directory%20name%3A%20%24%7Bname%7D%60%0A%20%20%20%20%20%7D%0A%20%20%20%20%20return%20%5B%0A%20%20%20%20%20%20%20%60mkdir%20-p%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%60pushd%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%5D.concat(%0A%20%20%20%20%20%20%20this.map(child%20%3D%3E%20child.execute())%0A%20%20%20%20%20).concat(%5B%0A%20%20%20%20%20%20%20%22popd%22%0A%20%20%20%20%20%5D).join(%22%5Cn%22)%0A%20%20%20%7D%0A%20fileNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20javascript%0A%20%20%20execute()%20%7B%0A%20%20%20%20%20const%20filename%20%3D%20this.getLine()%0A%20%20%20%20%20if%20(filename.indexOf('%2F')%20!%3D%20-1)%20%7B%0A%20%20%20%20%20%20%20throw%20%60Invalid%20filename%3A%20%24%7Bfilename%7D%60%0A%20%20%20%20%20%7D%0A%20%20%20%20%20const%20lines%20%3D%20this.getLines()%0A%20%20%20%20%20if%20(lines.indexOf(%22EOF%22)%20!%3D%20-1)%20%7B%0A%20%20%20%20%20%20%20throw%20%60%24%7Bfilename%7D%3A%20Unsupported%20line%3A%20EOF%60%3B%0A%20%20%20%20%20%7D%20%0A%20%20%20%20%20if%20(lines.length%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20return%20%60touch%20%24%7Bfilename%7D%60%0A%20%20%20%20%20%7D%0A%20%20%20%20%20let%20out%20%3D%20%5B%0A%20%20%20%20%20%20%20%60%3E%24%7Bfilename%7D%20%3C%3C'EOF'%0A%20%20%20%24%7Blines.join(%22%5Cn%22)%7D%0A%20%20%20EOF%60%0A%20%20%20%20%20%5D%0A%20%20%20%20%20if%20(lines%5B0%5D.startsWith(%22%23!%22))%20%7B%0A%20%20%20%20%20%20%20out.push(%60chmod%20%2Bx%20%24%7Bfilename%7D%60)%0A%20%20%20%20%20%7D%0A%20%20%20%20%20return%20out.join(%22%5Cn%22)%0A%20%20%20%7D%0A%20catchAllAnyLineNode%0A%20%20cells%20anyCell%0A%20%20catchAllCellType%20anyCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20javascript%0A%20%20%20getTextContent()%20%7B%0A%20%20%20%20%20return%20this.getLine()%0A%20%20%20%7D%0Asample%0A%20empty.txt%0A%20foo.txt%0A%20%20foo%0A%20%20bar%0A%20%20baz%0A%20executable.sh%0A%20%20%23!%2Fbin%2Fsh%0A%20%20echo%20%22Do%20you%20have%205%24%3F%22%0A%20foo%2F%0A%20%20__init__.py%0A%20%20%20__version__%20%3D%20'0.0.1'%0A%20%20bar%2F%0A%20%20%20__init__.py

@breck7
Copy link
Owner

breck7 commented Aug 6, 2021

@Sarcasm finally got back to this. This is awesome!

I find it way better than Stamp. Feels natural. I made a few tiny changes to your code above (just changed execute methods to compile for consistency. The other reductions in code were just to temporarily make the link shorter). Named it "Clay". Playing around with it made me think of shaping a full project fluidly.

I want to go through your feedback and address the individual points, but just wanted to say this is awesome. Better than Stamp and really as simple as possible. Kudos.

https://jtree.treenotation.org/designer/#grammar%0A%20anyCell%0A%20%20highlightScope%20string%0A%20filePathCell%0A%20%20highlightScope%20keyword%0A%20clayNode%0A%20%20description%20Edit%20an%20entire%20project%20as%20a%20single%20text%20file.%0A%20%20root%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20javascript%0A%20%20%20compile()%20%7B%20return%20this.map(child%20%3D%3E%20child.compile()).join(%22%5Cn%22)%7D%0A%20%20example%0A%20%20%20foo.txt%0A%20%20%20%20foo%0A%20directoryNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20pattern%20%5C%2F%24%0A%20%20javascript%0A%20%20%20compile()%20%7B%0A%20%20%20%20%20const%20name%20%3D%20this.getLine()%0A%20%20%20%20%20return%20%5B%0A%20%20%20%20%20%20%20%60mkdir%20-p%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%60pushd%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%5D.concat(%0A%20%20%20%20%20%20%20this.map(child%20%3D%3E%20child.compile())%0A%20%20%20%20%20).concat(%5B%22popd%22%5D).join(%22%5Cn%22)%0A%20%20%20%7D%0A%20fileNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20javascript%0A%20%20%20compile()%20%7B%0A%20%20%20%20%20const%20filename%20%3D%20this.getLine()%0A%20%20%20%20%20if%20(filename.indexOf('%2F')%20!%3D%20-1)%0A%20%20%20%20%20%20%20throw%20%60Invalid%20filename%3A%20%24%7Bfilename%7D%60%0A%20%20%20%20%20const%20lines%20%3D%20this.getLines()%0A%20%20%20%20%20if%20(lines.length%20%3D%3D%200)%0A%20%20%20%20%20%20%20return%20%60touch%20%24%7Bfilename%7D%60%0A%20%20%20%20%20let%20out%20%3D%20%5B%0A%20%20%20%20%20%20%20%60%3E%24%7Bfilename%7D%20%3C%3C'EOF'%0A%20%20%20%24%7Blines.join(%22%5Cn%22)%7D%0A%20%20%20EOF%60%0A%20%20%20%20%20%5D%0A%20%20%20%20%20if%20(lines%5B0%5D.startsWith(%22%23!%22))%0A%20%20%20%20%20%20%20out.push(%60chmod%20%2Bx%20%24%7Bfilename%7D%60)%0A%20%20%20%20%20return%20out.join(%22%5Cn%22)%0A%20%20%20%7D%0A%20catchAllAnyLineNode%0A%20%20cells%20anyCell%0A%20%20catchAllCellType%20anyCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20javascript%0A%20%20%20getTextContent()%20%7B%20return%20this.getLine()%20%7D%0Asample%0A%20readme.md%0A%20%20%23%20Click%20%22Compile%22%0A%20%20Get%20a%20bash%20script%20that%20creates%20your%20project.%0A%20%20Read%20more%3A%20https%3A%2F%2Fgithub.com%2Fpublicdomaincompany%2Fjtree%2Fissues%2F120%0A%20package.json%0A%20%20%7B%0A%20%20%20%22name%22%3A%22clay%22%0A%20%20%7D%0A%20executable.sh%0A%20%20%23!%2Fbin%2Fsh%0A%20%20echo%20%22Hello%20world%22%0A%20src%2F%0A%20%20app.js%0A%20%20%20console.log(%22Hello%20world%22)

@Sarcasm
Copy link
Author

Sarcasm commented Aug 11, 2021

Hello,

I just try the Clay example, and it looks like there is an issue with the package.json generated content:

image

@breck7
Copy link
Owner

breck7 commented Aug 11, 2021

You are right. This should work:

https://jtree.treenotation.org/designer/#grammar%0A%20anyCell%0A%20%20highlightScope%20string%0A%20filePathCell%0A%20%20highlightScope%20keyword%0A%20clayNode%0A%20%20description%20Edit%20an%20entire%20project%20as%20a%20single%20text%20file.%0A%20%20root%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20javascript%0A%20%20%20compile()%20%7B%20return%20this.map(child%20%3D%3E%20child.compile()).join(%22%5Cn%22)%7D%0A%20%20example%0A%20%20%20foo.txt%0A%20%20%20%20foo%0A%20directoryNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20inScope%20directoryNode%0A%20%20catchAllNodeType%20fileNode%0A%20%20pattern%20%5C%2F%24%0A%20%20javascript%0A%20%20%20compile()%20%7B%0A%20%20%20%20%20const%20name%20%3D%20this.getLine()%0A%20%20%20%20%20return%20%5B%0A%20%20%20%20%20%20%20%60mkdir%20-p%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%60pushd%20%24%7Bname%7D%60%2C%0A%20%20%20%20%20%20%20%5D.concat(%0A%20%20%20%20%20%20%20this.map(child%20%3D%3E%20child.compile())%0A%20%20%20%20%20).concat(%5B%22popd%22%5D).join(%22%5Cn%22)%0A%20%20%20%7D%0A%20fileNode%0A%20%20cells%20filePathCell%0A%20%20catchAllCellType%20filePathCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0A%20%20javascript%0A%20%20%20compile()%20%7B%0A%20%20%20%20%20const%20filename%20%3D%20this.getLine()%0A%20%20%20%20%20if%20(filename.indexOf('%2F')%20!%3D%20-1)%0A%20%20%20%20%20%20%20throw%20%60Invalid%20filename%3A%20%24%7Bfilename%7D%60%0A%20%20%20%20%20const%20contents%20%3D%20this.childrenToString()%0A%20%20%20%20%20if%20(!contents.length)%0A%20%20%20%20%20%20%20return%20%60touch%20%24%7Bfilename%7D%60%0A%20%20%20%20%20let%20out%20%3D%20%5B%0A%20%20%20%20%20%20%20%60%3E%24%7Bfilename%7D%20%3C%3C'EOF'%0A%20%20%20%24%7Bcontents%7D%0A%20%20%20EOF%60%0A%20%20%20%20%20%5D%0A%20%20%20%20%20if%20(contents.startsWith(%22%23!%22))%0A%20%20%20%20%20%20%20out.push(%60chmod%20%2Bx%20%24%7Bfilename%7D%60)%0A%20%20%20%20%20return%20out.join(%22%5Cn%22)%0A%20%20%20%7D%0A%20catchAllAnyLineNode%0A%20%20cells%20anyCell%0A%20%20catchAllCellType%20anyCell%0A%20%20catchAllNodeType%20catchAllAnyLineNode%0Asample%0A%20readme.md%0A%20%20%23%20Click%20%22Compile%22%0A%20%20Get%20a%20bash%20script%20that%20creates%20your%20project.%0A%20%20Read%20more%3A%20https%3A%2F%2Fgithub.com%2Fpublicdomaincompany%2Fjtree%2Fissues%2F120%0A%20package.json%0A%20%20%7B%0A%20%20%20%22name%22%3A%22clay%22%0A%20%20%7D%0A%20executable.sh%0A%20%20%23!%2Fbin%2Fsh%0A%20%20echo%20%22Hello%20world%22%0A%20src%2F%0A%20%20app.js%0A%20%20%20console.log(%22Hello%20world%22)

@breck7
Copy link
Owner

breck7 commented Aug 11, 2021

Two reasons for this:

  1. The core TreeNode methods are not great. Some methods I often make mistakes with, such as getLines. I think some subpar methods could removed, some can be better named, and some more helpful core methods could be added. Perhaps there should be fewer public methods, but the ones remaining should be fantastic and foolproof. Or maybe there's a missing pattern(s) that would make core easier to use. Not sure. All I know is that I wish the core API was better!

  2. In this specific example, I changed the compilation of the parent file block to use childrenToString instead of getLines. Given a Tree like:

a
 b
  c
  d

Then "childrenToString" of "a" returns simply the text block:

b
 c
 d

I find this to be a very common pattern when embedding non-tree languages in a tree language and use it often. Using methods designed for tree languages inside "blob", non-tree language blocks can be tricky, and generally just dumping those blobs is what you want, in which case "childrenToString" works great. This situation should probably be well documented in future Grammar docs. The code currently parses non-Tree language blobs like this just like any other Tree Node, and I think there are some theoretical issues that could be resolved there. It's definitely one of the places that needs some good FAQs, as I was just having a long conversation with another dev on this very topic.

@breck7
Copy link
Owner

breck7 commented Aug 11, 2021

Just for clarity, a diff of the fix:
Screen Shot 2021-08-11 at 6 36 18 AM

@Sarcasm
Copy link
Author

Sarcasm commented Aug 11, 2021

The fix makes sense, childrenToString() looks more natural/correct than iterating over the lines, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants