### ----------------------------------------------------
### -- Gnome::Gtk3
### -- Licenses: Artistic-2.0
### -- Authors: Marcel Timmerman
### -- File: xbin/gnome-gtk3-source-skim-tool.raku
### ----------------------------------------------------
### -- Chunk 4 of 5
 ~($<struct-type-section> // '');
#note $struct-type-section;

    # if no structs are found, clear the string
    if !?$struct-type-section {
#      $structs-doc = '' unless $found-doc;
      last;
    }

    # this match "m:g/'/**' .*? '*/' ...etc... /" can fail. It can gather
    # too many comment blocks to stop at a final struct. So try to find the
    # last doc section.
    my Int $start-doc = 1;  # There is a '/**' string at 0!
    my Int $x;
    while ?($x = $struct-type-section.index( '/**', $start-doc)) {
      $start-doc = $x + 1;
    }

    $start-doc -= 1;
    $struct-type-section = $struct-type-section.substr(
      $start-doc, $struct-type-section.chars - $start-doc
    );
#note $struct-type-section;


    # remove struct info for next search
    $include-content ~~ s/$struct-type-section//;

    # structs found
    $found-doc = True;
    my Bool $struct-skip = False;

    my Bool ( $get-item-doc, $get-struct-doc, $process-struct) =
            ( False, False, False);

    for $struct-type-section.lines -> $line {
      next if $line ~~ m/ '/**' /;

      if $line ~~ m/^ \s+ '*' \s+ $<struct-name> = [<alnum>+] ':' \s* $/ {
        $struct-name = 'N-' ~ ~($<struct-name> // '');

        # skip this structure if it is about this classes structure
        if $struct-name ~~ m/ \w+ Class $/ {
          $struct-skip = True;
          last;
        }
#        note "get structure $struct-name";
        $get-item-doc = True;
      }

      elsif $line ~~ m/^ \s+ '*' \s+ '@' $<item> = [ <alnum>+ ':' .* ] $ / {
        # Add extra characters to insert type information later on
        $items-doc ~= "\n=item ___" ~ ~($<item>//'');
#note "Item: $items-doc";
      }

      # on empty line swith from item to enum doc
      elsif $line ~~ m/ ^ \s+ '*' \s* $ / {
        $get-item-doc = False;
        $get-struct-doc = True;

        $struct-doc ~= "\n";
      }

      # end of type documentation
      elsif $line ~~ m/ ^ \s+ '*'*? '*/' \s* $ / {
        $get-item-doc = False;
        $get-struct-doc = False;
        $process-struct = True;

        $struct-spec = "\n=end pod\n\n#TT:0:$struct-name:\n" ~
          "class $struct-name is export is repr\('CStruct') \{\n";
      }

      elsif $line ~~ m/ ^ \s+ '*' \s* 'Since:' .* $ / {
        # ignore
      }

      elsif $line ~~ m/ ^ \s+ '*' \s+ $<doc> = [ \S .* ] $ / {
        if $get-item-doc {
          $items-doc ~= " " ~ ~($<doc>//'');
        }

        elsif $get-struct-doc {
          $struct-doc ~= "\n" ~ ~($<doc>//'');
        }
      }

      elsif $line ~~ m:s/ '};' / {
        $struct-spec ~= "}\n";
      }

      elsif $line ~~ m/^ \s+ $<struct-entry> = [ .*? ] ';' $/ {
        my Str $s = ~($<struct-entry> // '');
        ( $s, $entry-type, $raku-entry-type, $type-is-class) =
          get-type( $s, :!attr);

        # entry type Str must be converted to str
        $entry-type ~~ s/Str/str/;

        # if there is a comma separated list then split vars up
        if $s ~~ m/ ',' / {
          my @varlist = $s.split( / \s* ',' \s* /);
          for @varlist -> $var {
            $struct-spec ~= "  has $entry-type \$.$var;\n";
            $items-doc ~~ s/ 'item ___' $var /item $raku-entry-type \$.$var/;
          }
        }

        # $s is holding a single var
        else {
          $struct-spec ~= "  has $entry-type \$.$s;\n";
  #note "check for 'item ___$s'";
          $items-doc ~~ s/ 'item ___' $s /item $raku-entry-type \$.$s/;
        }
      }
    }

    # remove first space
    $struct-doc ~~ s/ ^ \s+ //;

    $struct-doc = primary-doc-changes($struct-doc);
    $items-doc = primary-doc-changes($items-doc);

    unless $struct-skip {
      #$structs-doc ~= Q:qq:to/EODOC/;
      $struct-docs{$struct-name} = Q:qq:to/EODOC/;
        #-------------------------------------------------------------------------------
        =begin pod
        =head2 class $struct-name

        $struct-doc

        $items-doc

        $struct-spec
        EODOC
    }
  }

#  $output-file.IO.spurt( $structs-doc, :append);

  print "\n";
  for $struct-docs.keys.sort -> $struct-name {
    note "get structure $struct-name";
    $output-file.IO.spurt( $struct-docs{$struct-name}, :append);
  }

#  note "add structure information to $output-file";
}

#-------------------------------------------------------------------------------
sub cleanup-source-doc ( Str:D $text is copy --> Str ) {

#note "cleanup-source-doc 0: $text";
  # remove property and signal line
  $text ~~ s/ ^^ \s+ '*' \s+ $*lib-class-name ':'+ .*? \n //;
#  $text ~~ s/ ^^ \s+ '*' \s+ $*lib-class-name ':' .*? \n //;

  $text ~~ s/ '/**' .*? \n //;                          # Doc start
  $text ~~ s/ \s* '*/' .* $ //;                         # Doc end
  $text ~~ s/ \s* '*'? \s* 'Since:' \d+\.\d+ \n //;     # Since: version
#  $text ~~ s/ ^^ \s+ '*' \s+ Deprecated: .*? \n //;    # Deprecated: version
#  $text ~~ s/ ^^ \s+ '*' \s+ Stability: .*? \n //;     # Stability: status
  $text ~~ s:g/ \s+ '*' \s+ '-' \s? (.*?) \n /=item $/[0]\n/; # doc star + dash
  $text ~~ s:g/ ' '+ '*' ' '*/ /;                       # doc star + something

#note "\ncleanup-source-doc 1: $text";

  $text ~~ s:g/ \n**3 /\n\n/;                           # 3 x \n -> 2x \n
  $text ~~ s:g/ ^^ ' '+ //;                             # prefixed spaces -> ''
  $text ~~ s:g/ ( <-[\s]>) \n (<-[\s]>) /$/[0] $/[1]/;  # \n -> ' '
  $text ~~ s:g/ ' '**2 / /;                             # more spaces -> ' '

#note "\ncleanup-source-doc 2: $text";
  $text
}

#-------------------------------------------------------------------------------
sub primary-doc-changes ( Str:D $text is copy --> Str ) {

#note "\nprimary-doc-changes 0: $text";

  $text = podding-signal($text);
#note "\nprimary-doc-changes signal: $text";

  $text = podding-property($text);
#note "\nprimary-doc-changes property: $text";

  $text = podding-class($text);
#note "\nprimary-doc-changes class: $text";

  $text = modify-at-vars($text);
#note "\nprimary-doc-changes vars: $text";

  $text = modify-percent-types($text);
#note "\nprimary-doc-changes % types: $text";

  $text = podding-function($text);
#note "\nprimary-doc-changes function: $text";

  $text = adjust-image-path($text);
#note "\nprimary-doc-changes image path: $text";

$text ~~ s:g/ '=item' /\n=item/;

  $text
}

#-------------------------------------------------------------------------------
# change any :signal to I<signal>
sub podding-signal ( Str:D $text is copy --> Str ) {

  loop {
    # When used with classname, e.g #GtkAppChooserWidget::application-selected
    # change it to I<application-selected from Gnome::Gtk3::AppChooserWidget>
    # Otherwise, when classname is empty, or the Raku classname is the
    # same as for this module, write I<application-selected> only.
    $text ~~ m/ ['#' $<gtk-classname> = [<alnum>+] || \s ] '::'
                $<sig-name> = [<alnum> || '-']+/;

    my Str $sig-name = ~($<sig-name>//'');

    last unless ?$sig-name;

    my Str $gtk-classname = ~($<gtk-classname>//'');
    my Str $raku-classname = make-raku-classname($gtk-classname);

    $raku-classname = '' if ?$raku-classname and
       $raku-classname ~~ "Gnome\:\:{$*raku-lib-name}::{$*raku-class-name}";

    if $raku-classname {
      $text ~~ s/ '#' $gtk-classname '::' $sig-name
                /I<$sig-name from $raku-classname>/;
    }

    else {
      # gtk classname could still be there
      $text ~~ s/ ['#' $gtk-classname]? '::' $sig-name
                /I<$sig-name>/;
    }
  }

  $text
}

#-------------------------------------------------------------------------------
# change any :property to I<property>
sub podding-property ( Str:D $text is copy --> Str ) {

  loop {
    # When used with classname, e.g #GtkAppChooserWidget:show-default
    # change it to I<show-default from Gnome::Gtk3::AppChooserWidget>
    # Otherwise, when classname is empty, or the Raku classname is
    # the same as for this module, write I<show-default> only.
    $text ~~ m/ '#' $<gtk-classname> = [<alnum>+]? ':'
                $<prop-name> = [<alnum> || '-']+/;

    my Str $prop-name = ~($<prop-name>//'');
    last unless ?$prop-name;

    my Str $gtk-classname = ~($<gtk-classname>//'');
    my Str $raku-classname = make-raku-classname($gtk-classname);
    $raku-classname = '' if ?$raku-classname and
       $raku-classname ~~ "Gnome\:\:{$*raku-lib-name}::{$*raku-class-name}";

    if $raku-classname {
      $text ~~ s/ '#' $gtk-classname ':' $prop-name
                /I<$prop-name from $raku-classname>/;
    }

    else {
      # gtk classname could still be there
      $text ~~ s/ [ '#' $gtk-classname]? ':' $prop-name
                /I<$prop-name>/;
    }
  }

  $text
}

#-------------------------------------------------------------------------------
# change;
#   #class::signal to I<signal>
#   #class:property to I<property>
#   #class to B<Gnome::Xyz::Class>
sub podding-class ( Str:D $text is copy --> Str ) {

  loop {
    $text ~~ m/ '#' $<classname> = [<alnum>+] /;
    my Str $classname = ~($<classname>//'');
    last unless ?$classname;

    my Str $raku-classname = make-raku-classname($classname);
#`{{    my Str $raku-classname = $classname;
    $raku-classname ~~ s/ (<[A..Z]>) /$0.lc()/;
    $raku-classname ~~ s:g/ (<[A..Z]>) /_$0.lc()/;
    my @parts = $raku-classname.split('_');
    my Str $class = '';
    for @parts -> $p {
      $class ~= ?$class ?? "_$p" !! $p;
note "$?LINE '$class', '$raku-classname', {%gnome-names-map{$class} // '-'}";

      # If class name is found in the map, substitute it with the Raku classname
      if ?%gnome-names-map{$class} {
        $raku-classname = %gnome-names-map{$class};
note "$?LINE, $raku-classname";
        last;
      }
    }
}}

    # replace changed part in text
    if $raku-classname eq 'Deprecated' {
      $text ~~ s/ '#' $classname /B<Deprecated gnome class $classname>/;
    }

#`{{
    elsif $raku-classname ~~ m:s/ Not implemented / {
      $text ~~ s/ '#' $classname /B<$raku-classname>/;
    }
}}

    else {
      $text ~~ s/ '#' $classname /B<$raku-classname>/;
    }

#note "$?LINE, $text";
#exit(0);
  }

  $text
}

#-------------------------------------------------------------------------------
# change any function() to C<function()>
sub podding-function ( Str:D $text is copy --> Str ) {

  loop {
    $text ~~ m/ $<function> = ( \s+ <[a..z \_]>+ \s* '()' \s+ ) /;
    my Str $function = ~($<function>//'').Str;
    last unless ?$function;

    $function ~~ s:g/ \s //;
    my Str $rk-function = $function;
    my @parts = $rk-function.split('_');
    my Str $class = '';
    for @parts -> $p {
      $class ~= ?$class ?? "_$p" !! $p;
#note "$?LINE '$class', '$function', {%gnome-names-map{$class} // '-'}";

      # If class name is found in the map, substitute it with the Raku classname
      # and replace the _ for -
      if ?%gnome-names-map{$class} {
#        $rk-function ~~ s/ $class '_' /%gnome-names-map{$class}./;
note "$?LINE, $rk-function";

        my Str $raku-classname = %gnome-names-map{$class};

        # replace changed part in text
        if $raku-classname eq 'Deprecated' {
          $rk-function ~~ s/ $class '_' /Deprecated gnome class {$class}_/;
        }
#`{{
        elsif $raku-classname ~~ m:s/ Not implemented / {
          $rk-function ~~ s/ $class '_' /$raku-classname./;
        }
}}

        else {
          $rk-function ~~ s/ $class '_' /$raku-classname./;
        }

        last;
      }
    }

    # replace the _ for -
    $rk-function ~~ s:g/ '_' /-/;

    # Substitute text for next lookup but remove class name when
    # in the same module
note "$?LINE, $function, $rk-function, $*base-sub-name";
    $rk-function ~~ s/ $*base-sub-name //
      if $rk-function ~~ m/^ $*base-sub-name /;

    $text ~~ s:g/ $function /C<$rk-function>/;

#note "$?LINE, $rk-function";
#note $text;
#exit 0;
  }

#`{{
#note "$?LINE $classname";
#  my Str $raku-classname = %gnome-names-map{$classname};



  # change any function() to C<function()>. first change to [[function]] to
  # prevent nested substitutions.
  $text ~~ s:g/ ( <[\w\d\-\_]>+ ) \s* '()' /\[\[$/[0]\]\]/;

  # Remove the classname when it is the current class and start with a dot
  $text ~~ s:g/ $*base-sub-name '_' /./;

  #TODO
  # 'g_' prefix can be from Glib, GObject or Gio
  # A sub in a class can have 0 or more dashes. so, what part is the class name?

  $text ~~ s:g/ '[[' ( <[\w\d\-\_]>+ )']]' /C<$/[0]\()>/;
  $text ~~ s:g/ '_' /-/;
}}

  $text
}

#-------------------------------------------------------------------------------
# change any %type to C<type>
sub modify-percent-types ( Str:D $text is copy --> Str ) {
  $text ~~ s:g/ '%TRUE' /C<True>/;
  $text ~~ s:g/ '%FALSE' /C<False>/;
  $text ~~ s:g/ '%NULL' /C<undefined>/;
  $text ~~ s:g/ '%' ([<alnum> || '_' ]+) /C<$/[0]>/;

  $text
}

#-------------------------------------------------------------------------------
# change any @var to I<var>
sub modify-at-vars ( Str:D $text is copy --> Str ) {
  $text ~~ s:g/ '@' (<alnum>+) /I<$/[0]>/;

  $text
}

#-------------------------------------------------------------------------------
# change any ![alt](path) to ![alt](images/path)
sub adjust-image-path ( Str:D $text is copy --> Str ) {
  $text ~~ s:g/ '![' (<-[\]]>*) '](' (<-[\)]>+) ')'
              /\!\[$/[0]\]\(images\/$/[1]\)/;

  $text
}

#-------------------------------------------------------------------------------
sub make-raku-classname ( Str $classname --> Str ) {

  my Str $raku-classname = $classname;
  if $classname eq 'GdkRGBA' {
    $raku-classname = 'gdk_rgba';
  }

  else {
    $raku-classname ~~ s/ (<[A..Z]>) /$0.lc()/;
    $raku-classname ~~ s:g/ (<[A..Z]>) /_$0.lc()/;
  }

  my @parts = $raku-classname.split('_');
  my Str $class = '';
  for @parts -> $p {
    $class ~= ?$class ?? "_$p" !! $p;
#note "$?LINE '$class', '$raku-classname', {%gnome-names-map{$class} // '-'}";

    # If class name is found in the map, substitute it with the Raku classname
    if ?%gnome-names-map{$class} {
      $raku-classname = %gnome-names-map{$class};
#note "$?LINE, $raku-classname";
      last;
    }
  }

  $raku-classname
}


#`{{
  my Str $raku-classname;
#  $gtk-classname ~~ m/ '#' $<raku-classname> = (<alnum>+) /;
#  $raku-classname = ~($<raku-classname> // '');
#  return '' unless ?$raku-classname;

  return '' unless ?$gtk-classname;

#note "$?LINE $gtk-classname";
#  $raku-classname = %gnome-names-map{$gtk-classname};

#  $gtk-classname ~~ m/ '#' $<raku-classname> = (<alnum>+) /;

  $raku-classname = $gtk-classname;
  $raku-classname ~~
    m/ $<classlibpart> = [
      'Gtk' || 'Gdk' || 'G' || 'cairo_'
    ] <alnum>+ /;
#note "make-raku-classname: $raku-classname, $<classlibpart>.Str()";
  given my Str $classlibpart = ~($<classlibpart>//'') {
    when any(<Gtk Gdk>) {
      $classlibpart ~= '3';
    }

    when 'G' {
      # assume Gio but could be Glib or GObject
      $classlibpart = 'Gio';
    }

    when 'cairo_' {
      $classlibpart = 'Cairo';
    }

    default {
      note "Unknown '$classlibpart' from gtk class $raku-classname"
        if ?$_;
    }
  }

  $raku-classname ~~ s/^ ['Gtk' || 'Gdk' || 'G' || 'cairo_'] ( <alnum>+ )
                      /Gnome::$classlibpart\:\:$/[0]/;

  # replace changed part in text
  #$text ~~ s/ '#' $part /B\<$oct\>/;

  $raku-classname
}}


#-------------------------------------------------------------------------------
sub generate-test ( ) {

  # create var name named after classname. E.g. TextBuffer -> $tb.
  my Str $m = '$' ~ $*raku-class-name.comb(/<[A..Z]>/).join.lc;
  my Str $class = [~] 'Gnome::', $*raku-lib-name, '::', $*raku-class-name;
  my Str $test-content = Q:q:s:b:to/EOTEST/;
    use v6;
    use NativeCall;
    use Test;

    use $class;

    #use Gnome::N::GlibToRakuTypes:api<1>;
    #use Gnome::N::N-GObject:api<1>;
    #use Gnome::N::X:api<1>;
    #Gnome::N::debug(:on);

    #-------------------------------------------------------------------------------
    my $class $m;
    #-------------------------------------------------------------------------------
    subtest 'ISA test', {
      $m .= new;
      isa-ok $m, $class, '.new()';
    }

    #-------------------------------------------------------------------------------
    done-testing;

    =finish


    #-------------------------------------------------------------------------------
    # set environment variable 'raku-test-all' if rest must be tested too.
    unless %*ENV<raku_test_all>:exists {
      done-testing;
      exit;
    }

    #-------------------------------------------------------------------------------
    subtest 'Manipulations', {
    }

    #-------------------------------------------------------------------------------
    subtest 'Inherit $class', {
      class MyClass is $class {
        method new ( |c ) {
          self.bless( :$*lib-class-name, |c);
        }

        submethod BUILD ( *%options ) {

        }
      }

      my MyClass \$mgc .= new;
      isa-ok \$mgc, $class, 'MyClass.new()';
    }

    #-------------------------------------------------------------------------------
    subtest 'Properties …', {
    #  my $class $m .= new;
      my \@r = $m.get-properties\(
    #    name, type,  …
      );
      is-deeply \@r, [
    #    value, …
      ], 'properties: ' ~ (
    #    name, …
      ).join\(', ');
    }

    #-------------------------------------------------------------------------------
    subtest 'Signals …', {
      use Gnome::Gtk3::Main:api<1>;
      use Gnome::N::GlibToRakuTypes:api<1>;

      my Gnome::Gtk3::Main \$main .= new;

      class SignalHandlers {
        has Bool \$!signal-processed = False;

        method … (
          'any-args',
          $class\() :\$_native-object, gulong :\$_handler-id
          # --> …
        ) {

          isa-ok \$_native-object, $class;
          \$!signal-processed = True;
        }

        method signal-emitter ( $class :\$_widget --> Str ) {

          while \$main.gtk-events-pending\() { \$main.iteration-do\(False); }

          \$_widget.emit-by-name\(
            'signal',
          #  'any-args',
          #  :return-type(int32),
          #  :parameters([int32,])
          );
          is \$!signal-processed, True, '\\'…\\' signal processed';

          while \$main.gtk-events-pending\() { \$main.iteration-do\(False); }

          #\$!signal-processed = False;
          #\$_widget.emit-by-name\(
          #  'signal',
          #  'any-args',
          #  :return-type(int32),
          #  :parameters([int32,])
          #);
          #is \$!signal-processed, True, '\\'…\\' signal processed';

          while \$main.gtk-events-pending\() { \$main.iteration-do\(False); }
          sleep\(0.4);
          \$main.gtk-main-quit;

          'done'
        }
      }

      my $class $m .= new;

      #my Gnome::Gtk3::Window \$w .= new;
      #\$w.add(\$m);

      my SignalHandlers \$sh .= new;
      $m.register-signal\( \$sh, 'method', 'signal');

      my Promise \$p = $m.start-thread\(
        \$sh, 'signal-emitter',
        # :!new-context,
        # :start-time(now + 1)
      );

      is \$main.gtk-main-level, 0, "loop level 0";
      \$main.gtk-main;
      #is \$main.gtk-main-level, 0, "loop level is 0 again";

      is \$p.result, 'done', 'emitter finished';
    }

    #-------------------------------------------------------------------------------
    subtest 'Themes …', {
    }

    #-------------------------------------------------------------------------------
    subtest 'Interface …', {
    }

    EOTEST

  "xt/NewModules/$*raku-class-name.rakutest".IO.spurt($test-content);
  note "generate tests in xt/NewModules/$*raku-class-name.rakutest";
}







=finish

#`{{
#-------------------------------------------------------------------------------
sub get-signals ( Str:D $source-content is copy ) {

  return unless $source-content;

  my Array $items-src-doc;
  my Str $signal-name;
  my Str $signal-doc = '';
  my Hash $signal-classes = %();

  print "Find signals ";
  my Hash $signal-doc-entries = %();
  loop {
    print ".";
    $*OUT.flush;

    $items-src-doc = [];
    $signal-name = '';

    $source-content ~~ m/
      $<signal-doc> = [ '/**' \s+ '*' \s+ $*lib-class-name '::'  .*? '*/' ]
    /;

    # save doc and remove from source but stop if none left
    my Str $sdoc = ~($<signal-doc> // '');
#note "SDoc 0 $*lib-class-name: ", ?$sdoc;
    my Bool $has-doc = ($sdoc ~~ m/ '/**' / ?? True !! False);

    # possibly no documentation
    if $has-doc {
      $source-content ~~ s/$sdoc//;

      # get lib class name and remove line from source
      $sdoc ~~ m/
        ^^ \s+ '*' \s+ $*lib-class-name '::' $<signal-name> = [ [<alnum> || '-']+ ]
      /;
      $signal-name = ~($<signal-name> // '');
      $sdoc ~~ s/ ^^ \s+ '*' \s+ $*lib-class-name '::' $signal-name '::'? //;
#note "SDoc 1 ", $sdoc;
    }

    # get some more info from the function call
    $source-content ~~ m/
      'g_signal_new' '_class_handler'? \s* '('
      $<signal-args> = [
        [ <[A..Z]> '_('                     || # gtk sources
          'g_intern_static_string' \s* '('     # gdk sources
        ]
        '"' <-[\"]>+ '"' .*?
      ] ');'
    /;
#note "SDoc 2 ",  ~($<signal-args>//'-');

    # save and remove from source but stop if there isn't any left
    my Str $sig-args = ~($<signal-args>//'');
    if !$sig-args {
      $sdoc = '';
      last;
    }
    $source-content ~~
       s/ 'g_signal_new' '_class_handler'? \s* '(' $sig-args ');' //;

#note "sig args: ", $sig-args;
    # when there's no doc, signal name must be retrieved from function argument
    unless $signal-name {
      $sig-args ~~ m/ '"' $<signal-name> = [ <-[\"]>+ ] '"' /;
      $signal-name = ($<signal-name>//'').Str;
    }

#note "SA $signal-name: ", $sig-args;

    # start pod doc
    $signal-doc = Q:qq:to/EOSIG/;

      =comment -----------------------------------------------------------------------
      =comment #TS:0:$signal-name:
      =head3 $signal-name
      EOSIG

note "get signal $signal-name";

    # process g_signal_new arguments, remove commas from specific macro
    # by removing the complete argument list. it's not needed.
    $sig-args ~~ s/ 'G_STRUCT_OFFSET' \s* \( <-[\)]>+ \) /G_STRUCT_OFFSET/;
    my @args = ();
    for $sig-args.split(/ \s* ',' \s* /) -> $arg is copy {
#note "  arg: '$arg'";
      @args.push($arg);
    }

note "  Args: ", @args[*];
    # get a return type from arg 7
    my Str $return-type = '';
    given @args[7] {
      # most of the time it is a boolean ( == c int32)
      when 'G_TYPE_BOOLEAN' { $return-type = 'Int'; }
      when 'G_TYPE_INT' { $return-type = 'Int'; }
      when 'G_TYPE_UINT' { $return-type = 'Int'; }
      when 'G_TYPE_STRING' { $return-type = 'Str'; }
      when 'G_TYPE_NONE' { $return-type = ''; }
      when 'GTK_TYPE_TREE_ITER' { $return-type = 'N-GtkTreeIter'; }

      # show that there is something if return type not recognized
      default { $return-type = "Unknown type @args[7]"; }
    }

    my Int $item-count = 0;

    # create proper variable name when not available from the doc
    my Str $iname = $*lib-class-name;
    $iname ~~ s:i/^ [ gtk || gdk || g ] //;
    $iname .= lc;
    $items-src-doc.push: %(
      :item-type<Gnome::GObject::Object>, :item-name($iname),
      :item-doc('')
    );

    # process handler argument types. nbr args at 8, types at 9 and further
    my Array $signal-args = ['N-GObject'];
    my Int $arg-count = @args[8].Int;
#    loop ( my $i = 0; $i < $arg-count; $i++ ) {
    for ^$arg-count -> $i {

#note "  A[9 + $i]: @args[9 + $i]";

      my Str $arg-type = '';
      given @args[9 + $i] {
        when 'G_TYPE_BOOLEAN' { $arg-type = 'Int'; }
        when 'G_TYPE_INT' { $arg-type = 'Int'; }
        when 'G_TYPE_UINT' { $arg-type = 'UInt'; }
        when 'G_TYPE_LONG' { $arg-type = 'glong #`{ use Gnome::N::GlibToRakuTypes }':api<1>; }
        when 'G_TYPE_FLOAT' { $arg-type = 'Num'; }
        when 'G_TYPE_DOUBLE' { $arg-type = 'gdouble #`{ use Gnome::N::GlibToRakuTypes }':api<1>; }
        when 'G_TYPE_STRING' { $arg-type = 'Str'; }
        when 'G_TYPE_ERROR' { $arg-type = 'N-GError'; }

        when 'GTK_TYPE_OBJECT' { $arg-type = 'N-GObject #`{ is object }'; }
        when 'GTK_TYPE_WIDGET' { $arg-type = 'N-GObject #`{ is widget }'; }

        when 'GTK_TYPE_TEXT_ITER' {
          $arg-type = 'N-GObject #`{ native Gnome::Gtk3::TextIter }';
        }
        when 'GTK_TYPE_TREE_ITER' {
          $arg-type = 'N-GtkTreeIter #`{ native Gnome::Gtk3::TreeIter }';
        }
        when 'GDK_TYPE_DISPLAY' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::Display }';
        }
        when 'GDK_TYPE_DEVICE' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::Device }';
        }
        when 'GDK_TYPE_DEVICE_TOOL' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::DeviceTool }';
        }
        when 'GDK_TYPE_MONITOR' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::Monitor }';
        }
        when 'GDK_TYPE_SCREEN' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::Screen }';
        }
        when 'GDK_TYPE_SEAT' {
          $arg-type = 'N-GObject #`{ native Gnome::Gdk3::Seat }';
        }
        when 'GDK_TYPE_MODIFIER_TYPE' {
          $arg-type = 'GdkModifierType #`{ from Gnome::Gdk3::Window }';
        }
        default { $arg-type = "Unknown type @args[{9 + $i}]"; }
      }

      my Str $item-name = $arg-type.lc;
      $item-name ~~ s/ 'gnome::gtk3::' //;
      $items-src-doc.push: %(
        :item-type($arg-type), :$item-name,
        :item-doc('')
      );

note "  A Type: $i, $arg-type, $item-name";
      $signal-args.push: $arg-type;
    }

    # we know the number of extra arguments and signal name
    my Str $sig-class = "w$arg-count";
    $signal-classes{$sig-class} = [] unless $signal-classes{$sig-class}:exists;
    $signal-classes{$sig-class}.push: $signal-name;

    # get arguments for this signal handler
    my Str ( $item-doc, $item-name, $spart-doc) = ( '', '', '');
    my Bool $item-scan = True;
    #my Bool $first-arg = True;

    $item-count = 0;
    if $has-doc {
#      $items-src-doc = [];
      for $sdoc.lines -> $line {
note "L: $line";

        # argument doc start
        if $item-scan and $line ~~ m/^ \s* '*' \s+ '@' / {

          # push when 2nd arg is found
#note "ISD 0: $item-count, $item-name, $signal-args[$item-count]" if ?$item-name;
          $items-src-doc.push: %(
            :item-type($signal-args[$item-count++]), :$item-name, :$item-doc
          ) if ?$item-name;

          # get the info from the current line
          $line ~~ m/ '*' \s+ '@' $<item-name> = [<alnum>+] ':'
                      \s* $<item-doc> = [ .* ]
                    /;

          $item-name = ~($<item-name> // '');
          $item-doc = primary-doc-changes(~($<item-doc> // '')) ~ "\n";
note "n, d: $item-name, $item-doc";
        }

        # continue previous argument doc
        elsif $item-scan and
              $line ~~ m/^ \s* '*' \s ** 2..* $<item-doc> = [ .* ] / {
          my Str $s = ~($<item-doc> // '');
          $item-doc ~= primary-doc-changes($s);
note "d: $item-doc";
        }

        # on empty line after '*' start sub doc
        elsif $line ~~ m/^ \s* '*' \s* $/ {
          # push last arg
#note "ISD 1: $item-count, $item-name, $signal-args[$item-count]"
#if $item-scan and ?$item-name;
          $items-src-doc.push: %(
            :item-type($signal-args[$item-count]), :$item-name, :$item-doc
          ) if $item-scan and ?$item-name;

          $spart-doc ~= "\n";
          $item-scan = False;
        }

        # rest is sub doc
        elsif !$item-scan {
          # skip end of document
          next if $line ~~ m/ '*/' /;

          my Str $l = $line;
          $l ~~ s/^ \s* '*' \s* //;
          $spart-doc ~= $l ~ "\n";
        }
      }

      #