Fix CR LF in .gitignore / .pubignore (#3026)

diff --git a/lib/src/ignore.dart b/lib/src/ignore.dart
index be898f2..307e652 100644
--- a/lib/src/ignore.dart
+++ b/lib/src/ignore.dart
@@ -99,8 +99,11 @@
     Iterable<String> patterns, {
     bool ignoreCase = false,
     void Function(String pattern, FormatException exception) onInvalidPattern,
-  }) : _rules = _parseIgnorePatterns(patterns, ignoreCase,
-            onInvalidPattern: onInvalidPattern);
+  }) : _rules = _parseIgnorePatterns(
+          patterns,
+          ignoreCase,
+          onInvalidPattern: onInvalidPattern,
+        ).toList(growable: false);
 
   /// Returns `true` if [path] is ignored by the patterns used to create this
   /// [Ignore] instance, assuming those patterns are placed at `.`.
@@ -335,27 +338,32 @@
   }
 }
 
+/// Pattern for a line-break which accepts CR LF and LF.
+final _lineBreakPattern = RegExp('\r?\n');
+
 /// [onInvalidPattern] can be used to handle parse failures. If
 /// [onInvalidPattern] is `null` invalid patterns are ignored.
-List<_IgnoreRule> _parseIgnorePatterns(
+Iterable<_IgnoreRule> _parseIgnorePatterns(
   Iterable<String> patterns,
   bool ignoreCase, {
   void Function(String pattern, FormatException exception) onInvalidPattern,
-}) {
+}) sync* {
   ArgumentError.checkNotNull(patterns, 'patterns');
   ArgumentError.checkNotNull(ignoreCase, 'ignoreCase');
+  onInvalidPattern ??= (_, __) => null;
 
   final parsedPatterns = patterns
-      .map((s) => s.split('\n'))
-      .expand((e) => e)
+      .expand((s) => s.split(_lineBreakPattern))
       .map((pattern) => _parseIgnorePattern(pattern, ignoreCase));
-  if (onInvalidPattern != null) {
-    for (final invalidResult
-        in parsedPatterns.where((result) => !result.valid)) {
-      onInvalidPattern(invalidResult.pattern, invalidResult.exception);
+
+  for (final r in parsedPatterns) {
+    if (!r.valid) {
+      onInvalidPattern(r.pattern, r.exception);
+    }
+    if (!r.empty) {
+      yield r.rule;
     }
   }
-  return parsedPatterns.where((r) => !r.empty).map((r) => r.rule).toList();
 }
 
 _IgnoreParseResult _parseIgnorePattern(String pattern, bool ignoreCase) {
diff --git a/test/ignore_test.dart b/test/ignore_test.dart
index a925990..fb613c4 100644
--- a/test/ignore_test.dart
+++ b/test/ignore_test.dart
@@ -195,6 +195,43 @@
   }, {
     'README.md': false,
   }),
+  // Patterns given in multiple lines with comments
+  TestData('multiple lines LF', {
+    '.': [
+      '#comment\n/.git/ \n*.o\n',
+      // Using CR CR LF doesn't work
+      '#comment\n*.md\r\r\n',
+      // Tab is not ignored
+      '#comment\nLICENSE\t\n',
+      // Trailing comments not allowed
+      '#comment\nLICENSE  # ignore license\n',
+    ]
+  }, {
+    '.git/config': true,
+    '.git/': true,
+    'README.md': false,
+    'LICENSE': false,
+    'main.c': false,
+    'main.o': true,
+  }),
+  TestData('multiple lines CR LF', {
+    '.': [
+      '#comment\r\n/.git/ \r\n*.o\r\n',
+      // Using CR CR LF doesn't work
+      '#comment\r\n*.md\r\r\n',
+      // Tab is not ignored
+      '#comment\r\nLICENSE\t\r\n',
+      // Trailing comments not allowed
+      '#comment\r\nLICENSE  # ignore license\r\n',
+    ]
+  }, {
+    '.git/config': true,
+    '.git/': true,
+    'README.md': false,
+    'LICENSE': false,
+    'main.c': false,
+    'main.o': true,
+  }),
   // Test simple patterns
   TestData.single('file.txt', {
     'file.txt': true,