/// XML position printer. library; import 'dart:io'; import 'dart:math'; import 'package:args/args.dart' as args; import 'package:petitparser/petitparser.dart'; import 'package:xml/xml_events.dart'; final args.ArgParser argumentParser = args.ArgParser() ..addOption( 'position', abbr: 'p', help: 'Print character index instead of line:column.', allowed: ['start', 'stop', 'start-stop', 'line', 'column', 'line:column'], defaultsTo: 'line:column', ) ..addOption( 'limit', abbr: 'l', help: 'Limit output to the specified number of characters.', defaultsTo: '60', ); void printUsage() { stdout.writeln('Usage: xml_pos [options] {files}'); stdout.writeln(); stdout.writeln(argumentParser.usage); exit(1); } void main(List arguments) { final files = []; final results = argumentParser.parse(arguments); final position = results['position'] as String; final limit = int.parse(results['limit'] as String); for (final argument in results.rest) { final file = File(argument); if (file.existsSync()) { files.add(file); } else { stderr.writeln('File not found: $file'); exit(2); } } if (files.isEmpty) { printUsage(); } for (final file in files) { final events = parseEvents( file.readAsStringSync(), withBuffer: true, withLocation: true, ).where((event) => event is! XmlTextEvent || event.value.trim().isNotEmpty); for (final event in events) { final positionString = outputPosition(position, event).padLeft(10); final tokenString = outputString(limit, event); stdout.writeln('$positionString: $tokenString'); } } } String outputPosition(String position, XmlEvent event) { switch (position) { case 'start': return '${event.start}'; case 'stop': return '${event.stop}'; case 'start-stop': return '${event.start}-${event.stop}'; } final lineAndColumn = Token.lineAndColumnOf(event.buffer!, event.start!); switch (position) { case 'line': return '${lineAndColumn[0]}'; case 'column': return '${lineAndColumn[1]}'; default: return '${lineAndColumn[0]}:${lineAndColumn[1]}'; } } String outputString(int limit, XmlEvent event) { final input = event.buffer!.substring(event.start!, event.stop); final index = input.indexOf('\n'); final length = min(limit, index < 0 ? input.length : index); final output = input.substring(0, length); return output.length < input.length ? '$output...' : output; }