-
Notifications
You must be signed in to change notification settings - Fork 6
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
feat: Import Code Block from source code #130
Comments
Thanks for filing this @dickermoshe - CC @angelosilvestre I've talked with Angelo a number of times about situations similar to the one you described. We've looked at a view different syntaxes that might accomplish the goal. @angelosilvestre can you mention the syntax details that we discussed most recently to mark areas of source code that should be documented? I agree that copying code into docs is counterproductive, and it would be nice to automate that. I'd like for us all to consider the variety of use-cases associated with this and then come up with a syntax that covers all reasonable use-cases. For example, consider the following desired goals:
If we can figure out a reasonable syntax, and if we can figure out a way for this behavior to work regardless of where the static site sits compared to the source code, then I'd be happy to see this as a plugin included within |
I don't have anything to add other than that this syntax should not be language specific at all. |
I experimented with this a long time ago. It wasn't designed to be part of a static generator, so it only generates markdown for a single file and it was meant be used to generate step by step guides. The syntax is like: // magic_prefix:>step:{step number} {block description}
void myMethod() {}
// magic_prefix:<step:{step number} Reference: https://github.com/angelosilvestre/code2docs Currently, none of the @matthew-carroll's use cases are supported, but we can come up with a syntax that works for these use cases. |
@angelosilvestre feel free to brainstorm anything that comes to mind. We can collect all the reasonable options and then pick whatever seems most versatile. Or perhaps we need a few different syntaxes for different use-cases. |
CC @suragch in case you have thoughts on this, too. |
Keeping documentation/tutorial code up-to-date and error-free is definitely a big need. In the past I've created unit tests or entire repos for the code used in a chapter or article, but it still required copying the code by hand. That would be amazing to be able to directly unit test the code that is included within an article. I have no idea what the syntax would be to only show partial code snippets like the use cases Matt is talking about. Perhaps some sort of marker in the source code that correlates it with a tag in the doc code block. I recall that Bob Nystrom was able to pull in code and test it when he wrote Crafting Interpreters. He discusses that here, but I don't understand how he did it. |
It's probably a worthwhile exercise to check for any existing languages/tools/approaches to see what others have been able to accomplish. Obviously this isn't a new problem. I'll check out the link for Bob's approach. But also no need to limit ourselves to Flutter/Dart - an approach in a JS project, Ruby project, Python project would all probably inform the effort. |
Basic SnippetA code snippet which just contains one section: // @docregion snippet_name
void main(){
print("Hello World");
}
// @enddocregion snippet_name Snippet with segments// @docregion snippet_name 1
void main(){
print("Hello");
// @enddocregion snippet_name 1
print("Hidden");
// @docregion snippet_name 2
print("World");
}
// @enddocregion snippet_name 2 This snippet would be stitched together from all the segments I agree, something that already exists were be much better. |
I haven't studied these in great depth, but here are some solutions that seem to be trying to solve a similar problem for other SSGs: Hexohttps://hexo.io/docs/tag-plugins#Include-Code
MkDocshttps://squidfunk.github.io/mkdocs-material/reference/code-blocks/#embedding-external-files Gatsbyhttps://www.gatsbyjs.com/plugins/gatsby-remark-embed-snippet/ |
I would caution against any syntax that depends on line number. I think we should do Gatsby, however, I think we should not include line numbers at all. |
I agree we should rely on line numbers. Also, I think we should use a magic prefix to make it easy to distinguish between syntax comments and regular comments. For example: // shock: region snippet_name
void main(){}
// shock: endregion snippet_name To show only a portion of a file, we could do something like the following: // shock: region snippet_name
void main(){
print('This line will be rendered');
// shock: snippet_name hide
print('No lines will be displayed until we find a "show" directive');
// shock: snippet_name show
print('This line will be rendered');
}
// shock: endregion snippet_name We could also declare multiple sections on the same block. That way, the docs could contain a block with parts of the code and another block with the full code. For example: // shock: region partial_region
// shock: region full_region
void main(){
print('This line will be rendered');
// shock: partial_region hide
print('No lines will be displayed until we find a "show" directive');
// shock: partial_region show
print('This line will be rendered');
}
// shock: endregion partial_region
// shock: endregion full_region If the user includes the region "partial_region", the following will be rendered: void main(){
print('This line will be rendered');
print('This line will be rendered');
} If the user includes the region "full_region", the following will be rendered: void main(){
print('This line will be rendered');
print('No lines will be displayed until we find a "show" directive');
print('This line will be rendered');
} @dickermoshe @suragch Any thoughts on this syntax? Do any of you have another use-case that we should consider? |
One random thought after looking at one of the samples that @suragch posted, I wonder if it would be productive to meld together the concept of line numbers with labels. We wouldn't use actual line numbers, because that's not maintainable. But we could use labels so that the documentation has a bit more control over what's included.
Then various possible includes:
While it has been requested that this syntax be language agnostic, I'm wondering if we should have generally useful agnostic syntax, but also some syntax that understands Dart and thereby can shorten requests:
|
I love the syntax, except for one thing.
This would mean that labels would have to be unique too, which would defeat the entire purpose. I would propose this:
Getting into analyzing dart would be a nice addition, but it adds lots of complexity. |
@dickermoshe - I didn't follow this point. Can you elaborate on what you mean? Which part are you calling a "label" and why would uniqueness defeat the entire purpose? |
I see 2 benefits to
1.// @start: section_name
final a = "ignored";
// @label: label_name1
final b = "included";
// @label: label_name2
final c = "ignored";
// @end: section_name If we only want to include The syntax you're proposing would work great with this!
I was wrong about this 2.Under the current syntax these will get quite verbose, we are repeating the words Example
// @start: my_widget
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
// @start: my_widget_build
@override
Widget build(BuildContext context) {
// @label: my_widget_setup
final thing = ...
final other = ...
// @label: my_widget_tree
return SuperEditor(
...
);
}
// @end: my_widget_build
}
// @end: my_widget
// @start: another_widget
class AnotherWidget extends StatelessWidget {
const AnotherWidget({super.key});
// @start: another_widget_build
@override
Widget build(BuildContext context) {
// @label: another_widget_setup
final thing = ...
final other = ...
// @label: another_widget_tree
return SuperEditor(
...
);
}
// @end: another_widget_build
}
// @end: another_widget What I'm proposing is that nested blocks and labels are accessed via their parents. // @start: my_widget
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
// @start: build
@override
Widget build(BuildContext context) {
// @label: setup
final thing = ...
final other = ...
// @label: tree
return SuperEditor(
...
);
}
// @end: build
}
// @end: my_widget The entire widget:
Just the build method:
Just the setup section of the build method:
|
So @dickermoshe it sounds like the specific point you're making is that blocks should automatically nest. Is that right? If so, seems reasonable to me. |
When working on the Dart ORM package, Drift (https://github.com/simolus3/drift), our founder created a static site generator too.
It's not as nice as this one, but it had a feature that I have never seen in any other static site generator.
It would be awesome if this package had such a feature.
One of the annoying parts of documenting a package is making sure that example code is up to date.
If changes are made to the project that changes some of the syntax, it's quite easy to forget to update the text in the markdown.
However, imagine if we could keep all the code in
.dart
(or anything else.py
,.js
etc.) and import the code blocks directly.For example, in our source documentation, we have sections that look like this:
/manager.md
When building, the site generator goes through all the dart files in
blocks/snippet
, looks for a snippet namedmanager_select
and loads the code into the markdown resulting in docs like this:Marking an area with a code snippet looks something like this:
This could work with any lang, parsing the file extension and putting the correct lang code on top of the multi-line code snippet.
The primary benefit of this is that code is not being written in Markdown files, it being written in source code files, where tests could be ran and code can be shared.
Imagine if you could use your test code as example code!
If interest for this feature is expressed, I will gladly put some time into it
The text was updated successfully, but these errors were encountered: