Generates step by step samples in markdown using source code delimited by specific comments.
Create a source file containing the final code. For example:
void main() {
print('hello,');
print('world');
print('The end.');
}
At the start of the file, define a title for the sample code and the list of steps:
// code2docs:TITLE: This is the sample code.
// code2docs:STEPS:
// code2docs:1: Print hello.
// code2docs:2: Print world.
// The description can be multiline.
// code2docs:3: Describe step 3.
Delimit the start of a code block that belongs to a specific step by preceding the line with a comment containing // code2docs:>step:{step number} {block description}
:
void main() {
// code2docs:>step:1 Add this to the beginning of main.
print('hello,');
// code2docs:>step:2 Add this after `print('hello,');`
print('world');
// code2docs:>step:3 The description is optional.
print('The end.');
}
Delimit the end of a code block that belongs to a specific step by following the line with a comment containing // code2docs:<step:{step number}
:
void main() {
// code2docs:>step:1 Add this to the beginning of main.
print('hello,');
// code2docs:<step:1
// code2docs:>step:2 Add this after `print('hello,');`
print('world');
// code2docs:<step:2
// code2docs:>step:3 The description is optional.
print('The end.');
// code2docs:<step:3
}
View generated markdown
Starting Code
void main() {
}
Print hello.
print('hello,');
Add this to the beginning of main.
Print world. The description can be multiline.
print('world');
Add this after
print('hello,');
Describe step 3.
print('The end.');
The description is optional.
import 'package:code2docs/code2docs.dart';
void main() {
final generator = SourceCodeSampleToMarkdown(language: 'dart');
final markdown = generator.generate('source code as string');
print(markdown);
}
View source code
// code2docs:TITLE: Creating an unselectable HR.
// code2docs:STEPS:
// code2docs:1: Create a component that returns a `BoxComponent` in the build method.
// code2docs:2: Create a `ComponentBuilder` that returns the custom component.
// code2docs:3: Add the custom `ComponentBuilder` to the editor's componentBuilders.
import 'package:flutter/material.dart';
import 'package:super_editor/super_editor.dart';
/// Example of a horizontal rule component that is not directly selectable.
///
/// The user can select around the horizontal rule, but cannot select it, specifically.
class UnselectableHrDemo extends StatefulWidget {
@override
_UnselectableHrDemoState createState() => _UnselectableHrDemoState();
}
class _UnselectableHrDemoState extends State<UnselectableHrDemo> {
late MutableDocument _doc;
late DocumentEditor _docEditor;
@override
void initState() {
super.initState();
_doc = _createDocument();
_docEditor = DocumentEditor(document: _doc);
}
@override
void dispose() {
_doc.dispose();
super.dispose();
}
MutableDocument _createDocument() {
return MutableDocument(
nodes: [
ParagraphNode(
id: DocumentEditor.createNodeId(),
text: AttributedText(
text:
"Below is a horizontal rule (HR). Normally in a SuperEditor, the user can tap to select an HR. In this case, you can't select the HR. You can only select around it. Try and find out:",
),
),
HorizontalRuleNode(id: DocumentEditor.createNodeId()),
ParagraphNode(
id: DocumentEditor.createNodeId(),
text: AttributedText(
text:
"Duis mollis libero eu scelerisque ullamcorper. Pellentesque eleifend arcu nec augue molestie, at iaculis dui rutrum. Etiam lobortis magna at magna pellentesque ornare. Sed accumsan, libero vel porta molestie, tortor lorem eleifend ante, at egestas leo felis sed nunc. Quisque mi neque, molestie vel dolor a, eleifend tempor odio.",
),
),
],
);
}
@override
Widget build(BuildContext context) {
return SuperEditor(
editor: _docEditor,
stylesheet: defaultStylesheet.copyWith(
documentPadding: const EdgeInsets.symmetric(vertical: 56, horizontal: 24),
),
// code2docs:>step:3 Add this code in the end of the `SuperEditor` creation.
// Add a new component builder that creates an unselectable
// horizontal rule, instead of creating the usual selectable kind.
componentBuilders: [
const UnselectableHrComponentBuilder(),
...defaultComponentBuilders,
],
// code2docs:<step:3
);
}
}
// code2docs:>step:2
/// SuperEditor [ComponentBuilder] that builds a horizontal rule that is
/// not selectable.
class UnselectableHrComponentBuilder implements ComponentBuilder {
const UnselectableHrComponentBuilder();
@override
SingleColumnLayoutComponentViewModel? createViewModel(Document document, DocumentNode node) {
// This builder can work with the standard horizontal rule view model, so
// we'll defer to the standard horizontal rule builder.
return null;
}
@override
Widget? createComponent(
SingleColumnDocumentComponentContext componentContext, SingleColumnLayoutComponentViewModel componentViewModel) {
if (componentViewModel is! HorizontalRuleComponentViewModel) {
return null;
}
return _UnselectableHorizontalRuleComponent(
componentKey: componentContext.componentKey,
);
}
}
// code2docs:<step:2
// code2docs:>step:1
class _UnselectableHorizontalRuleComponent extends StatelessWidget {
const _UnselectableHorizontalRuleComponent({
Key? key,
required this.componentKey,
}) : super(key: key);
final GlobalKey componentKey;
@override
Widget build(BuildContext context) {
return BoxComponent(
key: componentKey,
isVisuallySelectable: false,
child: const Divider(
color: Color(0xFF000000),
thickness: 1.0,
),
);
}
}
// code2docs:<step:1
View Generated Markdown
Starting Code
import 'package:flutter/material.dart';
import 'package:super_editor/super_editor.dart';
/// Example of a horizontal rule component that is not directly selectable.
///
/// The user can select around the horizontal rule, but cannot select it, specifically.
class UnselectableHrDemo extends StatefulWidget {
@override
_UnselectableHrDemoState createState() => _UnselectableHrDemoState();
}
class _UnselectableHrDemoState extends State<UnselectableHrDemo> {
late MutableDocument _doc;
late DocumentEditor _docEditor;
@override
void initState() {
super.initState();
_doc = _createDocument();
_docEditor = DocumentEditor(document: _doc);
}
@override
void dispose() {
_doc.dispose();
super.dispose();
}
MutableDocument _createDocument() {
return MutableDocument(
nodes: [
ParagraphNode(
id: DocumentEditor.createNodeId(),
text: AttributedText(
text:
"Below is a horizontal rule (HR). Normally in a SuperEditor, the user can tap to select an HR. In this case, you can't select the HR. You can only select around it. Try and find out:",
),
),
HorizontalRuleNode(id: DocumentEditor.createNodeId()),
ParagraphNode(
id: DocumentEditor.createNodeId(),
text: AttributedText(
text:
"Duis mollis libero eu scelerisque ullamcorper. Pellentesque eleifend arcu nec augue molestie, at iaculis dui rutrum. Etiam lobortis magna at magna pellentesque ornare. Sed accumsan, libero vel porta molestie, tortor lorem eleifend ante, at egestas leo felis sed nunc. Quisque mi neque, molestie vel dolor a, eleifend tempor odio.",
),
),
],
);
}
@override
Widget build(BuildContext context) {
return SuperEditor(
editor: _docEditor,
stylesheet: defaultStylesheet.copyWith(
documentPadding: const EdgeInsets.symmetric(vertical: 56, horizontal: 24),
),
);
}
}
Create a component that returns a BoxComponent
in the build method.
class _UnselectableHorizontalRuleComponent extends StatelessWidget {
const _UnselectableHorizontalRuleComponent({
Key? key,
required this.componentKey,
}) : super(key: key);
final GlobalKey componentKey;
@override
Widget build(BuildContext context) {
return BoxComponent(
key: componentKey,
isVisuallySelectable: false,
child: const Divider(
color: Color(0xFF000000),
thickness: 1.0,
),
);
}
}
Create a ComponentBuilder
that returns the custom component.
/// SuperEditor [ComponentBuilder] that builds a horizontal rule that is
/// not selectable.
class UnselectableHrComponentBuilder implements ComponentBuilder {
const UnselectableHrComponentBuilder();
@override
SingleColumnLayoutComponentViewModel? createViewModel(Document document, DocumentNode node) {
// This builder can work with the standard horizontal rule view model, so
// we'll defer to the standard horizontal rule builder.
return null;
}
@override
Widget? createComponent(
SingleColumnDocumentComponentContext componentContext, SingleColumnLayoutComponentViewModel componentViewModel) {
if (componentViewModel is! HorizontalRuleComponentViewModel) {
return null;
}
return _UnselectableHorizontalRuleComponent(
componentKey: componentContext.componentKey,
);
}
}
Add the custom ComponentBuilder
to the editor's componentBuilders.
// Add a new component builder that creates an unselectable
// horizontal rule, instead of creating the usual selectable kind.
componentBuilders: [
const UnselectableHrComponentBuilder(),
...defaultComponentBuilders,
],
Add this code in the end of the
SuperEditor
creation.