Skip to content

Instantly share code, notes, and snippets.

@jakejscott
Last active March 16, 2016 22:33
Show Gist options
  • Select an option

  • Save jakejscott/dfd22a747919c4d7042e to your computer and use it in GitHub Desktop.

Select an option

Save jakejscott/dfd22a747919c4d7042e to your computer and use it in GitHub Desktop.

Revisions

  1. jakejscott revised this gist Mar 16, 2016. 1 changed file with 108 additions and 0 deletions.
    108 changes: 108 additions & 0 deletions Slug.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    using System;
    using System.Text;

    namespace ConsoleApp
    {
    public static class Slug
    {
    public static string Create(bool toLower, params string[] values)
    {
    return Create(toLower, String.Join("-", values));
    }

    public static string Create(bool toLower, string value)
    {
    if (value == null) return "";

    var normalised = value.Normalize(NormalizationForm.FormKD);

    const int maxlen = 80;
    int len = normalised.Length;
    bool prevDash = false;
    var sb = new StringBuilder(len);
    char c;

    for (int i = 0; i < len; i++)
    {
    c = normalised[i];
    if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
    {
    if (prevDash)
    {
    sb.Append('-');
    prevDash = false;
    }
    sb.Append(c);
    }
    else if (c >= 'A' && c <= 'Z')
    {
    if (prevDash)
    {
    sb.Append('-');
    prevDash = false;
    }
    // tricky way to convert to lowercase
    if (toLower)
    sb.Append((char)(c | 32));
    else
    sb.Append(c);
    }
    else if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-' || c == '_' || c == '=')
    {
    if (!prevDash && sb.Length > 0)
    {
    prevDash = true;
    }
    }
    else
    {
    string swap = ConvertEdgeCases(c, toLower);

    if (swap != null)
    {
    if (prevDash)
    {
    sb.Append('-');
    prevDash = false;
    }
    sb.Append(swap);
    }
    }

    if (sb.Length == maxlen) break;
    }

    return sb.ToString();
    }

    static string ConvertEdgeCases(char c, bool toLower)
    {
    string swap = null;
    switch (c)
    {
    case 'ı':
    swap = "i";
    break;
    case 'ł':
    swap = "l";
    break;
    case 'Ł':
    swap = toLower ? "l" : "L";
    break;
    case 'đ':
    swap = "d";
    break;
    case 'ß':
    swap = "ss";
    break;
    case 'ø':
    swap = "o";
    break;
    case 'Þ':
    swap = "th";
    break;
    }
    return swap;
    }
    }
    }
  2. jakejscott created this gist Mar 16, 2016.
    114 changes: 114 additions & 0 deletions MarkdownTable.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,114 @@
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using CommonMark;
    using CommonMark.Formatters;
    using CommonMark.Syntax;

    namespace ConsoleApp
    {
    public class Program
    {
    // blocks are elemets like paragraphs and lists, inlines are
    // elements like emphasis, links, images.

    public static void Main(string[] args)
    {
    CommonMarkSettings.Default.OutputDelegate = (document, textWriter, settings) =>
    {
    var formatter = new CustomHtmlFormatter(document, textWriter, settings);
    formatter.WriteDocument(document);
    };

    using (var reader = new StreamReader("./README.md"))
    {
    var document = CommonMarkConverter.Parse(reader);

    using (var writer = new StringWriter())
    {
    // write the HTML output
    CommonMarkConverter.ProcessStage3(document, writer);
    Console.WriteLine(writer.ToString());
    }
    }

    Console.ReadLine();
    }

    private class CustomHtmlFormatter : HtmlFormatter
    {
    private readonly List<EnumeratorEntry> headings;

    public CustomHtmlFormatter(Block block, TextWriter target, CommonMarkSettings settings)
    : base(target, settings)
    {
    headings = block.AsEnumerable().Where(
    x => x.IsOpening &&
    x.Block != null &&
    x.Block.Tag == BlockTag.AtxHeading &&
    x.Block.InlineContent != null
    ).ToList();
    }

    protected override void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes)
    {
    if (block.Tag == BlockTag.AtxHeading && block.InlineContent != null)
    {
    //
    // Add anchorable id to each heading
    //

    ignoreChildNodes = false;

    if (isOpening)
    {
    var slug = Slug.Create(true, block.InlineContent.LiteralContent);
    Write(string.Format("<h{0} id=\"{1}\">", block.Heading.Level, slug));
    }

    if (isClosing)
    {
    Write(string.Format("</h{0}>", block.Heading.Level));
    }
    }
    else if (block.Tag == BlockTag.Paragraph && block.InlineContent != null && block.InlineContent.LiteralContent == "{:toc}" && headings.Any())
    {
    //
    // Injects a table of contents.
    //

    ignoreChildNodes = true;

    if (isOpening)
    {
    WriteLine();
    Write("<ul>");

    foreach (var heading in headings)
    {
    var text = heading.Block.InlineContent.LiteralContent;
    var slug = Slug.Create(true, text);

    WriteLine();
    Write(string.Format("<li href=\"#{0}\">", slug));
    Write(text);
    Write("</li>");
    }
    }

    if (isClosing)
    {
    WriteLine();
    Write("</ul>");
    WriteLine();
    }
    }
    else
    {
    base.WriteBlock(block, isOpening, isClosing, out ignoreChildNodes);
    }
    }
    }
    }
    }