#!/bin/sh

# ------------------------------------------------------------

rm -f tags
touch tags
find . -name '*.retro' -print0 | xargs -0 -n 1 retro $0 >>tags
find . -name '*.forth' -print0 | xargs -0 -n 1 retro $0 >>tags
cat tags | sort | uniq >tags2
mv tags2 tags
exit

--------------------------------------------------------------

This will scan a source file and create output for a `tags`
file in the minimal *ctags* format. In this, the tags file
will contain one line per tag, with a tab separated structure:

    tag-name<tab>tag-file<tab>tag-address

I am using the line number as the tag address.

To generate a tags file:

    retro-tags

Tags for variables, constants, and data structures are not
always identified correctly. Specifically:

    'foo d:create ....             <- not identified
    #1 'foo const  #2 'bar const   <- only the last is identified
    'foo var  'bar var             <- only the last is identified

For these, this assumes one name defined per line, with nothing
following. Better detection and handling of this is left open
for a future project.

To start, I bring in the `retro-unu` tool to locate the code
blocks and call a combinator for each line in the code block.
This one is extended to keep track of the tag address and
file name as well.

~~~
'TagAddress var
'TagFile var

{{
  'Fenced var
  :toggle-fence @Fenced not !Fenced ;
  :fenced? (-f) @Fenced ;
  :handle-line (s-)
    fenced? [ over call ] [ drop ] choose ;
  :prepare
    #0 !TagAddress   over s:keep !TagFile ;
---reveal---
  :unu (sq-)
    prepare
    swap [ &TagAddress v:inc
           dup '~~~ s:eq?
           [ drop toggle-fence ]
           [ handle-line       ] choose
         ] file:for-each-line drop ;
}}
~~~

Next, identification of things to tag begins. This will use
multiple passes of the source file.

First, colon definitions.

~~~
:colon-definition?
  dup ': s:begins-with? ;

:output-location
  tab @TagFile #2 + s:put tab @TagAddress n:put nl ;

:output-name
  ASCII:SPACE s:tokenize #0 a:fetch n:inc s:put ;

#0 script:get-argument [ s:trim colon-definition? &drop -if; output-name output-location ] unu
~~~

Then variables.

~~~
:variable?
  dup 'var s:ends-with? over 'var-n s:ends-with? or ;

:output-name
  ASCII:SPACE s:tokenize dup a:length #2 - a:fetch n:inc s:put ;

#0 script:get-argument [ s:trim variable? &drop -if; output-name output-location ] unu
~~~

Constants.

~~~
:constant?
  dup 'const s:ends-with? ;

:output-name
  ASCII:SPACE s:tokenize dup a:length #2 - a:fetch n:inc s:put ;

#0 script:get-argument [ s:trim constant? &drop -if; output-name output-location ] unu
~~~

And finally, words made with `d:create`:

~~~
:created?
  dup 'd:create s:ends-with? ;

:output-name
  ASCII:SPACE s:tokenize dup a:length #2 - a:fetch n:inc s:put ;

#0 script:get-argument [ s:trim created? &drop -if; output-name output-location ] unu
~~~
