### ----------------------------------------------------
### -- Gnome::Gtk3
### -- Licenses: Artistic-2.0
### -- Authors: Marcel Timmerman
### -- File: xbin/gnome-gtk3-source-skim-tool.raku
### ----------------------------------------------------
### -- Chunk 2 of 5
;

        unit class Gnome::LIBRARYMODULE;
        ALSO-IS-LIBRARY-PARENT


      =comment head2 Uml Diagram

      =comment ![](plantuml/MODULENAME.svg)


      =begin comment
      =head2 Inheriting this class

      Inheriting is done in a special way in that it needs a call from new() to get the native object created by the class you are inheriting from.

        use Gnome::LIBRARYMODULE;

        unit class MyGuiClass;
        also is Gnome::LIBRARYMODULE;

        submethod new ( |c ) {
          # let the Gnome::LIBRARYMODULE class process the options
          self.bless( :LIBCLASSNAME, |c);
        }

        submethod BUILD ( ... ) {
          ...
        }

      =end comment


      =comment head2 Example

      =end pod
      #-------------------------------------------------------------------------------
      use NativeCall;

      #use Gnome::N::X:api<1>;
      use Gnome::N::NativeLib:api<1>;
      use Gnome::N::N-GObject:api<1>;
      use Gnome::N::GlibToRakuTypes:api<1>;
      USE-LIBRARY-PARENT

      #-------------------------------------------------------------------------------
      unit class Gnome::LIBRARYMODULE:auth<github:MARTIMM>:api<1>;
      ALSO-IS-LIBRARY-PARENT
      EOTEMPLATE
  }

  my Str ( $t1, $t2) = ( '', '');
  if $class-is-top {
    $t1 = "use Gnome::N::TopLevelClassSupport:api<1>;";
    $t2 = "also is Gnome::N::TopLevelClassSupport;";
  }

  elsif $*raku-parentlib-name and $*raku-parentclass-name {
    $t1 = "use Gnome::{$*raku-parentlib-name}::{$*raku-parentclass-name}:api<1>;";
    $t2 = "also is Gnome::{$*raku-parentlib-name}::{$*raku-parentclass-name};";
  }


  $template-text ~~ s:g/ 'MODULENAME' /$*raku-class-name/;
  $template-text ~~ s:g/ 'LIBRARYMODULE' /{$*raku-lib-name}::{$*raku-class-name}/;
  $template-text ~~ s:g/ 'USE-LIBRARY-PARENT' /$t1/;
  $template-text ~~ s:g/ 'ALSO-IS-LIBRARY-PARENT' /$t2/;

  $template-text ~~ s:g/ 'MODULE-SHORTDESCRIPTION' /$short-description/;
  $template-text ~~ s:g/ 'MODULE-DESCRIPTION' /$section-doc/;
  $template-text ~~ s:g/ 'MODULE-SEEALSO' /$see-also/;
  $template-text ~~ s:g/ 'LIBCLASSNAME' /$*lib-class-name/;

  $output-file = "xt/NewModules/$*raku-class-name.rakumod";
  $output-file.IO.spurt($template-text);

  note "Write Gnome::{$*raku-lib-name}::{$*raku-class-name} to $output-file";

  get-vartypes($include-content) if $do-all or $types;

  if $do-all or $main {
    if $class-is-role {
      $template-text = Q:q:to/EOTEMPLATE/;
        #-------------------------------------------------------------------------------
        =begin pod
        =head1 Methods
        =end pod

        # interfaces are not instantiated
        #submethod BUILD ( *%options ) { }

        #`{{
        # All interface calls should become methods
        #-------------------------------------------------------------------------------
        # no pod. user does not have to know about it.
        method _INTERFACE_NAME ( $native-sub --> Callable ) {

          my Callable $s;
          try { $s = &:("BASE-SUBNAME_$native-sub"); };
        # check for gtk_, gdk_, g_, pango_ !!!
          try { $s = &:("gtk_$native-sub"); } unless ?$s;
          try { $s = &:($native-sub); } if !$s and $native-sub ~~ m/^ 'gtk_' /;

          $s;
        }
        }}


        #-------------------------------------------------------------------------------
        # setup signals from interface
        method _add_INTERFACE_NAME_signal_types ( Str $class-name ) {
        BUILD-ADD-SIGNALS}

        EOTEMPLATE

      my Str $iname = $*base-sub-name;
      $iname ~~ s/ [ gtk | gdk | gio ] '_' //;
      $template-text ~~ s:g/ INTERFACE_NAME /{$iname}_interface/;
#`{{
  TODO must call interfaces after ._set-class-name-of-sub()
  and in interface must also call ._set-class-name-of-sub() if sub is found.
  this is for casting.

  Methods can be written for interfaces and remove self._xyz_interface() from
  classes. ==> interfaces can not be handled as leafs because casting necessary

  self._set-class-name-of-sub('GSimpleAction') if ?$s;
}}
    }

    else {
      $template-text = Q:q:to/EOTEMPLATE/;
        #-------------------------------------------------------------------------------
        BOOL-SIGNALS-ADDED
        =begin pod
        =head1 Methods
        =head2 new

        =head3 default, no options

        Create a new RAKU-CLASS-NAME object.

          multi method new ( )


        =head3 :native-object

        Create a RAKU-CLASS-NAME object using a native object from elsewhere. See also B<Gnome::N::TopLevelClassSupport>.

          multi method new ( N-GObject :$native-object! )


        =head3 :build-id

        Create a RAKU-CLASS-NAME object using a native object returned from a builder. See also B<Gnome::GObject::Object>.

          multi method new ( Str :$build-id! )

        =end pod

        #TM:0:new():inheriting
        #TM:1:new():
        #TM:4:new(:native-object):Gnome::N::TopLevelClassSupport
        #TM:4:new(:build-id):Gnome::GObject::Object

        submethod BUILD ( *%options ) {

        BUILD-ADD-SIGNALS

          # prevent creating wrong native-objects
          if self.^name eq 'Gnome::LIBRARYMODULE' #`{{ or %options<LIBCLASSNAME> }} {

            # check if native object is set by a parent class
            if self.is-valid { }

            # check if common options are handled by some parent
            elsif %options<native-object>:exists { }
            elsif %options<build-id>:exists { }

            # process all other options
            else {
              my N-GObject() $no;
              if ? %options<___x___> {
                #$no = %options<___x___>;
                #$no .= _get-native-object-no-reffing unless $no ~~ N-GObject;
                #$no = _BASE-SUBNAME_new___x___($no);
              }

              #`{{ use this when the module is not made inheritable
              # check if there are unknown options
              elsif %options.elems {
                die X::Gnome.new(
                  :message(
                    'Unsupported, undefined, incomplete or wrongly typed options for ' ~
                    self.^name ~ ': ' ~ %options.keys.join(', ')
                  )
                );
              }
              }}

              #`{{ when there are no defaults use this
              # check if there are any options
              elsif %options.elems == 0 {
                die X::Gnome.new(:message('No options specified ' ~ self.^name));
              }
              }}

              #`{{ when there are defaults use this instead
              # create default object
              else {
                $no = _BASE-SUBNAME_new();
              }
              }}

              self.set-native-object($no);
            }

            # only after creating the native-object, the gtype is known
            self._set-class-info('LIBCLASSNAME');
          }
        }

        EOTEMPLATE
    }

    $template-text ~~ s:g/ 'RAKU-CLASS-NAME' /$*raku-class-name/;
    $template-text ~~ s:g/ 'LIBRARYMODULE' /{$*raku-lib-name}::{$*raku-class-name}/;
    $template-text ~~ s:g/ 'BASE-SUBNAME' /$*base-sub-name/;
    $template-text ~~ s:g/ 'LIBCLASSNAME' /$*lib-class-name/;
    $output-file.IO.spurt( $template-text, :append);

    note "add BUILD routine to $output-file";
  }
}

#-------------------------------------------------------------------------------
sub get-sub-doc ( Str:D $sub-name, Str:D $source-content --> List ) {

#  return ( '', '') unless $source-content;

  return ( '', []) unless $source-content ~~ m/ '/**' <[\s\*]>+ $sub-name/;

  $source-content ~~ m/ '/**' <[\s\*]>+ $sub-name ':' $<sub-doc> = [ .*? '*/' ] /;
  my Str $doc = ~($<sub-doc> // '');

  my Array $items-src-doc = [];
  my Bool $gather-items-doc = True;
  my Str ( $item, $sub-doc) = ( '', '');
  my Int $line-count = 0;
  for $doc.lines -> $line {

    if $line ~~ m/ ^ \s+ '* @' <alnum>+ ':' $<item-doc> = [ .* ] / {
      # check if there was some item. if so, save before set to new item
      # @ can be in documentation too!

      #if $gather-items-doc {
      #  $items-src-doc.push(primary-doc-changes($item)) if ?$item;
      #}
      $items-src-doc.push(primary-doc-changes($item))
        if $gather-items-doc and ?$item;

      # new item. remove first space char
      $item = ~($<item-doc> // '');
      $item ~~ s/ ^ \s+ //;
    }

    elsif $line ~~ m/ ^ \s+ '*' \s+ $<doc> = [ .+ ] / {
      # additional doc for items. separate with a space.
      if $gather-items-doc {
        $item ~= " " ~ ~($<doc> // '');
      }

      else {
        $sub-doc ~= "\n" ~ ~($<doc> // '');
      }
    }


    # an empty line is end of items doc and starts/continues sub doc
    elsif $line ~~ m/ ^ \s+ '*' \s* $ / {
      if $gather-items-doc {
        # save previous item
        $items-src-doc.push(primary-doc-changes($item));

        $gather-items-doc = False;
        $sub-doc ~= " ";
      }

      else {
        $sub-doc ~= "\n";
      }
    }

    $line-count++ if ?$sub-doc;
    last if $line-count > 100;
  }

  # in case there is no doc, we still need to save the last arg item
  if $gather-items-doc {
    $items-src-doc.push(primary-doc-changes($item));
  }

  # cleanup documentation of sub
  $sub-doc ~~ s/ 'Since:' \s*? \d+\.\d+ //;
#  $sub-doc ~~ s:g/^^ \s+ //;
#  $sub-doc ~~ s:g/ \s+ $$/\n/;
#  $sub-doc ~~ s:g/ <[\ \t]>+ / /;
  $sub-doc ~~ s/ \s* 'Returns:'/\n\nReturns:/;
#  $sub-doc ~~ s/ \n $//;

  $sub-doc ~~ s/^ \s+ //;
  $sub-doc ~~ s/ \s+ $//;
#  $sub-doc ~~ s:g/ \n\n\n* /\n\n/;
  $sub-doc ~~ s:g/ \n\n /[=====]/;
  $sub-doc ~~ s:g/ \s+ / /;
  $sub-doc ~~ s:g/ '[=====]' /\n\n/;

  ( primary-doc-changes($sub-doc), $items-src-doc )
}

#-------------------------------------------------------------------------------
# get the class title and class info from the source file
sub get-section ( Str:D $source-content --> List ) {

  return ( '', '', '') unless $source-content;

  $source-content ~~ m/ '/**' .*? SECTION ':' .*? '*/' /;
  return ( '', '', '') unless ?$/;

  my Str $section-doc = ~$/;

  # get short description and remove it from $section-doc
  $section-doc ~~ m:i/
      ^^ \s+ '*' \s+ '@Short_description:' \s*
      $<text> = [
        [ \s+ '*' \s+ [ <-[@]> || \S ] .*? \n ] ||
        [ .*? \n ]
      ]
  /;
  my Str $short-description = ~($<text>//'');
  $section-doc ~~ s:i/ ^^ \s+ '*' \s+ '@Short_description:'
                       \s* $short-description//;

  $short-description ~~ s:g/ \n\s* '*' \s* / /;
#note 'sd: ', $short-description;
  $short-description = cleanup-source-doc($short-description);


  # get see also and remove it from $section-doc
  $section-doc ~~ m:i/ ^^ \s+ '*' \s+ '@See_also:' \s* $<text> = [.*?] $$ /;
  my Str $see-also = ~($<text>//'');
  $section-doc ~~ s:i/ ^^ \s+ '*' \s+ '@See_also:' [.*?] \n //;

  # cleanup rest
#note "get-section 0: $section-doc";

  $section-doc ~~ s:i/ ^^ \s+ '*' \s+ 'SECTION:' [.*?] \n //;
  $section-doc ~~ s:i/ ^^ \s+ '*' \s+ '@Title:' [.*?] \n //;
  $section-doc = cleanup-source-doc($section-doc);
  $section-doc ~~ s:i/ '#' \s+ CSS \s+ nodes
                     /\n\n=head2 Css Nodes\n\n/;

#note "get-section 1: $section-doc";
  $section-doc ~~ s:g:i/ ^^ '#' '#'? \s+ /\n=head2 /;
#  $section-doc ~~ s:g/ \n\s* '*' \s* / /;


#note "doc 2: ", $section-doc;

  ( primary-doc-changes($section-doc),
    primary-doc-changes($short-description),
    (?$see-also ?? "=head2 See Also\n\n" ~ primary-doc-changes($see-also) !! '')
  )
}

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

  print "Find signals ";

  # In this case classes are groups of signals with the same number of arguments
  # Use like:
  #   my Str $signal-class = "w$arg-count";
  #   $signal-classes{$signal-class}.push: $signal-name;
  my Hash $signal-classes = %();

  # Container for all signal docs
  # Use like;
  #   $signal-doc-entries{$signal-name} = $signal-doc;
  my Hash $signal-doc-entries = %();

  # Make a loop to go through the source code of GTK+. Found sections are
  # removed and thus, when no sections are found, loop stops.
  loop {
#print "\n";
    print ".";
    $*OUT.flush;

    my ( $signal-name, $function-doc, $signal-args) =
      get-signal-function-declaration($source-content);

    #last unless $function-doc;
    last unless ?$signal-name;

    # Construct a class name for this signal and add signal to that class
    my Str $signal-class = 'w' ~ @$signal-args[8];
    $signal-classes{$signal-class} = []
      unless $signal-classes{$signal-class}:exists;
    $signal-classes{$signal-class}.push: $signal-name;

#note "GS 0: $*lib-class-name, $function-doc, $signal-name, ", $signal-args.join(', ');

    my ( $signal-doc, $items-src-doc) = get-arg-doc($function-doc);
#note "GS 1: $signal-doc, ", @$items-src-doc.gist;

    my ( $return-type, $signal-arg-types) = get-arg-types(@$signal-args);
#note "GS 2: $return-type", @$signal-arg-types.gist;


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

      =comment -----------------------------------------------------------------------
      =comment #TS:0:$signal-name:
      =head2 $signal-name
      $signal-doc
        method handler (
      EOSIG

    my $arg-count;

    # Show the argument list of the handler together with their types. Skip
    # the first argument which is the object used to register the signal.
    loop (
      $arg-count = 1; $arg-count < $signal-arg-types.elems; $arg-count++
    ) {

      my Hash $var-counts-when-undef = {};
      my Str $item-src-doc = $items-src-doc[$arg-count][0] // Str;
#`{{
      unless ?$item-src-doc {
        my Str $key = $signal-arg-types[$arg-count].lc;
        my Str $var-name;
        if $var-counts-when-undef{$key}:exists {
          $var-counts-when-undef{$key}++;
          $item-src-doc = $key ~ $var-counts-when-undef{$key};
        }
        else {
          $var-counts-when-undef{$key} = 1;
          $item-src-doc = $key ~ $var-counts-when-undef{$key};
        }
      }
}}
      $signal-doc ~= "    $signal-arg-types[$arg-count] \$$item-src-doc,\n";
#note "get-signals: ", ($arg-count, $signal-arg-types[$arg-count], $item-src-doc)>>.gist.join(', ');
    }

    # Add the arguments given by the register-signal() method
    $signal-doc ~= Q:qq:to/EOSIG/;
          Int :\$_handler-id,
          N-GObject :\$_native-object,
          *\%user-options
      EOSIG

    # Add the return type
    if ?$return-type {
      $signal-doc ~= "\n    --> $return-type\n";
    }

    # Add finish handler method
    $signal-doc ~= "  )\n\n";

    # Add itemized argument documentation
    loop ( $arg-count = 1; $arg-count < $items-src-doc.elems; $arg-count++ ) {
      $signal-doc ~=
       "=item \$$items-src-doc[$arg-count][0]; $items-src-doc[$arg-count][1]\n";
    }

    # And the extra provided arguments
    $signal-doc ~= "=item \$_handler-id; The handler id which is returned from the registration\n";
    $signal-doc ~= "=item \$_native-object; The native object provided by the caller wrapped in the Raku object which registered the signal.\n";
    $signal-doc ~= "=item \%user-options; A list of named arguments provided at the C<register-signal\()> method\n";

#note "GS 3: $signal-doc";
    $signal-doc-entries{$signal-name} = $signal-doc;
  }

  print "\n";

  # No output when there are no signals found
  if ?$signal-doc-entries {
    # Make one big signal doc
    my Str $doc-total = Q:q:to/EOSIGDOC/;

      #-------------------------------------------------------------------------------
      =begin pod
      =head1 Signals

      EOSIGDOC

    print "\n";
    for $signal-doc-entries.keys.sort -> $signal-name {
      note "add signal $signal-name";
      $doc-total ~= $signal-doc-entries{$signal-name};
    }

    $doc-total ~= "\n=end pod\n";

#    $doc-total = primary-doc-changes($doc-total);

    # And append to output file
    note "add signal information to $output-file";
    $output-file.IO.spurt( $doc-total, :append);
  }

  # Now modify the new body to insert the signals
  modify-newbody-for-signals($signal-classes);
}

#-------------------------------------------------------------------------------
sub get-signal-function-declaration ( Str:D $source-content is rw --> List ) {

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

  # Search doc for function declaration. Then remove from source.
  # Stop if none left
  $source-content ~~ m/
    $<signal-doc> = [
      '/**'                               # start c-comment block
      \s+ '*' \s+ <alnum>+                # first line has a class name
      '::' [ <alnum> || '-' ]+ ':'        # and a ::signal name:
      .*? '*/'
    ]
  /;

  my Str $function-doc = ~($<signal-doc> // '');
#note "\nget-signal-function-declaration 0 $*lib-class-name: \n", $function-doc;

  # possibly no documentation
  if ?$function-doc {
    # remove from source
    $source-content ~~ s/$function-doc//;

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

  # 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
      ]
      '"' <-[\"]>+ '"' .*?
    ] ');'
  /;
}}

  $source-content ~~ m/
    $<signal-args> = [
      [ 'g_signal_new_class_handler' || 'g_signal_new' ]
      \s* '(' \s* ['I_("' || '"'] $signal-name ['")' || '"']
      .*? ');'                              # till the signal spec ends
    ]
  /;


#if $signal-name ~~ m/ 'preedit-changed' / {
note $?LINE, ', ', ($<signal-args> // '-').Str;
#exit;
#}

  # Save and remove from source
  my Str $signal-args-text = ~($<signal-args>//'');
  $function-doc = '' unless $signal-args-text;

#note "get-signal-function-declaration 3: $signal-name, $signal-args-text";

  $source-content ~~ s/$signal-args-text//;
  $signal-args-text ~~ s/ ');' //;
#     s/ 'g_signal_new' '_class_handler'? \s* '(' $signal-args-text ');' //;

    # When there's no doc, signal name must be retrieved from function argument.
    # Mostly noted as I_("some name")
    unless $signal-name {
      $signal-args-text ~~ m/ '"' $<signal-name> = [ <-[\"]>+ ] '"' /;
      $signal-name = ($<signal-name>//'').Str;
    }

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

#note "get-signal-function-declaration 4: ", ( $signal-name, |@signal-args).join(', ');

  ( $signal-name, $function-doc, @signal-args)
}

#-------------------------------------------------------------------------------
sub get-arg-doc ( Str $function-doc --> List ) {

  my Str $signal-doc = '';

  # True when scanning for arguments in document. It starts with it and
  # ends after an empty line
  my Bool $item-scan = True;

  my Str $item-doc = '';
  my Str $item-name = '';

  my Array $items-src-doc = [];
  my Int $item-count = 0;

  for $function-doc.lines -> $line {
#note "L: $line";

    # Argument found when $item-scan still True and starts with '@'.
    if $item-scan and $line ~~ m/^ \s* '*' \s+ '@' / {
      # Get the argument info from the current line.
      # Something like "* @argument-name: documentation".
      $line ~~ m/ '*' \s+ '@' $<item-name> = [<alnum>+] ':'
                  \s* $<item-doc> = [ .* ]
                /;

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

      $items-src-doc.push: [ $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);
      $items-src-doc[*-1][1] ~= $item-doc ~ " ";
#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;

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

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

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

  # when there is no sub doc, it might end a bit abdrupt
  #note "ISD 2: $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;

  # Cleanup and drop the Since: version line
  $signal-doc = primary-doc-changes($signal-doc);
  $signal-doc ~~ s/\s+ 'Since:' \s+ \d+ \. \d+ //;

#note "GAN: ", $items-src-doc.gist;
  ( $signal-doc, $items-src-doc);
}

#-------------------------------------------------------------------------------
sub get-arg-types ( @signal-args --> List ) {

#note "GAT: '@signal-args[8]': ", @signal-args.join("\n  ");

  # get a return type from arg 7
  my Str $return-type = raku-sig-type(@signal-args[7] // 'any');

  # process handler argument types. nbr args at 8, types at 9 and further
  my @signal-arg-types = 'N-GObject';
#note 'get-arg-types: ', @signal-args.join(', ');
  my Int $arg-count = @signal-args[8].Int;
  for ^$arg-count -> $i {
#note "  A[9 + $i]: @signal-args[9 + $i]";

    @signal-arg-types.push: raku-sig-type(@signal-args[9 + $i]);
  }

  ( $return-type, @signal-arg-types);
}

#-------------------------------------------------------------------------------
sub raku-sig-type ( Str $native-type --> Str ) {
  my Str $raku-type;

  given $native-type {
    when 'G_TYPE_NONE' { $raku-type = ''; }
    when 'G_TYPE_BOOLEAN' { $raku-type = 'Bool'; }
    when 'G_TYPE_INT' { $raku-type = 'Int'; }
    when 'G_TYPE_UINT' { $raku-type = 'UInt'; }
    when 'G_TYPE_STRING' { $raku-type = 'Str'; }
    when 'GTK_TYPE_TREE_ITER' { $raku-type = 'N-GtkTreeIter'; }
    when 'G_TYPE_LONG' {
      $raku-type = 'glong #`{ use Gnome::N::GlibToRakuTypes }':api<1>;
    }
    when 'G_TYPE_FLOAT' { $raku-type = 'Num'; }
    when 'G_TYPE_DOUBLE' {
      $raku-type = 'gdouble #`{ use Gnome::N::GlibToRakuTypes }':api<1>;
    }

    when 'G_TYPE_ERROR' {
      $raku-type = 'N-GError #`{ native Gnome::Glib::Error }';
    }
    when 'G_TYPE_CLOSURE' {
      $raku-type = 'N-GObject #`{ native Gnome::GObject::Closure }';
    }
    when 'G_TYPE_APP_INFO' {
      $raku-type = 'N-GObject #`{ native Gnome::Gio::AppInfo }';
    }
#    when 'G_TYPE_OBJECT' { $raku-type = 'N-GObject #`{ native object }'; }
#    when 'GDK_TYPE_OBJECT' { $raku-type = 'N-GObject #`{ native object }'; }
#    when 'GTK_TYPE_OBJECT' { $raku-type = 'N-GObject #`{ native object }'; }
#    when 'GTK_TYPE_WIDGET' { $raku-type = 'N-GObject #`{ native widget }'; }
    when any(<G_TYPE_OBJECT GDK_TYPE_OBJECT GTK_TYPE_OBJECT
              GTK_TYPE_WIDGET GTK_TYPE_MENU
            >) { $raku-type = 'N-GObject #`{ native widget }'; }

    when 'GTK_TYPE_TEXT_ITER' {
      $raku-type = 'N-GObject #`{ native Gnome::Gtk3::TextIter }';
    }
    when 'GTK_TYPE_TREE_ITER' {
      $raku-type = 'N-GtkTreeIter #`{ native Gnome::Gtk3::TreeIter }';
    }
    when 'GDK_TYPE_DISPLAY' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::Display }';
    }
    when 'GDK_TYPE_DEVICE' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::Device }';
    }
    when 'GDK_TYPE_DEVICE_TOOL' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::DeviceTool }';
    }
    when 'GDK_TYPE_MONITOR' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::Monitor }';
    }
    when 'GDK_TYPE_SCREEN' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::Screen }';
    }
    when 'GDK_TYPE_SEAT' {
      $raku-type = 'N-GObject #`{ native Gnome::Gdk3::Seat }';
    }
    when 'GDK_TYPE_MODIFIER_TYPE' {
      $raku-type = 'UInt #`{ GdkModifierType flags from Gnome::Gdk3::Window }';
    }

    # show that there is something if native type not recognized
    default { $raku-type = "Unknown type: $native-type"; }
  }

  $raku-type
}

#-------------------------------------------------------------------------------
sub modify-newbody-for-signals ( Hash $signal-classes ) {

  my Str $bool-signals-added = '';
  my Str $build-add-signals = '';

  # Create the class definition string
  my Str $sig-class-str = '';

  if ?$signal-classes {
    for $signal-classes.kv -> $class, $signals {
      $sig-class-str ~= "\:$class\<";
      $sig-class-str ~= $signals.join(' ');
      $sig-class-str ~= '>, ';
    }

    $bool-signals-added = Q:q:to/EOBOOL/;
      my Bool $signals-added = False;
      #-------------------------------------------------------------------------------
      EOBOOL

    if $class-is-role {
      $build-add-signals = Q:q:to/EOBUILD/;
          # add signal info in the form of w*<signal-name>.
          self.add-signal-types( $?CLASS.^name,
            SIG_CLASS_STR
          );
        EOBUILD
        $build-add-signals ~~ s/SIG_CLASS_STR/$sig-class-str/;
    }

    else {
      $build-add-signals = Q:q:to/EOBUILD/;
          # add signal info in the form of w*<signal-name>.
          unless $signals-added {
            $signals-added = self.add-signal-types( $?CLASS.^name,
              SIG_CLASS_STR
            );

            # signals from interfaces
            #_add_..._signal_types($?CLASS.^name);
          }
        EOBUILD
        $build-add-signals ~~ s/SIG_CLASS_STR/$sig-class-str/;
    }

    # and append signal data to result module
    #$output-file.IO.spurt( $signal-doc, :append);
  }

  # load the module for substitutions
  my Str $module = $output-file.IO.slurp;

  # substitute
  $module ~~ s/ 'BOOL-SIGNALS-ADDED' /$bool-signals-added/;
  $module ~~ s/ 'BUILD-ADD-SIGNALS' /$build-add-signals/;

  # rewrite
  $output-file.IO.spurt($module);
#  note "add signal information to $output-file";
}

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

  return unless $source-content;

  my Str $property-doc;
  my Str $property-name;

  print "Find properties ";
  my Hash $property-doc-entries = %();
  loop {
#print "\n";
    print ".";
    $*OUT.flush;

    $property-doc = '';
    $property-name = '';

    my Str ( $search-prop-doc, $search-prop-spec) =
      property-search($source-content);

    last unless ?$search-prop-doc or ?$search-prop-spec;

    # Skip deprecated properties
    next if $search-prop-doc ~~ m/ '*' \s+ 'Deprecated:' / or
            $search-prop-spec ~~ m/'G_PARAM_DEPRECATED'/;


#    my Str ( $prop-name, $prop-blurp);
#    my Str $prop-args-string;
    my Str ( $prop-name, $prop-blurp) = get-prop-doc($search-prop-doc);
#note "$?LINE: $search-prop-doc, $prop-name";

    my Array $flags;
    my Str $gtype-string;
    my $prop-default;
    my Str $prop-g-type = '';
    my Str ( $min, $max);
    my Array $args;
      ( $flags, $gtype-string, $prop-g-type, $prop-default, $min, $max, $args
      ) = process-prop-args($search-prop-spec);   # if ?$search-prop-spec;
#note 'A1: ', $flags.gist;

    # Arguments have also documentation. See if it is larger and if so,
    # Take the larger part.

#note 'A2: ', $prop-blurp//'', ', ', @$args[2];
    $prop-blurp = (($prop-blurp//'').chars > (@$args[2]//'').chars)
                  ?? $prop-blurp !! @$args[2]//'';

    my Str $type-string = "=item B<Gnome::GObject::Value> type of this property is $prop-g-type\n";
    $type-string ~= "=item The type of this $prop-g-type object is $gtype-string\n" if ?$gtype-string and $gtype-string ne $prop-g-type;

    my Str $flags-text = '';
    for @$flags -> $ftext {
      $flags-text ~= "=item $ftext.\n";
    }

    my Str $min-max-text = '';
    $min-max-text ~= "=item Minimum value is $min.\n" if ?$min;
    $min