I'd love some early feedback on Margin, a markup language for hierarchically structured thought.
Margin came out of my desire to build a lightweight to-do app – though I soon realized what I really wanted was a markup language to capture structured thought. One that was not only human-readable, but also easily machine parsable.
Most importantly, Margin doesn't impose strict hierarchical categories (eg. "Header 1", "Project", "Task"). Instead it allows the user/application to define those categories. The ultimate goal is to democratize your to-do lists, notes, writing, etc. making them portable and platform-independent.
Aside from feedback on the specs & philosophy of Margin, which would be very appreciated, I could use some serious help with the parser (https://margin.love/parser/). I'm only a casual coder, so this problem was a difficult one for me. The parser is both incomplete and buggy, but hopefully it gets across the basics of how Margin is supposed to work.
Thanks!
One issue with ambiguity now is that you specify that "dashes" are ignored, even though (I assume) you probably meant "hyphens". Using UTF-8 would solve that.
Also, you might consider adding "+" the set of ignored characters. It's frequently used for lists. Just something to think about.
EDIT: I should probably start filing these as issues on your github
I made a query language for use in situations just like this years ago, never ended up using it much though.
These probably seem like really picky questions but I’m thinking about how to write a parser for this and these are the questions that are coming up.
Though it's a great question, and I could see myself changing course if a good use case were pitched whereby the ordering of annotations mattered specifically in a way that a use-case-specific app couldn't function if those children weren't already ordered for it in the plaintext.
There's also a case to be made that, because annotations are just a special type of child items, and because item order is generally meaningful in Margin, then we might as well keep annotations ordered too for good measure.
One weird edge case I’m thinking about: what happens if you have two lines, A and B, and A is indented with a tab and B is indented with 3 spaces? Is A the parent of B?
More generally: how do you compare tabs and spaces in the context of indentation levels?
Unfortunately, that might be the cleanest solution for Margin, too: to simply disallow the intermingling of tabs and spaces as hierarchical tokens within a single parent.
In that scenario, you could use tabs in one part of the document and spaces in the other -- as long as all the direct children of one parent item follow the same rules.
Currently I am using a set of markdown editors: Ulysses[^1], Typora, iA Writer and a few others. That makes me interface agnostic. The most important thing is the content, the (markdown)text I am producing. I can't say that about text in org-mode. It's tied to Emacs.
(Edit:)
In Ulysses I started using an annotation system myself, that's why this project here caught my attention. I am experimenting with brackets, double brackets, colons, double colons. Still in the process of experimenting.
---
[^0]: was using org-mode to write documentation, journal entries, and as a task management system
[^1]: Ulysses is way more than an editor. It is like Evernote with markdown targeting authors. It‘s my ‚Zettelkasten‘
It looks great for coders who are ready to learn new syntax. Though what I'd really like to avoid with Margin is anything that makes the language more complex than it needs to be.
For example, org mode defines headlines as:
The headlines in Org start with one or more stars, on the left margin. For example:
* Top level headline
** Second level
*** Third level
With Margin, there's no concept of a "headline." For the thinker, the headline could be represented by any level of the plain text hierarchical tree. And the thinker would then be free to choose (or conform to) any Margin-based app that corresponds with their model. In other words, it works best however you want to use it.Pretty much all you need. Would love to see it augmented with rich text. :)
Good work!
[1] https://github.com/gamburg/margin/blob/master/parser/js/Marg...
I'd say the goals of Margin are similar, but more focused on thought that is specifically hierarchical in nature -- whereas ArchieML seems to be more focused on structuring text in key:value pairs (if I'm understanding it correctly).
The hope with Margin is that lots of people already store their notes, to do lists, and random thoughts in a format that might already be (or almost be) valid Margin. It's intentionally non-technical, and its syntax should make sense to those who don't know or care what Margin is.
- It seems like annotations should be excluded from the "value" field. If I write something like "Frankenstein [author:Mary Shelley]", I'm probably going to want to access the title "Frankenstein" on its own after parsing.
- It would be nice to be able to omit the brackets when there's no whitespace inside an annotation. For example, you could write "broccoli type:vegetable" instead of "broccoli [type: vegetable]"
- I like that you can use different list decorators, like -, >, or *. But these don't show up anywhere except the "raw_data" field—it would be nice if there was a field that contained just the decorator, something like:
{
"raw-data" : "\t- Some Item",
"value" : "Some Item",
"decorator" : "-",
"annotations": {},
"children": []
}
Then you could easily use different decorators to encode semantic information. For instance, a Pros/Cons list could use '+' for Pros and '-' for Cons, and that distinction would be easy to access programmatically. If you do this, I think "[ ]" and "[x]" should be end up in the decorator field. Or maybe it could be a "prefix" field and "suffix" field, to hold decorators at either the beginning or end?- check that video Alice mentioned at time 3:42 - don't forget to text Bob O:) - my favorite thing is:strawberries
It makes parsing more complicated, as well as creating unexpected results in non-obvious cases (for example the last one could just be a typo, and what if it was instead written as 'is:strawberries, cake'?). It also isn't intuitive in the case of your first example, since I think of Mary Shelley as a single thing.
Alternatively, annotations could just read to EOL, unless it's explicitly guarded off. That would depend on how people use it, I suppose.
The parser in its current form is here: https://github.com/gamburg/margin/blob/master/parser/js/Marg...
I haven’t written any Margin — I’ve only read through you documentation — but maybe this feedback may be useful. (Apologies if you’re already doing all of this, in which case it may be helpful to others at least.)
I love the idea of flexibility in how Margin can be used. Because if this though, you will find emergent behavior among your user base. People will do things you could never have imagined and expect Margin not to break their workflow.
If you capture these as a standard test suite or set of test cases, it will be very helpful to anyone implementing a Margin parser in another language.
You already have a reference parser in JS and if you get to the million user mark (!) you might like to provide it in C instead. Something like libSYCK did for YAML.
For now, having a test suite is the next best thing. While Margin is not prescriptive about how you use it, you’ll want Margin parsers to be strictly in agreement in how they interpret Margin, for it to be widely adopted! Then when someone sees Margin, finds it to be a good idea to use in their language of choice, and writes their own parser they can confidently announces “passes 100% of the Margin test suite!”.
The big difference here would be that Margin isn't an app, but a markup language that's meant to be used as an open & portable storage system for apps. A storage system that is, by design, human readable plain text.
I do love that there's an (albeit niche) interest in apps that let you think/notate in this way.
However, margin doesn't really seem to have any equivalent of links between files, which I find essential for organising thoughts in anything beyond small notes. This seems like something that's contrary to the philosophy in a sense, but what would be the margin-ish equivalent of something like that, and (following from that) things like file tags? Would those be done with annotations?
The philosophical question is an interesting one. I think for the most part, if items are meaningfully related, the Margin philosophy would probably be to store them within the same document parent (or file).
> you wouldn’t build a web app in markdown
I'm willing to bet it's been done and has already been a Show HN. After all, there's "My blog is now generated by Google Docs"[1] currently on the front page of HN. If not then it's only a matter of time :)
And fair, re: "you wouldn’t build a web app in markdown". I'm sure it's been done :)
[1] https://github.com/gamburg/margin/blob/master/parser/js/Marg...
How are URL's handled? One solution would be to just reuse Markdown's [link](text) notation, as a subset of annotations. That would be the least-mental-friction route for markdown users.
[1] https://github.com/gamburg/margin/commit/d9abf003f665627d392...
We'll definitely consider supporting import/export to Margin.
Definitely a necessary feature if people are going to use this to store text. Do let me know if you have any ideas about what kind of syntax might be best for multiline blocks -- keeping in mind it should be both easy to type and easy to read (eg. ideally avoiding '\n' or special newline characters, for example).
I don't see how this is different than just opening notepad.exe and writing stuff.
> Lightweight markup
> The plain text language
> Margin is a lightweight markup language
> Margin can thrive within any plain text editor
> Margin is not an app, but a markup language.
The author's experimental parser? It's linked: https://github.com/gamburg/margin
The processing of my 6000 lines Dynalist export (perfectly compatible due to the permissive syntax!) took about 1 second on an i7 from 2015.