-
Notifications
You must be signed in to change notification settings - Fork 197
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
Support titles for links and images #42
base: master
Are you sure you want to change the base?
Conversation
This is an awesome start! I haven't looked at the actual code yet, but spec tests are promising (see corresponding examples here). Newly passing CommonMark tests are 166, 327, 481, 485, 504, 523, and 535. It looks like the newly failing tests should be pretty easy to fix; I'll try to look at your code and give specifics tomorrow. Thanks for working on this, @bensyverson! |
Nice, thanks @john-mueller ! I'll take a look at the newly failing tests too and poke around in the codebase. 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With these tweaks, this PR passes 7 new CommonMark tests (166, 327, 481, 485, 504, 523, 535), and does not cause any CommonMark regressions.
All the changes, as well as an additional 4 tests to guard against regressions, are on the link-titles-fixup
branch at https://github.com/john-mueller/Ink. I suggest merging these changes into your feature branch before merging this PR. If it would be easier, I can open a PR to add them to your feature branch.
Thanks again for adding this!
@@ -8,9 +8,31 @@ internal extension Character { | |||
var isSameLineWhitespace: Bool { | |||
isWhitespace && !isNewline | |||
} | |||
|
|||
var isLegalInURL: Bool { | |||
self != ")" && self != " " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self != ")" && self != " " | |
self != ")" && self != " " && self != "\n" |
This helps fix the new failure of CommonMark test 487:
"The destination cannot contain line breaks" (spec)
Sources/Ink/Internal/Link.swift
Outdated
@@ -19,20 +20,35 @@ internal struct Link: Fragment { | |||
|
|||
if reader.currentCharacter == "(" { | |||
reader.advanceIndex() | |||
let url = try reader.read(until: ")") | |||
return Link(target: .url(url), text: text) | |||
let url = try reader.readCharacters(matching: \.isLegalInURL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let url = try reader.readCharacters(matching: \.isLegalInURL) | |
let url = try? reader.readCharacters(matching: \.isLegalInURL) |
This helps fix the new failure of CommonMark tests 483 and 563:
"Both the title and the destination may be omitted" (spec)
"Inline links also take precedence" (spec)
If both title and destination are missing, then this line encounters ")" immediately and throws, which ends link parsing. So instead of throwing, we assign nil
to the url if it is not present, and use a default value of ""
on line 33.
Sources/Ink/Internal/Link.swift
Outdated
titleText = try reader.read(until: "\"") | ||
} | ||
try reader.read(")") | ||
return Link(target: .url(url), text: text, title: titleText) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Link(target: .url(url), text: text, title: titleText) | |
return Link(target: .url(url ?? ""), text: text, title: titleText) |
Needed since url
is now optional.
if reader.currentCharacter.isSameLineWhitespace { | ||
try reader.readWhitespaces() | ||
} | ||
if let delimeter = TitleDelimeter(rawValue: reader.currentCharacter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if let delimeter = TitleDelimeter(rawValue: reader.currentCharacter) { | |
if let delimeter = TitleDelimeter(rawValue: reader.currentCharacter) { | |
let index = reader.currentIndex |
We capture the index at the start of the title parsing, in case there is an otherwise valid title followed by non-whitespace. If that happens, we rewind the reader to the beginning of what would have been the title, and set titleText = nil
.
} | ||
if let delimeter = TitleDelimeter(rawValue: reader.currentCharacter) { | ||
reader.advanceIndex() | ||
titleText = try reader.read(until: delimeter.closing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
titleText = try reader.read(until: delimeter.closing) | |
titleText = try reader.read(until: delimeter.closing) | |
reader.discardWhitespaces() | |
if !reader.didReachEnd && !reader.currentCharacter.isWhitespace { | |
reader.moveToIndex(index) | |
titleText = nil | |
} |
This helps fix the new failure of CommonMark test 179:
"No further non-whitespace characters may occur on the line." (spec & example)
Amazing, thanks @john-mueller! Just merged in your changes 🥳 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Looks good to me!
Just wanted to chime in and alert you to PR #47 which I've just opened and which is somewhat related. Some Markdown editors support PR #47 is already agnostic over what attributes it can handle. What it doesn't do is deal with quoting. I.e. while it currently does support I'm pretty sure with what's in this PR here my PR #47 could be extended (although I haven't looked at the changes in here in detail yet). What are your thoughts to merge the two approaches? |
Hold on, I misread the syntax for the title definition. It's not declared the same way as the width and height parameters, which are Still, supporting both |
@finestructure Attributes on images/links would be fantastic—I've often wanted this for image sizes. I'll take a look and see if there's a nice clean way to merge the two! |
I left a note on #47 that is relevant. |
I didn't learn this until yesterday, but apparently stock Markdown supports titles in links and images:
Same thing for images, meaning

should turn into:It's also supported in the link definition syntax, with any amount of same-line whitespace, and two other delimiters:
It even supports putting the title on the next line and using spaces for padding:
I took a very quick pass at implementing this functionality in Ink, and added a few tests to kick the tires. But I probably haven't spent enough time in the Ink codebase to do things 100% idiomatically. So please take or leave any of this!
Thanks @JohnSundell for creating such a powerful Markdown parser—I'm already customizing Ink via a Modifier in a Publish plug-in, which is a testament to how powerful this suite of tools really is!