Add support for github task lists (aka checkboxes)  actually fixes dart-lang/markdown#268  add color swatch syntax support (dart-lang/markdown#428)

* change source of emojis to github api

* add github checkboxes and color syntax

* update change log

* update extension sets

* correct change log

* clean up, rename color_syntax.dart to color_swatch_syntax.dart

* remove unintentional emoji changes

* restore to master version

* restore to master version

* move ColorSwatchSyntax to gitHubWeb extension set

* add exports for new syntaxes

* made requested changes

* clean up so variables and comments as code review suggested
diff --git a/pkgs/markdown/CHANGELOG.md b/pkgs/markdown/CHANGELOG.md
index 4c8ad47..1172756 100644
--- a/pkgs/markdown/CHANGELOG.md
+++ b/pkgs/markdown/CHANGELOG.md
@@ -1,6 +1,14 @@
 ## 6.0.0-dev
 
-* Change emoji list do be derived from the GitHub API. The only two emoji that visually change are `:cricket:` and `:beetle:`. There are alternate emoji `:cricket_game:` and `:lady_beetle:` which can be used to access the previous emoji.  `update_github_emoji.dart` now pulls all emoji info directly from GitHub API and as a result we have now support the entire GitHub emoji set (excluding the 19 custom GitHub specific emoji which have no Unicode support).
+* Add support to GFM extension for GitHub task lists (aka checkboxes).  These
+  are only active in the `gitHubFlavored` and `gitHubWeb` extension sets.
+* Add support for `#ff0000` color swatches.
+* Change emoji list do be derived from the GitHub API. The only two emoji that
+  visually change are `:cricket:` and `:beetle:`. There are alternate emoji
+  `:cricket_game:` and `:lady_beetle:` which can be used to access the previous
+  emoji.  `update_github_emoji.dart` now pulls all emoji info directly from
+  GitHub API and as a result we have now support the entire GitHub emoji set
+  (excluding the 19 custom GitHub specific emoji which have no Unicode support).
 * **Breaking change**: The `TagSyntax` is _deprecated_.
 * Add new syntax `DelimiterSyntax`.
 * **Breaking change**: `StrikethroughSyntax` now extends `DelimiterSyntax`
diff --git a/pkgs/markdown/example/index.html b/pkgs/markdown/example/index.html
index 97515c6..82650a6 100644
--- a/pkgs/markdown/example/index.html
+++ b/pkgs/markdown/example/index.html
@@ -10,6 +10,34 @@
     <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/dart.min.js" integrity="sha512-14QR6tzX5xTNeMJKXzSK+xCquDvtNEr1jM5NlKy/149BBY50Kv70qqxHtzo6zClbtc1gIG7G0CGWXuMgPIMt0g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
     <script defer src="app.dart.js"></script>
     <title>Dart Markdown Live Editor</title>
+    <style>
+.gfm-color_chip span {
+  display: inline-block;
+  line-height: 1;
+  margin: 0 0 2px 4px;
+  vertical-align: middle;
+  border-radius: 3px;
+  width: 0.9em;
+  height: 0.9em;
+  background: #fff;
+}
+
+code.gfm-color_chip {
+  padding: 2px 4px;
+  color: #1f1f1f;
+  background-color: #f0f0f0;
+  border-radius: 4px;
+}
+
+ul.contains-task-list, ol.contains-task-list {
+  margin-left: -1em;
+  list-style-type: none;
+}
+
+.task-list-item {
+  list-style-type: none;
+}
+    </style>
   </head>
   <body>
     <div class="container">
diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart
index 205ba38..6155242 100644
--- a/pkgs/markdown/lib/markdown.dart
+++ b/pkgs/markdown/lib/markdown.dart
@@ -53,12 +53,14 @@
 export 'src/block_syntaxes/list_syntax.dart';
 export 'src/block_syntaxes/long_block_html_syntax.dart';
 export 'src/block_syntaxes/ordered_list_syntax.dart';
+export 'src/block_syntaxes/ordered_list_with_checkbox_syntax.dart';
 export 'src/block_syntaxes/other_tag_block_html_syntax.dart';
 export 'src/block_syntaxes/paragraph_syntax.dart';
 export 'src/block_syntaxes/setext_header_syntax.dart';
 export 'src/block_syntaxes/setext_header_with_id_syntax.dart';
 export 'src/block_syntaxes/table_syntax.dart';
 export 'src/block_syntaxes/unordered_list_syntax.dart';
+export 'src/block_syntaxes/unordered_list_with_checkbox_syntax.dart';
 export 'src/document.dart';
 export 'src/emojis.dart';
 export 'src/extension_set.dart';
@@ -67,6 +69,7 @@
 export 'src/inline_syntaxes/autolink_extension_syntax.dart';
 export 'src/inline_syntaxes/autolink_syntax.dart';
 export 'src/inline_syntaxes/code_syntax.dart';
+export 'src/inline_syntaxes/color_swatch_syntax.dart';
 export 'src/inline_syntaxes/delimiter_syntax.dart';
 export 'src/inline_syntaxes/email_autolink_syntax.dart';
 export 'src/inline_syntaxes/emoji_syntax.dart';
diff --git a/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart
index 06b1cf9..483a0d8 100644
--- a/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart
+++ b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart
@@ -14,6 +14,14 @@
   final List<String> lines;
 }
 
+/// Invisible string used to placehold for an *unchecked* CheckBox.
+/// The character is Unicode Zero Width Space (U+200B).
+const indicatorForUncheckedCheckBox = '\u{200B}';
+
+/// Invisible string used to placehold for a *checked* CheckBox.
+/// This is 2 Unicode Zero Width Space (U+200B) characters.
+const indicatorForCheckedCheckBox = '\u{200B}\u{200B}';
+
 /// Base class for both ordered and unordered lists.
 abstract class ListSyntax extends BlockSyntax {
   @override
@@ -49,6 +57,8 @@
   Node parse(BlockParser parser) {
     final items = <ListItem>[];
     var childLines = <String>[];
+    final isCheckboxListSubclass =
+        (listTag == 'ol_with_checkbox' || listTag == 'ul_with_checkbox');
 
     void endItem() {
       if (childLines.isNotEmpty) {
@@ -57,10 +67,10 @@
       }
     }
 
-    late Match? match;
+    late Match? possibleMatch;
     bool tryMatch(RegExp pattern) {
-      match = pattern.firstMatch(parser.current);
-      return match != null;
+      possibleMatch = pattern.firstMatch(parser.current);
+      return possibleMatch != null;
     }
 
     String? listMarker;
@@ -89,16 +99,43 @@
       } else if (tryMatch(hrPattern)) {
         // Horizontal rule takes precedence to a new list item.
         break;
-      } else if (tryMatch(ulPattern) || tryMatch(olPattern)) {
-        final precedingWhitespace = match![1]!;
-        final digits = match![2] ?? '';
+      } else if ((isCheckboxListSubclass &&
+              (tryMatch(ulWithCheckBoxPattern) ||
+                  tryMatch(olWithCheckBoxPattern))) ||
+          tryMatch(ulPattern) ||
+          tryMatch(olPattern)) {
+        // We know we have a valid [possibleMatch] now, so capture it.
+        final successfulMatch = possibleMatch!;
+        // The checkbox "subclass" patterns ([ulWithCheckBoxPattern] and
+        // [olWithCheckBoxPattern]) have 2 extra capturing groups at the 5
+        // position to capture the checkbox. These shift the other groups
+        // forward by 2 slots.
+        final cbGroupOffset = isCheckboxListSubclass ? 2 : 0;
+        final precedingWhitespace = successfulMatch[1]!;
+        final digits = successfulMatch[2] ?? '';
         if (startNumber == null && digits.isNotEmpty) {
           startNumber = int.parse(digits);
         }
-        final marker = match![3]!;
-        final firstWhitespace = match![5] ?? '';
-        final restWhitespace = match![6] ?? '';
-        final content = match![7] ?? '';
+        final marker = successfulMatch[3]!;
+        // [checkBoxIndicator] is always empty unless a checkbox was found.
+        String checkBoxIndicator = '';
+        if (isCheckboxListSubclass) {
+          // Look at checkbox capture group and get checkbox state.
+          // If we find a checked or unchecked checkbox then we will
+          // set [checkBoxIndicator] to one of our invisible
+          // codes that we can later detect to know if we need to insert
+          // a check or unchecked checkbox when we are inserting the
+          // listitem li node.
+          final String checkboxGroup = successfulMatch[5]!.toLowerCase();
+          if (checkboxGroup == '[ ]') {
+            checkBoxIndicator = indicatorForUncheckedCheckBox;
+          } else if (checkboxGroup == '[x]') {
+            checkBoxIndicator = indicatorForCheckedCheckBox;
+          }
+        }
+        final firstWhitespace = successfulMatch[5 + cbGroupOffset] ?? '';
+        final restWhitespace = successfulMatch[6 + cbGroupOffset] ?? '';
+        final content = successfulMatch[7 + cbGroupOffset] ?? '';
         final isBlank = content.isEmpty;
         if (listMarker != null && listMarker != marker) {
           // Changing the bullet or ordered list delimiter starts a new list.
@@ -128,7 +165,7 @@
         }
         // End the current list item and start a new one.
         endItem();
-        childLines.add(restWhitespace + content);
+        childLines.add('$checkBoxIndicator$restWhitespace$content');
       } else if (BlockSyntax.isAtBlockEnd(parser)) {
         // Done with the list.
         break;
@@ -156,7 +193,30 @@
     for (final item in items) {
       final itemParser = BlockParser(item.lines, parser.document);
       final children = itemParser.parseLines();
-      itemNodes.add(Element('li', children));
+      // If this is a checkbox sublass of ListSyntax then we must check
+      // for possible invisible checkbox placeholder characters at
+      // the start of first node's text to see if we need to insert a checkbox.
+      Element? checkboxToInsert;
+      if (isCheckboxListSubclass) {
+        if (children.isNotEmpty) {
+          if (children.first.textContent
+              .startsWith(indicatorForCheckedCheckBox)) {
+            checkboxToInsert = Element.withTag('input')
+              ..attributes['type'] = 'checkbox'
+              ..attributes['checked'] = 'true';
+          } else if (children.first.textContent
+              .startsWith(indicatorForUncheckedCheckBox)) {
+            checkboxToInsert = Element.withTag('input')
+              ..attributes['type'] = 'checkbox';
+          }
+        }
+      }
+      if (checkboxToInsert != null) {
+        itemNodes.add(Element('li', [checkboxToInsert, ...children])
+          ..attributes['class'] = 'task-list-item');
+      } else {
+        itemNodes.add(Element('li', children));
+      }
       anyEmptyLinesBetweenBlocks =
           anyEmptyLinesBetweenBlocks || itemParser.encounteredBlankLine;
     }
@@ -182,7 +242,17 @@
       }
     }
 
-    if (listTag == 'ol' && startNumber != 1) {
+    if (listTag == 'ol_with_checkbox') {
+      final olWithCheckbox = Element('ol', itemNodes)
+        ..attributes['class'] = 'contains-task-list';
+      if (startNumber != 1) {
+        olWithCheckbox.attributes['start'] = '$startNumber';
+      }
+      return olWithCheckbox;
+    } else if (listTag == 'ul_with_checkbox') {
+      return Element('ul', itemNodes)
+        ..attributes['class'] = 'contains-task-list';
+    } else if (listTag == 'ol' && startNumber != 1) {
       return Element(listTag, itemNodes)..attributes['start'] = '$startNumber';
     } else {
       return Element(listTag, itemNodes);
diff --git a/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart
new file mode 100644
index 0000000..2f8a66a
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../patterns.dart';
+import 'list_syntax.dart';
+
+/// Parses ordered lists.
+class OrderedListWithCheckBoxSyntax extends ListSyntax {
+  @override
+  RegExp get pattern => olWithCheckBoxPattern;
+
+  @override
+  String get listTag => 'ol_with_checkbox';
+
+  const OrderedListWithCheckBoxSyntax();
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart
new file mode 100644
index 0000000..795d8a7
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../patterns.dart';
+import 'list_syntax.dart';
+
+/// Parses unordered lists.
+class UnorderedListWithCheckBoxSyntax extends ListSyntax {
+  @override
+  RegExp get pattern => ulWithCheckBoxPattern;
+
+  @override
+  String get listTag => 'ul_with_checkbox';
+
+  const UnorderedListWithCheckBoxSyntax();
+}
diff --git a/pkgs/markdown/lib/src/extension_set.dart b/pkgs/markdown/lib/src/extension_set.dart
index c0e0b13..7f2be48 100644
--- a/pkgs/markdown/lib/src/extension_set.dart
+++ b/pkgs/markdown/lib/src/extension_set.dart
@@ -1,9 +1,13 @@
+import 'package:markdown/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart';
+import 'package:markdown/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart';
+
 import 'block_syntaxes/block_syntax.dart';
 import 'block_syntaxes/fenced_code_block_syntax.dart';
 import 'block_syntaxes/header_with_id_syntax.dart';
 import 'block_syntaxes/setext_header_with_id_syntax.dart';
 import 'block_syntaxes/table_syntax.dart';
 import 'inline_syntaxes/autolink_extension_syntax.dart';
+import 'inline_syntaxes/color_swatch_syntax.dart';
 import 'inline_syntaxes/emoji_syntax.dart';
 import 'inline_syntaxes/inline_html_syntax.dart';
 import 'inline_syntaxes/inline_syntax.dart';
@@ -56,6 +60,8 @@
         const HeaderWithIdSyntax(),
         const SetextHeaderWithIdSyntax(),
         const TableSyntax(),
+        const UnorderedListWithCheckBoxSyntax(),
+        const OrderedListWithCheckBoxSyntax(),
       ],
     ),
     List<InlineSyntax>.unmodifiable(
@@ -63,6 +69,7 @@
         InlineHtmlSyntax(),
         StrikethroughSyntax(),
         EmojiSyntax(),
+        ColorSwatchSyntax(),
         AutolinkExtensionSyntax()
       ],
     ),
@@ -75,6 +82,8 @@
       <BlockSyntax>[
         const FencedCodeBlockSyntax(),
         const TableSyntax(),
+        const UnorderedListWithCheckBoxSyntax(),
+        const OrderedListWithCheckBoxSyntax(),
       ],
     ),
     List<InlineSyntax>.unmodifiable(
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart
new file mode 100644
index 0000000..0998d74
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches code blocks containing a subset of CSS color syntax.
+class ColorSwatchSyntax extends InlineSyntax {
+  /// This pattern matches:
+  /// * GitHub Flavored Markup supports fewer of these options, GitLab Flavored
+  ///   Markup supports all of these. Presumably GitHub will be more complete at
+  ///   some point.
+  /// * CSS style '#' prefixed color hex codes in 3,4,6 or 8 digits in length.
+  /// * CSS style RGB()/RgbA()/Hsl()/HSLA() style color declarations, of any
+  ///   capitalization.
+  /// EXAMPLES:
+  /// * `#f00`
+  /// * `#BA`        (2 digit hex, regex will not match)
+  /// * `#F00a`
+  /// * `#F0BAD`     (5 digit hex, regex will not match)
+  /// * `#FF0000`
+  /// * `#F000BAD`   (7 digit hex, regex will not match)
+  /// * `#FF0000aA`    (GitHub supports only this style)
+  /// * `RGB(0,255,0)`
+  /// * `rgb(0,255,0)`
+  /// * `RGB(0%,100%,0%)`
+  /// * `rgb(0%,100%,0%)`
+  /// * `RGBA(0,255,0,0.3)`
+  /// * `rgba(0,255,0,0.3)`
+  /// * `HSL(540,70%,50%)`
+  /// * `hsl(540,70%,50%)`
+  /// * `HSLA(540,70%,50%,0.3)`
+  /// * `Hsla(540,70%,50%,0.3)`
+  static final String _pattern =
+      '`((#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}))|'
+      r'([Rr][Gg][Bb][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\))|'
+      r'([Hh][Ss][Ll][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\)))`';
+
+  ColorSwatchSyntax() : super(_pattern);
+
+  @override
+  bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+    if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) {
+      // Not really a match! We can't just sneak past one backtick to try the
+      // next character. An example of this situation would be:
+      //
+      //     before ``` and `` after.
+      //             ^--parser.pos
+      return false;
+    }
+
+    final match = pattern.matchAsPrefix(parser.source, parser.pos);
+    if (match == null) {
+      return false;
+    }
+    parser.writeText();
+    if (onMatch(parser, match)) parser.consume(match.match.length);
+    return true;
+  }
+
+  @override
+  bool onMatch(InlineParser parser, Match match) {
+    var code = match[1]!.trim().replaceAll('\n', ' ');
+
+    if (parser.encodeHtml) code = escapeHtml(code);
+
+    parser.addNode(Element('code', [
+      Text(code),
+      Element.withTag('span')..attributes['style'] = 'background-color:$code;',
+    ])
+      ..attributes['class'] = 'gfm-color_chip');
+
+    return true;
+  }
+}
diff --git a/pkgs/markdown/lib/src/patterns.dart b/pkgs/markdown/lib/src/patterns.dart
index 4ddc184..f2aa7d8 100644
--- a/pkgs/markdown/lib/src/patterns.dart
+++ b/pkgs/markdown/lib/src/patterns.dart
@@ -35,15 +35,29 @@
 /// three leading spaces before the marker and any number of spaces or tabs
 /// after.
 ///
-/// Contains a dummy group at [2], so that the groups in [ulPattern] and
-/// [olPattern] match up; in both, [2] is the length of the number that begins
+/// Contains a dummy group at `[2]`, so that the groups in [ulPattern] and
+/// [olPattern] match up; in both, `[2]` is the length of the number that begins
 /// the list marker.
 final ulPattern = RegExp(r'^([ ]{0,3})()([*+-])(([ \t])([ \t]*)(.*))?$');
 
+/// Similar to [ulPattern] but with a GitHub style checkbox
+/// `'[ ]'|'[x]'|'[X]'` following the number. The checkbox will
+/// be grabbed by group `[5]` and [ulPattern]'s groups `[5,6,7]` are all
+/// shifted 2 places to be `[7,8,9]`
+final ulWithCheckBoxPattern = RegExp(
+    r'^([ ]{0,3})()([*+-])([ \t]{0,4})(\[[ xX]{1}\])(([ \t])([ \t]*)(.*))?$');
+
 /// A line starting with a number like `123.`. May have up to three leading
 /// spaces before the marker and any number of spaces or tabs after.
 final olPattern = RegExp(r'^([ ]{0,3})(\d{1,9})([\.)])(([ \t])([ \t]*)(.*))?$');
 
+/// Similar to [olPattern] but with a GitHub style checkbox
+/// `'[ ]'|'[x]'|'[X]'` following the number. The checkbox will
+/// be grabbed by group `[5]` and [olPattern]'s groups `[5,6,7]` are all
+/// shifted 2 places to be `[7,8,9]`
+final olWithCheckBoxPattern = RegExp(
+    r'^([ ]{0,3})(\d{1,9})([\.)])([ \t]{0,4})(\[[ xX]{1}\])(([ \t])([ \t]*)(.*))?$');
+
 /// A line of hyphens separated by at least one pipe.
 final tablePattern = RegExp(
     r'^[ ]{0,3}\|?([ \t]*:?\-+:?[ \t]*\|)+([ \t]|[ \t]*:?\-+:?[ \t]*)?$');