Summer schedule: Row types and containers

I have been working on updating Bike settings. I know I should use SwiftUI for this, I started doing that, I got stuck, and then my mind wandered…


I ended up at row types and containers, and that’s been a lot more fun!

It’s a bigger job, but I think more useful in the end. Also I’ve been able to get things up on the screen pretty quick, so that helps. There is still lots of work on details (probably most of the summer)… but screenshot was exciting enough to me that I decided to share:


The design is intended to map nicely into Bike and Markdown. First goal is nice for Bike, second goal is nice serialize to Markdown, third is nice reading from Markdown. I expect I can meet goals one and two quite well. Nicely reading all possible Markdown into an outline would be nice, but I’m not sure if that’s reachable without making everything really complicated.

The structures that I have are:

struct Row
  type: RowType
  containers: [RowContainer]

enum RowType
  case paragraph
  case heading(level)
  case horizontalRuler

enum RowContainer
  case taskList
  case orderedList
  case unorderedList
  case blockquote

There are a number of decisions to be made when mapping row types into an outline:

  • Row handles stay the same, they don’t take on any UI from the row type or containers.

  • More generally outline structure and row types/containers are separate and don’t interact except when calculating ordered list numbers.

  • Row containers are an ordered list…

  • Row containers would be quite a bit simpler if we only had to support one, instead of a list. The list is to handle cases such as a single row with a number, a checkbox, and block quoted content. Any thoughts on how necessary handling that case is?

  • Each row container indents the text content by the outline indentation level… but each row container does NOT change the outline level. This means we can create a list item that contains other rows and the text indents match. You can see this in the “Structure” item above.

  • Headings also have a level that’s used for formatting, but also do not change the outline structure.


Another bit of summer schedule is that I’ll be mostly away for next two weeks from Saturday. Will try to keep up with email and forums, but likely will be a bit slow. Summer fun!

5 Likes

Sounds quite exotic :slight_smile: Perhaps the kind of thing that the architecture can afford to deprecate or bypass in the first implementation ?

Yes, though these cases come up. For example quote within a quote is being used on previous line. Now how often do they come up when “Writing to think”? I don’t know, but I suspect not very often.

I think it would be difficult to add after the fact. Or at least difficult enough that I would never get to it.

With that said I also am feeling like I will likely not support these cases, and instead a Row will only have the possibility of a single container type… and to be clear you’ll still be able to have an ordered list that contains an unordered list at next level… the issue is just assigning multiple containers to the same row.

Another question that comes up is how to store this information in Bike file. For example if I have this outline:

Then my first idea is to store it like this:

<?xml version="1.0" encoding="UTF-8"?>
<html>
  <body>
    <ul id="NOcdwPIA">
      <li id="a7">
        <h1>Heading</h1>
      </li>
      <li id="wl" container="tl" data-done="">
        <p>one</p>
      </li>
      <li id="VL" container="tl" data-done="">
        <p>two</p>
        <ul>
          <li id="U6">
            <p>a</p>
          </li>
        </ul>
      </li>
      <li id="Ub" container="ul">
        <p>three</p>
      </li>
      <li id="S1" container="ul">
        <p>four</p>
      </li>
      <li id="eg">
        <hr/>
      </li>
    </ul>
  </body>
</html>

Notes:

  • Leaf nodes are stored using own tag. So in above we have leaves of h1, hr, and p.

  • Attributes (which will later be exposed as tags) are stored at the li level using data-NAME. That’s being used above to track the done state of a task.

  • The hard case is how to represent the containers. There is a tension between what is most direct mapping of the Bike model and what is the standard HTML representation. In the above example I am direct mapping the Bike model. If a row has a container then the rows li is assigned a new container attribute.

    This approach keeps the file format simple, but means container types won’t be visible when opening the Bike file directly in a web browser. I think I’m OK with that, but feedback welcome.

Sounds great to me. I like this additional features … if some container types (or even all of them) are not visible in a web browser: not a big deal at all. Benefits weight outweight the costs, it seems to me. Looking forward to these new features!

This looks really cool! My only suggestion is to not have different “levels” of heading and just have only h1; the stuff that logically appears under this heading should then be syntactically underneath it (i.e. these should be children); this has the benefit of not only making the outline more semantic, but also making the section collapsible. This seems to me to be the best way to integrate heading-style formatting into the outline model, as opposed to inheriting features of Markdown or HTML that do not make much sense in the outline model.

3 Likes

Could it work to preserve the existing structure, and express node types in terms of one or more reserved attribute names ?

I’m not sure that I follow… can you give an example of what you mean?

I share Jon Sterling’s feeling that a core strength of Bike is that it’s semantically well-defined, and that it would be pity to lose that simple and consistent outline structure to the more formatting-based H1-H6 Markdown and Web decorative subdivision model that FoldingText was experimenting with.

Consistent structural simplicity, combined with format-specific exporters, seems more valuable than maximizing the amount of formatting that is displayed by default for raw .bike files in a browser.

The general kind of pattern that I have in mind is:

  • A small number of (perhaps just one ?) reserved attribute names like data-type (possibly a few additional reserved attribute names like data-checkvalue ?), and
  • a small number of data-type attribute values like heading, note, quote etc

In other words, rather than expecting to find (slightly unsemantic and outline-breaking) formatting elements like <H1> to <H6>, export plugins to specific formats like Markdown and Microsoft Word etc would instead obtain heading depths from:

  1. The presence of a data-type="heading" attribute in a node
  2. The depth of that node’s nesting within other data-type="heading" nodes

and similarly, data-type="quote" nodes could be arbitrarily nested.

(as could data-type="note" nodes)

Does that make any sense ?


Obviously, export to Markdown etc would then offer options for things like:

  1. What Hn level to use for top level heading nodes in the Bike document
  2. What format to or named style to apply when heading nodes are nested more deeply than (6-n) levels.

(Or in the case of export to Microsoft Word, more deeply than (9-n) levels)


Expand disclosure triangle to view rough sample of attribute-tagging
<?xml version="1.0" encoding="UTF-8"?>
<html>
  <head>
    <meta charset="utf-8"/>
  </head>
  <body>
    <ul id="eZMu8iHZ">
      <li id="3C" data-type="heading">
        <p>Heading</p>
        <ul>
          <li id="FF" check="1">
            <p><s>one</s></p>
          </li>
          <li id="6z" check="1">
            <p><s>two</s></p>
          </li>
          <li id="HR" data-type="heading">
            <p>Subheading</p>
            <ul>
              <li id="fc">
                <p>a</p>
              </li>
              <li id="be">
                <p>three</p>
                <ul>
                  <li id="sc">
                    <p>some kind of elaboration here</p>
                  </li>
                </ul>
              </li>
              <li id="bD">
                <p>four</p>
              </li>
              <li id="Jp" data-type="note">
                <p>Note supported by quotation</p>
                <ul>
                  <li id="Wg" data-type="quote">
                    <p>quote 1</p>
                  </li>
                  <li id="Ii" data-type="quote">
                    <p>quote 2</p>
                    <ul>
                      <li id="c0" data-type="quote">
                        <p>nested quote</p>
                      </li>
                    </ul>
                  </li>
                  <li id="ss" data-type="quote">
                    <p>quote 3</p>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </body>
</html>


One potential advantage being, of course, that no file format change would be needed – we can already read and write such attribute values in existing Bike builds, and even apply them with scripts.

3 Likes

PS I wonder whether the amount of formatting displayed in a browser could be increased, without having to add new HTML elements, by using some CSS which is sensitive to data-type attribute values, and to nesting depths ?

2 Likes

Thanks for the great feedback!

I’m in the process of becoming scarce for the next two weeks, so I don’t have any final answers here, but you’ve got me thinking.

Good point and I think I agree. I have for a while thought that a near lossless Markdown/Bike round trip would be a nice feature enabled by this work, and that’s been shaping the design.

I still think that’s possible, but no longer think it should be primary goal. And also think it would be better supported by and extra transformation instead of making the Bike/Markdown map as direct as possible.


I think the part of the design that I’m most excited about is the container type visualization. I think it’s possible that many apps already do it this way, but the idea of inserting a type graphic (bullet, checkbox, etc) matching indentation width (and keeping outline handle same everywhere) solves a lot of visual problems that I’ve long wondered about.

I can finally create a list item that contains multiple paragraphs, and it makes sense visually in a regular outline structure. More generally I can create a visual distinct container, without breaking the regular outline structure.


@complexpoint In your example serialization there doesn’t seem to be any distinction between leaf and container types, so for instance I think you couldn’t model a list row whose first line is a heading … you could on the other hand model a list row whose second (indented under it) row is a heading.

Is that intentional? It would further simplify things to only have a single type per row, and the number of compelling cases where it makes sense for a row to have multiple types (container + leaf) isn’t that big. I could go with that design, just making sure it’s your intention.

Generally the runtime design would change to:

struct Row
  type: RowType

enum RowType
  case paragraph
  case heading
  case horizontalRuler
  case taskList
  case orderedList
  case unorderedList
  case blockquote

And it would be up to each row type to decide if it was also a container type that provided a graphic of indentation width.


For serialization you have everything conforming to the pattern:

<li type="*">
   <p></p>
</li>

In the case of horizontal rule would it make sense to serialize as?:

<li type="hr">
   <p><hr /></p>
</li>

And in future I expect other leaf types with specific required serialization might be added and handled in a similar way:

  • image
  • attachment
  • equation

@jonsterling @complexpoint Headings… I’m not sure on this one.

I do agree that a natural way to do heading levels in an outline is to just have a single heading type and then indent to create structure, but I’m not sure that’s the only way. Sometimes it might be nice to have visual distinct headings without having to create a matching structure. I’m not sure on this, just thinking.

With respect to headings … any thoughts on if they should have a visual indicator?

So comparing these two cases:

Screenshot 2023-06-16 at 9.03.12 AM

2 Likes

I think it’s true that there may be cases where you don’t want to create a structure underneath the heading… For instance, to your point, the very top of the document might be an example, if you want to create some kind of title without indenting the whole document below it.

In either case, though, I think having multiple heading levels is what creates the nightmare of “outline refactoring” where writers become enthralled with the excess of possible ways to format something, whose elimination is one of the major raisons d’être for the outline model in the purpose.

So my recommendation is basically that (1) whether to force the “contents” of a section to be indented under the heading depends on context and a user’s preference, but (2) you do a huge favor to the user if you do not introduce a secondary implicit hierarchy that is foreign to the outlining model and which requires a ton of totally manual reformatting every time you move or re-graft a node (which is what outlines are supposed to make easy and stress-free).

Good question… I’m not certain about the visual indicator, but maybe it could be left as part of custom CSS that users can configure? I think as a default it might be a little distracting, but I don’t feel strongly.

2 Likes

I think that’s right – good to keep the layers separate:

  1. The underlying structural nesting
  2. any particular ornamental layer that is added above.

( as we’ve all discovered at some point, the shoe needs to fit the foot. The other way around soon inhibits and distracts )

Markdown is a suit of clothing with roots in a tradition of sub-dividing topics.
The structural coherence and simplicity of Bike allows for that, but its avoidance of an architectural row ⇄ note distinction, for example, also enables other uses, such as the key point and supporting point structure of arguments.

It might be a pity to rework or overspecialise the underlying bone and muscle (simple, coherent and highly flexible outline structure) to make it tightly fit an inherited (and slightly limiting e.g. H1-H6) set of clothing.

(Bike is a much more flexible and useful outliner than FoldingText was able to be, with its over-fitting to Markdown)

( As for Markdown, it’s been great, and it has its role and already saturated ecosystem, but I think other things now lie ahead. Text is going through a crisis, and won’t emerge unchanged )

2 Likes

I think I will also simplify things so that each row only has a single type and there are no separate container types. This is limiting, but I don’t think too limiting.

For example:

Screenshot 2023-06-17 at 7.07.35 AM

If you indent heading under block quote it can still take on styling of that block quote through stylesheet cascading rules. (italic in this case). The only limit is that the first line of the quote could not also be a heading. This is same for list types, etc … first line couldn’t be a heading or a horizontal rule, but those types could be inserted as children.

Edit And of course if you really wanted bold on first line of the quote you could do that by selecting text and making bold. It’s just can’t have two types for the row, text formatting is fine.

2 Likes

This seems pretty reasonable to me…

1 Like

… but (2) you do a huge favor to the user if you do not introduce a secondary implicit hierarchy that is foreign to the outlining model and which requires a ton of totally manual reformatting every time you move or re-graft a node (which is what outlines are supposed to make easy and stress-free).

This.

And this:

…good to keep the layers separate:

  1. The underlying structural nesting
  2. any particular ornamental layer that is added above.

We’ve already got Folding Text.

Please let Bike be Bike.

Just my two cents.

1 Like

I’ve just posted the first preview release for this work on row types:

2 Likes