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

Add a Contributing section to the docs, and cite it in error message #158

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,59 @@ If you already have XCode installed, you can ensure you have the latest XCode co
```bash
xcode-select --install
```

## Contributing

When contributing code changes to Wattsi, it’s important to understand some particulars about the programming API the code exposes.

### How to work with strings

Many operations in the Wattsi code don’t take normal strings as input but instead (for performance reasons) take custom types of string buffers that are called Rope and CutRopes in the code (but that aren’t the same kind of Rope as what’s described at https://en.wikipedia.org/wiki/Rope_(data_structure)).

The typical cases where you’d need to work with Ropes and CutRopes are when you’re getting text content from the document source, and when you’re setting the values of attributes and text nodes in the output.

Here’s a commented example of setting an attribute value for an element:

```pascal
// Create a new <a> element and assign it to the NewLink variable.
NewLink := ConstructHTMLElement(eA);
// Create a new rope and assign it to the Scratch variable.
Scratch := Default(Rope);
// Get the text content of Element (which happens to be the current
// element being processed) and assign it to the ExtractedData variable
// (which happens to be a cutrope).
ExtractedData := Element.TextContent.ExtractAll();
// Append the literal string “#refs” to the Scratch rope.
Scratch.Append('#refs');
// Append the ExtractedData cutrope to the Scratch rope (“destructively”
// means that the ExtractedData cutrope is destroyed after the Append).
Scratch.AppendDestructively(ExtractedData);
// Set the value of the NewLink <a> element’s href attribute to the
// content of the Scratch rope (“destructively” means that the Scratch
// rope is destroyed after the attribute value is set).
NewLink.SetAttributeDestructively('href', Scratch);
```

And here’s a commented example of creating and appending a new text node:

```pascal
// Create a new <a> element and assign it to the NewLink variable.
NewLink := ConstructHTMLElement(eA);
// Create a new rope and assign it to the Scratch variable.
Scratch := Default(Rope);
// Get the text content of Element (which happens to be the current
// element being processed) and assign it to the ExtractedData variable
// (which happens to be a cutrope).
ExtractedData := Element.TextContent.ExtractAll();
// Append the literal string “[” to the Scratch rope.
Scratch.Append('[');
// Append the ExtractedData cutrope to the Scratch rope (“destructively”
// means that the ExtractedData cutrope is destroyed after the Append).
Scratch.AppendDestructively(ExtractedData);
// Append the literal string “]” to the Scratch rope.
Scratch.Append(']');
// Create a new text node from the Scratch rope (“destructively” means
// that the Scratch rope is destroyed after the text node is created),
// and append it to the NewLink <a> element.
NewLink.AppendChild(TText.CreateDestructively(Scratch));
```
2 changes: 1 addition & 1 deletion src/lib/ropes.pas
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ procedure Rope.Append(const NewString: RopeInternals.TInlineString);
if (Length(NewString) > RopeInternals.UTF8InlineSize) then
begin
Writeln('Error: Append() call with string length > UTF8InlineSize: "' + NewString + '"');
Writeln('Call Append() with a string pointer, not a string: Append(@Foo), not Append(Foo)');
Writeln('Use Ropes instead; see https://github.com/whatwg/wattsi/#how-to-work-with-strings');
Halt(1);
end;
if ((not Assigned(FLast)) or (FLast^.Kind <> rfUTF8Inline) or (RopeInternals.UTF8InlineSize - FLast^.InlineLength < Length(NewString))) then
Expand Down