markdown headers should have anchors #6

Closed
technoweenie opened this Issue May 9, 2010 · 52 comments

Comments

Projects
None yet
Member

technoweenie commented May 9, 2010

Anchors are great for usability in long documentation.

# Install
blah blah

<h1 name="INSTALL">Install</h1>
<p>blah blah</p>

http://github.com/user/repo#INSTALL

Should be:

<h1 id="INSTALL">Install</h1>
<p>blah blah</p>

Name isn't a valid xhtml attribute for headers.

Member

technoweenie commented May 9, 2010

ah, i'm old school :)

Haha!

The MultiMarkdown renderer included in TextMate does this already.

Blech it's in Perl, but it's a pretty good implementation if you're looking for an example.

Contributor

dabrahams commented May 19, 2010

+1

Owner

defunkt commented Jul 7, 2010

If someone has a patch that works with RDiscount that would be best.

kneath commented Jul 25, 2010

Note that we can't support the id="blah" method due to expected suicide rate increases resulting from CSS specificity hell. If someone has a parser that outputs something like:

<a name="install" />
<h1>Install</h1>

I'd be all on board.

Contributor

dabrahams commented Jul 26, 2010

If I had ever coded a single line of Ruby I'm sure I could send you a correct patch with no testing and one hand tied behind my back. 'Till then, please consider this a feature request, guys :-). I don't have a patch.

I've noticed this problem with README.rst files as well. As well as headings, inline targets in .rst files, e.g. _some target, don't work. The inline target text gets wrapped in a <span> but doesn't get made into any sort of link target. Should I file this as a separate issue?

Another implementation of such a thing:

http://gitorious.org/python-markdown/mainline/blobs/master/markdown/extensions/toc.py

How about post-processing the html? Too slow?

getify commented Jan 24, 2011

+1 for this.

FYI, in IE

<a ... />

is invalid and won't work. You have to do:

<a ...></a>

:(

tmm1 commented Jan 24, 2011

RDiscount already has support for TOCs:

> md = RDiscount.new("# Install", :generate_toc)
 => #<RDiscount:0x101849728 @generate_toc=true, @text="# Install"> 

> md.to_html
 => "<h1 id=\"Install\">Install</h1>\n" 

> md.toc_content
 => "\n <ul>\n <li><a href=\"#Install\">Install</a> </li>\n </ul>\n\n" 

This should be easy to patch to generate <a> tags instead of using <h1 id=...>

tmm1 commented Jan 24, 2011

This patch to RDiscount:

diff --git a/ext/generate.c b/ext/generate.c
index 6840bdf..eb9a2ee 100644
--- a/ext/generate.c
+++ b/ext/generate.c
@@ -1215,12 +1215,12 @@ text(MMIOT *f)
 static void
 printheader(Paragraph *pp, MMIOT *f)
 {
-    Qprintf(f, "<h%d", pp->hnumber);
     if ( f->flags & TOC ) {
-       Qprintf(f, " id=\"", pp->hnumber);
+       Qprintf(f, "<a name=\"", pp->hnumber);
        mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f);
-       Qchar('"', f);
+       Qprintf(f, "\"></a>\n");
     }
+    Qprintf(f, "<h%d", pp->hnumber);
     Qchar('>', f);
     push(T(pp->text->text), S(pp->text->text), f);
     text(f);

lets it use <a> instead:

> md = RDiscount.new("# Install", :generate_toc)
 => #<RDiscount:0x10036a690 @text="# Install", @generate_toc=true> 

> md.to_html
 => "<a name=\"Install\"></a>\n<h1>Install</h1>\n" 

Ideally, though, the patch would instead be applied upstream to Discount and then pulled into RDiscount via the rake gather task. Otherwise these changes will just get blown away next time RDiscount updates its Discount dependency.

Contributor

rtomayko commented Jan 25, 2011

Applied to rdiscount master:

davidfstr/rdiscount@ea79c12^...96875c8

This has also been applied upstream:

Orc/discount@27bb206

I need to do some testing on linux at least before putting out the first rdiscount 2.x release.

benatkin commented May 6, 2011

Back to square one ;)

It was worth it, though - syntax highlighting FTW!

So can we use anchors or TOC's in README.md files now?

@ge0ffrey Not yet. Here's the code for a header in README.md of this repo:

<p>We use this library on GitHub when rendering your README or any other
rich text file.</p> 

<h2>Markups</h2> 

<p>The following markups are supported.  The dependencies listed are required if
you wish to run the library.</p> 

Nice and simple...doesn't support links, though.

+1 to getting anchor links. Our README.md file is getting to big for people to read without a TOC with links to anchors.

+5! come on, this is basic. you've got a nice wiki, you've got a nice tracker, you got nice version control... the versionc control is talking to the tickets, now the tickets need to tie to the wiki. everyone can see where the spec became a ticket became code became.... ah, needs automated test scripts. well, baby steps!

benatkin commented Jul 4, 2011

I'm right there with you, @FairchildHeavyIndustries. It would help with integration immensely. Half the time when I link to Wikipedia I link to subheadings.

Actually that's probably a part of it - it wouldn't be useful to very many without a way to get an anchor tag besides firing up a web inspector. I'm not too crazy about TOCs for short single web pages. It could also be a problem for pages where there are a ton of headers. I'm partial to the links that show up when you hover over paragraphs in Docco. Maybe something like that just for headers on github READMEs and wikis would be useful and not too obtrusive. Another idea is a button to show a TOC.

nazgob commented Jul 26, 2011

+1

tpope commented Sep 18, 2011

I don't understand the status of the RDiscount solution, but it took like 5 minutes and 3 lines of code to bolt in on after the fact:

diff --git a/lib/github/markups.rb b/lib/github/markups.rb
index 739b61a..90eb17a 100644
--- a/lib/github/markups.rb
+++ b/lib/github/markups.rb
@@ -1,5 +1,8 @@
 markup(:markdown, /md|mkdn?|mdown|markdown/) do |content|
-  Markdown.new(content).to_html
+  Markdown.new(content).to_html.gsub(/<h([1-6])>(.*?)<\/h\1>/) do |original|
+    anchor = $2.gsub(/<.*?>/, '').gsub(/[^[:alnum:]]+/, '-').downcase
+    %(<a name="#{anchor}"></a>\n#{original})
+  end
 end

 markup(:redcloth, /textile/) do |content|
diff --git a/test/markups/README.markdown b/test/markups/README.markdown
index b36565c..90a9b1b 100644
--- a/test/markups/README.markdown
+++ b/test/markups/README.markdown
@@ -1,2 +1,3 @@
+# Zero
 * One
 * Two
diff --git a/test/markups/README.markdown.html b/test/markups/README.markdown.ht
index a1b9aba..8123213 100644
--- a/test/markups/README.markdown.html
+++ b/test/markups/README.markdown.html
@@ -1,3 +1,6 @@
+<a name="zero"></a>
+<h1>Zero</h1>
+
 <ul>
 <li>One</li>
 <li>Two</li>

ojak commented Oct 19, 2011

+1 Shouldn't be too tough to give all markdown file anchors a namespace on display?

rmzelle commented Oct 27, 2011

+1

cbeams commented Jan 24, 2012

+1

Oh yeah, it would be awesome!

+1, seriously

+1, hard.

I'm a tech writer, and this would make documentation on Github significantly easier to navigate for my readers.

+1 I'm on!

@technoweenie @rtomayko Do you want a patch similar to what tpope had? I would like to get support for this feature as well.

What about repeated headers? Like, for instance, two h1s for API calls containing h2s that say "Request" and "Response".

Contributor

dabrahams commented Mar 18, 2012

on Sat Mar 17 2012, Benjamin Atkin <reply+i-190399-65dc3241e70f11fc371e342c329951a78781b1c6-44065-AT-reply.github.com> wrote:

What about repeated headers? Like, for instance, two h1s for API calls containing h2s that say "Request" and "Response".

Add a number at the end

+1

+1
Anchors for markdown files are incredibly important for usability, otherwise you get pages that are far too long and difficult to navigate.

Dru89 commented Apr 13, 2012

What about repeated headers? Like, for instance, two h1s for API calls containing h2s that say "Request" and "Response".

Add a number at the end

Or you could just as easily not care about what the actual id tag is, as long as you're keeping references to it. For instance, <h2>Response</h2> may just become some hash like <h2 id='a4f432e-38er-2838-187'>Response</h2> as long as it works and keeps the same reference.

@Dru89, the obvious difficulty with that is providing links to specific sub-sections. Even if the contents of the ID are deterministic, renaming a header could potentially change the ID and thus break all references to it.

Of course this issue exists with placing an incremental number at the end of the header string, but I think your proposal has a much higher chance of breaking stuff.

ivank commented Apr 24, 2012

+1 !!!

Common guys - you could just make a toc or a headers outline like the they have in Rails Guides - generated automatically or something.

Contributor

rtomayko commented Apr 24, 2012

This is fixed and in production on github.com.

There will be no TOC without it being opt in. We're not sure how best to do that yet. First step will likely be to have a hashmark appear when hovering over a header. We're experimenting.

rtomayko closed this Apr 24, 2012

🍰

Contributor

dabrahams commented Apr 25, 2012

Nicely done! I thought id="..." attributes were the modern way of doing this stuff, but whatever, as long as it works.

ivank commented May 11, 2012

Do you have any idea where is the switch to activate the TOC? is it some kind of custom GFM code or an option in the admin? I would really love this feature

If you could extend this to the github wiki's too, that would be great. for any reason you'd want to link directly to a header in a readme, it's even more so in a wiki.

@ivank I think you're on the wrong issue thread 😄

I agree with @jrochkind
This should also be availabile in the wiki's

current workaround is to manually put
<a name='A'/> before/after a header
and llink to it with
[A](#A)

dmtrs commented Feb 19, 2013

+1 +1 +1

@jrochkind 👍

Whatever happened to common sense here?

tobeportable referenced this issue in cjohansen/makeup Mar 5, 2013

Open

toc #2

I have noticed that this is now also available on the wiki's?

Is this available as an option when using GitHub::Markup.render(source, File.read(source)) ?

Owner

gjtorikian commented Feb 5, 2015

Hey @sanderson-sfdc! In the time between this issue and now, we moved our Markdown rendering over to use html-pipeline for "extended" Markdown behaviors. By extended I mean stuff like linkifying the headers (like here), syntax highlighting code examples, coverting emoji, etc. Basically anything beyond the usual "bold/italic" stuff you get our of regular Markdown.

html-pipeline is a series of filters that passes content from one filter to another, and the MarkdownFilter natively uses this gem to rendering markdown. The smallest filter sequence to turn markdown into HTML, and linkify headers, would be:

require 'html/pipeline'

pipeline = HTML::Pipeline.new [
  HTML::Pipeline::MarkdownFilter,
  HTML::Pipeline::TableOfContentsFilter
]
result = pipeline.call(source)
result[:output].to_s

Heya Garen! Thanks for the tip, that's exactly what I did and it works great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment