diff --git a/lib/ctelnet.dart b/lib/ctelnet.dart index 0d1aaac..57a4f43 100644 --- a/lib/ctelnet.dart +++ b/lib/ctelnet.dart @@ -5,4 +5,3 @@ export 'src/client.dart'; export 'src/message.dart'; export 'src/symbols.dart'; export 'src/builder.dart'; -export 'src/color_parser/color_parser.dart'; diff --git a/lib/src/color_parser/base.dart b/lib/src/color_parser/base.dart deleted file mode 100644 index 6e196da..0000000 --- a/lib/src/color_parser/base.dart +++ /dev/null @@ -1,78 +0,0 @@ -import '../consts.dart' as consts; - -enum Token { - esc, - colorStart, - colorTerm, - colorSeparator, - literal, -} - -class TokenValue { - final Token token; - final String raw; - - const TokenValue(this.token, this.raw); - - static const esc = TokenValue(Token.esc, consts.esc); - static const colorStart = TokenValue(Token.colorStart, '['); - static const colorSeparator = TokenValue(Token.colorSeparator, ';'); - static const colorTerm = TokenValue(Token.colorTerm, 'm'); - static const empty = TokenValue(Token.literal, ''); - - TokenValue.literal(String raw) : this(Token.literal, raw); - - @override - int get hashCode => raw.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is TokenValue && - runtimeType == other.runtimeType && - token == other.token && - raw == other.raw; - - @override - String toString() => token != Token.esc ? '${token.name}($raw)' : token.name; -} - -class LexerValue { - String text; - int fgColor; - int bgColor; - - LexerValue(this.text, this.fgColor, this.bgColor); - - @override - int get hashCode => text.hashCode ^ fgColor.hashCode ^ bgColor.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is LexerValue && - runtimeType == other.runtimeType && - text == other.text && - fgColor == other.fgColor && - bgColor == other.bgColor; - - @override - String toString() => 'Lex("$text", $fgColor:$bgColor)'; -} - -abstract class IReader { - T? read(); - T? peek(); - int get length; - int get index; - bool get isDone; - void setPosition(int originalIndex); -} - -abstract class ITokenizer { - List tokenize(); -} - -abstract class ILexer { - List lex(); -} diff --git a/lib/src/color_parser/color_parser.dart b/lib/src/color_parser/color_parser.dart deleted file mode 100644 index 678cf54..0000000 --- a/lib/src/color_parser/color_parser.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'base.dart'; -export 'reader.dart'; -export 'parser.dart'; diff --git a/lib/src/color_parser/parser.dart b/lib/src/color_parser/parser.dart deleted file mode 100644 index 8e2c463..0000000 --- a/lib/src/color_parser/parser.dart +++ /dev/null @@ -1,264 +0,0 @@ -import 'base.dart'; -import 'reader.dart'; -import '../consts.dart' as consts; - -/// Represents a string value with color information. -/// -/// Can be used to store the text and color information for a single token. -/// -/// Use [ColorToken.formatted] to get the ANSI formatted text, usable in a terminal. -class ColorToken { - /// The raw, uncoded text. - String text; - - /// The foreground color code. - int fgColor; - - /// The background color code. - int bgColor; - - /// Whether the text is bold. - bool bold; - - /// Whether the text is italic. - bool italic; - - /// Whether the text is underlined. - bool underline; - - /// Whether the text is an xterm256 color code. Otherwise, it is a standard color code. - bool xterm256; - - ColorToken({ - required this.text, - required this.fgColor, - required this.bgColor, - this.bold = false, - this.italic = false, - this.underline = false, - this.xterm256 = false, - }); - - /// Create an empty token. - factory ColorToken.empty() => ColorToken(text: '', fgColor: 0, bgColor: 0); - - /// Create a token with default color and the given text. - factory ColorToken.defaultColor(String text) => - ColorToken(text: text, fgColor: 0, bgColor: 0); - - /// Returns true if the text is empty. - bool get isEmpty => text.isEmpty; - - /// Returns true if the text is not empty. - bool get isNotEmpty => !isEmpty; - - /// Get the formatted text as ANSI formatted text. - /// - /// Outputting this value to a terminal will display the text with the correct colors. - /// - /// To format the text in other ways, use the properties to get the [fgColor] and [bgColor], - /// and construct it to whatever format you need. - String get formatted => bgColor == 0 - ? '\x1B[${fgColor}m$text\x1B[0m' - : '\x1B[$fgColor;${bgColor}m$text\x1B[0m'; - - @override - String toString() { - final b = bold ? 'b' : ''; - final i = italic ? 'i' : ''; - final u = underline ? 'u' : ''; - final x = xterm256 ? 'x' : ''; - final flags = '$b$i$u$x'; - return 'ColoredText("$text", $fgColor:$bgColor, $flags)'; - } - - @override - int get hashCode => text.hashCode ^ fgColor.hashCode ^ bgColor.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ColorToken && - runtimeType == other.runtimeType && - text == other.text && - fgColor == other.fgColor && - bgColor == other.bgColor; - - /// Set the style based on the given code. - void setStyle(int code) { - // debugPrint('setStyle: $code'); - if (code == consts.boldByte) { - bold = true; - } else if (code == consts.italicByte) { - italic = true; - } else if (code == consts.underlineByte) { - underline = true; - } - } -} - -/// A parser to parse a string with color codes. -class ColorParser implements IReader { - final IReader reader; - final _tokens = []; - - ColorParser._(this.reader); - - factory ColorParser(String text) => ColorParser._(StringReader(text)); - - /// Parse the text and return a list of [ColorToken]s. - /// - /// Each token represents a piece of text with color information. You can join all the text - /// together (without separators) to get the original text, uncolored. - /// - /// To get the colored text, use the [ColorToken.formatted] property of each token. - List parse() { - final lexed = []; - while (!reader.isDone) { - final token = reader.read(); - var cur = _getToken(token); - lexed.add(cur); - } - return lexed; - } - - ColorToken _getToken(String char) { - var token = ColorToken.empty(); - switch (char) { - case consts.esc: - String? next; - // keep reading until we hit the end of the escape sequence or the end of the string - while (!reader.isDone) { - next = reader.peek(); - if (next == consts.esc) { - break; - } - reader.read(); - if (next == '[') { - final color = _consumeUntil('m'); - reader.read(); - final colors = color.split(';'); - final first = int.tryParse(colors[0]) ?? 0; - final second = colors.length > 1 ? int.tryParse(colors[1]) ?? 0 : 0; - final third = colors.length > 2 ? int.tryParse(colors[2]) ?? 0 : 0; - int fg; - int bg; - if (first < 30) { - token.setStyle(first); - fg = second; - bg = third; - } else { - if (first == 38 && second == 5) { - token.xterm256 = true; - fg = third; - bg = 0; - } else { - fg = first; - bg = second; - } - } - token.fgColor = fg; - token.bgColor = bg; - // if (colors.length == 1) { - // final code = int.tryParse(colors[0]) ?? 0; - // if (code == consts.boldByte) { - // token.bold = true; - // } else if (code == consts.italicByte) { - // token.italic = true; - // } else if (code == consts.underlineByte) { - // token.underline = true; - // } else { - // token.fgColor = int.tryParse(colors[0]) ?? 0; - // } - // } else if (colors.length == 2) { - // final code = int.tryParse(colors[0]) ?? 0; - // if (code < 30) { - // token.fgColor = int.tryParse(colors[1]) ?? 0; - // } else { - // token.fgColor = int.tryParse(colors[1]) ?? 0; - // token.bgColor = int.tryParse(colors[0]) ?? 1; - // } - // } else if (colors.length == 3) { - // if (colors[0] == '38' && colors[1] == '5') { - // token.xterm256 = true; - // token.fgColor = int.tryParse(colors[2]) ?? 0; - // } else { - // token.bgColor = int.tryParse(colors[0]) ?? 1; - // token.fgColor = int.tryParse(colors[1]) ?? 0; - // } - // } - token.text = _consumeUntil(consts.esc); - return token; - } - if (next == null) { - break; - } - token.text += next; - } - return token; - default: - token.text += char; - return token; - } - } - - String _consumeUntil(String char) { - String? next = reader.peek(); - if (next == null) { - return ''; - } - var result = ''; - while (!reader.isDone) { - if (next == char) { - break; - } - next = reader.peek(); - if (next == null) { - break; - } - result += reader.read(); - next = reader.peek(); - } - return result; - } - - // String peekUntil(String char) { - // String? next = reader.peek(); - // if (next == null) { - // return ''; - // } - // var result = ''; - // var originalIndex = reader.index; - // while (!reader.isDone) { - // if (next == char) { - // break; - // } - // next = reader.peek(); - // if (next == null) { - // break; - // } - // result += reader.read(); - // next = reader.peek(); - // } - // reader.setPosition(originalIndex); - // return result; - // } - - @override - int index = 0; - - @override - bool get isDone => index >= reader.length; - - @override - peek() => _tokens[index]; - - @override - read() => _tokens[index++]; - - @override - int get length => _tokens.length; - - @override - setPosition(int position) => index = position; -} diff --git a/lib/src/color_parser/reader.dart b/lib/src/color_parser/reader.dart deleted file mode 100644 index 4e78791..0000000 --- a/lib/src/color_parser/reader.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'base.dart'; - -class StringReader implements IReader { - final String input; - - @override - int index = 0; - - StringReader(this.input); - - @override - int get length => input.length; - - @override - bool get isDone => index >= length; - - @override - String? peek() { - if (isDone) { - return null; - } - return input[index]; - } - - @override - String? read() { - if (isDone) { - return null; - } - return input[index++]; - } - - @override - void setPosition(int position) { - index = position; - } -} diff --git a/lib/src/message.dart b/lib/src/message.dart index 7f36e14..449b76f 100644 --- a/lib/src/message.dart +++ b/lib/src/message.dart @@ -1,4 +1,5 @@ -import 'color_parser/parser.dart'; +import 'package:terminal_color_parser/terminal_color_parser.dart'; + import 'consts.dart'; import 'parser.dart'; import 'symbols.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 0fc0bc3..cc7a491 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,6 +6,11 @@ repository: https://github.com/chenasraf/ctelnet_dart environment: sdk: ^3.1.2 +dependencies: + terminal_color_parser: any + # terminal_color_parser: + # path: ../terminal_color_parser + dev_dependencies: lints: ^2.0.0 test: ^1.21.0 diff --git a/test/color_parser_test.dart b/test/color_parser_test.dart deleted file mode 100644 index 272942b..0000000 --- a/test/color_parser_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:ctelnet/src/color_parser/parser.dart'; -import 'package:ctelnet/src/consts.dart'; -import 'package:test/test.dart'; - -const inputs = [ - '$esc[32mYou are standing in a small clearing.$esc[0m', - 'You are standing in a small clearing.', - '$esc[0m$esc[1m$esc[0m$esc[1m$esc[31mWelcome to SimpleMUD$esc[0m$esc[1m$esc[0m', - '$esc[0m$esc[37m$esc[0m$esc[37m$esc[1m[$esc[0m$esc[37m$esc[1m$esc[32m10$esc[0m$esc[37m$esc[1m/10]$esc[0m$esc[37m$esc[0m' -]; - -void main() { - group('ColorParser', () { - test('parse colors - simple', () { - final input = inputs[0]; - final output = ColorParser(input).parse(); - expect(output, [ - ColorToken( - text: 'You are standing in a small clearing.', - fgColor: 32, - bgColor: 0), - ColorToken.empty(), - ]); - }); - - test('formatted', () { - final input = inputs[0]; - final output = ColorParser(input).parse(); - expect(output[0].formatted, inputs[0]); - }); - }); -}