Skip to content
Merged
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
61 changes: 3 additions & 58 deletions _includes/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Description

{{ controller_data.short }}
{{ controller_data.short | replace_relative_links: page.path }}

{% if controller_data.min_api_version %}

Expand Down Expand Up @@ -89,7 +89,7 @@ your client and daemon API versions.

## Extended description

{{ controller_data.long }}
{{ controller_data.long | replace_relative_links: page.path }}

{% endunless %}

Expand Down Expand Up @@ -137,7 +137,7 @@ For example uses of this command, refer to the [examples section](#examples) bel

## Examples

{{ controller_data.examples }}
{{ controller_data.examples | replace_relative_links: page.path }}

{% endif %}

Expand Down Expand Up @@ -203,58 +203,3 @@ For example uses of this command, refer to the [examples section](#examples) bel
</table>

{% endunless %}

<script>
// This is a horrible hack, and cute little kittens are sacrificed every time it's run, so we
// need to remove it as soon as possible.
//
// Fix up links to markdown pages that weren't resolved by Jekyll (or the "jekyll-relative-links"
// plugin). This is a horrible hack, and should not rely on JavaScript (perhaps be re-implemented
// using Liquid). We need this hack to work around two bugs in the "jekyll-relative-links" plugin;
// 1. As reported in https://github.com/benbalter/jekyll-relative-links/issues/54, (relative) links
// to markdown pages in includes are not processed by Jekyll. This means that (for example) our
// reference pages (which use includes) contain broken links. We can work around this by modifying
// the markdown for those pages to use "absolute" "html" links (/link/to/other/page/#some-anchor),
// but doing so would render the links broken when viewed on GitHub. Instead, we're fixing them up
// here, hoping the bug will be fixed, and it's only temporarily.
// 2. As reported in https://github.com/benbalter/jekyll-relative-links/issues/61, (relative) links
// to markdown pages are not resolved if the link's caption/title is wrapped.
//
Array.prototype.forEach.call(document.querySelectorAll("section.section a:not(.nomunge)"), function (el) {
let href = el.getAttribute("href");
if (href.startsWith("/") || href.startsWith("#") || href.includes("://") || !href.includes('.md')) {
// Don't modify anchor links, absolute links, links to external websites,
// or links not pointing to a .md file; we assume those were
// resolved successfully by Jekyll.
return
}
if (href.startsWith("./")) {
href = href.substr(2)
}
if ("{{ page.name }}" !== "index.md") {
// For non-index pages, things are a bit hairy. For example, for /foo/bar/mypage.md, Jekyll
// will generate a page named /foo/bar/mypage/index.html. This means that all links relative
// to mypage.md expect those links to be relative to the /foo/bar/ directory, but end up
// being relative to /foo/bar/mypage/.
//
// For files "next to", or "below" this file, such as "file.md" or "nested/dir/file.md" we
// prepend the "parent-dir" to the URL.
//
// For links to files "up" the directory tree, we prepend
// "../" to the URL and have the browser handle this. For example, "../file.md" and "../../file.md"
// become "../../file.md" and "../../../file.md".
if (href.startsWith("../")) {
href = "../" + href
} else {
// Generate "parentPath" with Liquid, which is used below. Liquid's page.path (and page.dir)
// are relative to the _generated_ HTML page, not the source page, so we have to remove the
// last part of the path:
// {% raw %}{% assign parentPath = page.path | prepend: "/" | remove: page.name %}{% endraw %}
// {% assign parentPath = page.path | prepend: "/" | remove: page.name %}
href = "{{ parentPath}}" + href
}
}
// finally, we replace the .md extension for a slash, and update the link's href
el.setAttribute("href", href.replace(".md", "/"))
});
</script>
114 changes: 114 additions & 0 deletions _plugins/relative_links_filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module Jekyll
# This custom Filter is used to fix up links to markdown pages that weren't
# resolved by Jekyll (or the "jekyll-relative-links" plugin). We need this hack
# to work around a bug in the "jekyll-relative-links" plugin;
#
# As reported in https://github.com/benbalter/jekyll-relative-links/issues/54,
# (relative) links to markdown pages in includes are not processed by Jekyll.
# This means that our reference pages (which use includes) have broken links.
# We could work around this by modifying the markdown for those pages to use
# "absolute" "html" links (/link/to/other/page/#some-anchor), but doing so
# would render the links broken when viewed on GitHub. Instead, we're fixing
# them up here, until the bug is fixed upstream.
#
# A second bug (https://github.com/benbalter/jekyll-relative-links/issues/61),
# causes (relative) links to markdown pages to not be resolved if the link's
# caption/title is wrapped. This bug is currently not handled by this plugin,
# but could possibly be addressed by modifying the TITLE_REGEX.
#
# This plugin is based on code in the jekyll-relative-links plugin, but takes
# some shortcuts;
#
# - We use the code from jekyll-relative-links plugin to find/extract links
# on the page
# - Relative links are converted to absolute links, using the path of the
# markdown source file that's passed as argument
# - After conversion to an absolute link, we strip the ".md" extension; no
# attempt is made to resolve the file that's linked to. This is different
# from the jekyll-relative-links plugin, which _does_ resolve the linked
# file. This functionality could be added in future by someone who has
# more experience with Ruby.
module RelativeLinksFilter
attr_accessor :site, :config

# Use Jekyll's native relative_url filter
include Jekyll::Filters::URLFilters

LINK_TEXT_REGEX = %r!(.*?)!.freeze
FRAGMENT_REGEX = %r!(#.+?)?!.freeze
TITLE_REGEX = %r{(\s+"(?:\\"|[^"])*(?<!\\)"|\s+"(?:\\'|[^'])*(?<!\\)')?}.freeze
FRAG_AND_TITLE_REGEX = %r!#{FRAGMENT_REGEX}#{TITLE_REGEX}!.freeze
INLINE_LINK_REGEX = %r!\[#{LINK_TEXT_REGEX}\]\(([^\)]+?)#{FRAG_AND_TITLE_REGEX}\)!.freeze
REFERENCE_LINK_REGEX = %r!^\s*?\[#{LINK_TEXT_REGEX}\]: (.+?)#{FRAG_AND_TITLE_REGEX}\s*?$!.freeze
LINK_REGEX = %r!(#{INLINE_LINK_REGEX}|#{REFERENCE_LINK_REGEX})!.freeze

def replace_relative_links(input, source_path)
url_base = File.dirname("/" + source_path)
input = input.dup.gsub(LINK_REGEX) do |original|
link = link_parts(Regexp.last_match)
next original unless replaceable_link?(link.path)

path = path_from_root(link.path, url_base)
url = path.gsub(".md", "/")
next original unless url

link.path = url
replacement_text(link)
end
end

private

# Stores info on a Markdown Link (avoid rubocop's Metrics/ParameterLists warning)
Link = Struct.new(:link_type, :text, :path, :fragment, :title)

def link_parts(matches)
last_inline = 5
link_type = matches[2] ? :inline : :reference
link_text = matches[link_type == :inline ? 2 : last_inline + 1]
relative_path = matches[link_type == :inline ? 3 : last_inline + 2]
fragment = matches[link_type == :inline ? 4 : last_inline + 3]
title = matches[link_type == :inline ? 5 : last_inline + 4]
Link.new(link_type, link_text, relative_path, fragment, title)
end

def path_from_root(relative_path, url_base)
relative_path.sub!(%r!\A/!, "")
absolute_path = File.expand_path(relative_path, url_base)
absolute_path.sub(%r!\A#{Regexp.escape(Dir.pwd)}/!, "")
end

# @param link [Link] A Link object describing the markdown link to make
def replacement_text(link)
link.path << link.fragment if link.fragment

if link.link_type == :inline
"[#{link.text}](#{link.path}#{link.title})"
else
"\n[#{link.text}]: #{link.path}#{link.title}"
end
end

def absolute_url?(string)
return unless string

Addressable::URI.parse(string).absolute?
rescue Addressable::URI::InvalidURIError
nil
end

def fragment?(string)
string&.start_with?("#")
end

def replaceable_link?(string)
!fragment?(string) && !absolute_url?(string)
end

def global_entry_filter
@global_entry_filter ||= Jekyll::EntryFilter.new(site)
end
end
end

Liquid::Template.register_filter(Jekyll::RelativeLinksFilter)