3 namespace RemexHtml\TreeBuilder;
4 use RemexHtml\Tokenizer\TokenHandler;
5 use RemexHtml\Tokenizer\Tokenizer;
6 use RemexHtml\Tokenizer\Attributes;
9 * This is a debugging helper class which calls a callback function with a
10 * descriptive message each time a token event comes from the Tokenizer. The
11 * messages include information about the current state and transitions of the
12 * Dispatcher which is the next stage in the pipeline.
14 class DispatchTracer implements TokenHandler {
19 function __construct( $input, Dispatcher $dispatcher, callable $callback ) {
20 $this->input = $input;
21 $this->dispatcher = $dispatcher;
22 $this->callback = $callback;
25 private function trace( $msg ) {
26 call_user_func( $this->callback, "[Dispatch] $msg" );
29 private function excerpt( $text ) {
30 if ( strlen( $text ) > 20 ) {
31 $text = substr( $text, 0, 20 ) . '...';
33 return str_replace( "\n", "\\n", $text );
36 private function wrap( $funcName, $sourceStart, $sourceLength, $args ) {
37 $prevHandler = $this->getHandlerName();
38 $excerpt = $this->excerpt( substr( $this->input, $sourceStart, $sourceLength ) );
39 $msg = "$funcName $prevHandler \"$excerpt\"";
41 call_user_func_array( [ $this->dispatcher, $funcName ], $args );
42 $handler = $this->getHandlerName();
43 if ( $prevHandler !== $handler ) {
44 $this->trace( "$prevHandler -> $handler" );
48 private function getHandlerName() {
49 $handler = $this->dispatcher->getHandler();
50 $name = $handler ? get_class( $handler ) : 'NULL';
51 $slashPos = strrpos( $name, '\\' );
52 if ( $slashPos === false ) {
55 return substr( $name, $slashPos + 1 );
59 public function startDocument( Tokenizer $tokenizer, $ns, $name ) {
60 $prevHandler = $this->getHandlerName();
61 $nsMsg = $ns === null ? 'NULL' : $ns;
62 $nameMsg = $name === null ? 'NULL' : $name;
63 $this->trace( "startDocument $prevHandler $nsMsg $nameMsg" );
64 $this->dispatcher->startDocument( $tokenizer, $ns, $name );
65 $handler = $this->getHandlerName();
66 if ( $prevHandler !== $handler ) {
67 $this->trace( "$prevHandler -> $handler" );
71 public function endDocument( $pos ) {
72 $this->wrap( __FUNCTION__, $pos, 0, func_get_args() );
75 public function error( $text, $pos ) {
76 $handler = $this->getHandlerName();
77 $this->trace( "error $handler \"$text\"" );
78 $this->dispatcher->error( $text, $pos );
81 public function characters( $text, $start, $length, $sourceStart, $sourceLength ) {
82 $this->wrap( __FUNCTION__, $sourceStart, $sourceLength, func_get_args() );
85 public function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) {
86 $this->wrap( __FUNCTION__, $sourceStart, $sourceLength, func_get_args() );
89 public function endTag( $name, $sourceStart, $sourceLength ) {
90 $this->wrap( __FUNCTION__, $sourceStart, $sourceLength, func_get_args() );
93 public function doctype( $name, $public, $system, $quirks, $sourceStart, $sourceLength ) {
94 $this->wrap( __FUNCTION__, $sourceStart, $sourceLength, func_get_args() );
97 public function comment( $text, $sourceStart, $sourceLength ) {
98 $this->wrap( __FUNCTION__, $sourceStart, $sourceLength, func_get_args() );