Address old line-splitting TODO (#4351)

diff --git a/lib/src/io.dart b/lib/src/io.dart
index 218b228..f65919f 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -21,7 +21,6 @@
 import 'package:path/path.dart' as p;
 import 'package:pool/pool.dart';
 import 'package:stack_trace/stack_trace.dart';
-// ignore: prefer_relative_imports
 import 'package:tar/tar.dart';
 
 import 'error_group.dart';
@@ -1240,8 +1239,12 @@
 
   // TODO(rnystrom): Remove this and change to returning one string.
   static List<String> _toLines(String output) {
-    final lines = splitLines(output);
-    if (lines.isNotEmpty && lines.last == '') lines.removeLast();
+    final lines = const LineSplitter().convert(output);
+
+    if (lines.isNotEmpty && lines.last == '') {
+      lines.removeLast();
+    }
+
     return lines;
   }
 
diff --git a/lib/src/log.dart b/lib/src/log.dart
index 94db39f..ee39cda 100644
--- a/lib/src/log.dart
+++ b/lib/src/log.dart
@@ -232,15 +232,7 @@
 
 /// Logs [message] at [level].
 void write(Level level, String message) {
-  message = message.toString();
-  final lines = splitLines(message);
-
-  // Discard a trailing newline. This is useful since StringBuffers often end
-  // up with an extra newline at the end from using [writeln].
-  if (lines.isNotEmpty && lines.last == '') {
-    lines.removeLast();
-  }
-
+  final lines = const LineSplitter().convert(message);
   final entry = _Entry(level, lines);
 
   final logFn = verbosity._loggers[level];
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index fe981a7..efb1c70 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -381,15 +381,6 @@
 
 Uint8List hexDecode(String string) => hex.decode(string) as Uint8List;
 
-/// A regular expression matching a trailing CR character.
-final _trailingCR = RegExp(r'\r$');
-
-// TODO(nweiz): Use `text.split(new RegExp("\r\n?|\n\r?"))` when issue 9360 is
-// fixed.
-/// Splits [text] on its line breaks in a Windows-line-break-friendly way.
-List<String> splitLines(String text) =>
-    text.split('\n').map((line) => line.replaceFirst(_trailingCR, '')).toList();
-
 /// Like [String.split], but only splits on the first occurrence of the pattern.
 ///
 /// This always returns an array of two elements or fewer.
diff --git a/test/test_pub.dart b/test/test_pub.dart
index 463b4dc..bdc36cc 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -1130,7 +1130,7 @@
 /// of maps, one of them having the property `k` with value `v`, recurse into
 /// that map.
 ///
-/// Cast the result as a `<T>`.
+/// Cast the result as a [T].
 T dig<T>(dynamic json, List<dynamic> path) {
   for (var i = 0; i < path.length; i++) {
     switch (path[i]) {