@@ -154,6 +154,92 @@ def failure
154154 end
155155 end
156156
157+ # An action of the CLI that generates ctags for the given source.
158+ class CTags < Action
159+ attr_reader :entries
160+
161+ def initialize ( options )
162+ super ( options )
163+ @entries = [ ]
164+ end
165+
166+ def run ( item )
167+ lines = item . source . lines ( chomp : true )
168+
169+ SyntaxTree
170+ . index ( item . source )
171+ . each do |entry |
172+ line = lines [ entry . location . line - 1 ]
173+ pattern = "/^#{ line . gsub ( "\\ " , "\\ \\ \\ \\ " ) . gsub ( "/" , "\\ /" ) } $/;\" "
174+
175+ entries << case entry
176+ when SyntaxTree ::Index ::ModuleDefinition
177+ parts = [ entry . name , item . filepath , pattern , "m" ]
178+
179+ if entry . nesting != [ [ entry . name ] ]
180+ parts << "class:#{ entry . nesting . flatten . tap ( &:pop ) . join ( "." ) } "
181+ end
182+
183+ parts . join ( "\t " )
184+ when SyntaxTree ::Index ::ClassDefinition
185+ parts = [ entry . name , item . filepath , pattern , "c" ]
186+
187+ if entry . nesting != [ [ entry . name ] ]
188+ parts << "class:#{ entry . nesting . flatten . tap ( &:pop ) . join ( "." ) } "
189+ end
190+
191+ unless entry . superclass . empty?
192+ inherits = entry . superclass . join ( "." ) . delete_prefix ( "." )
193+ parts << "inherits:#{ inherits } "
194+ end
195+
196+ parts . join ( "\t " )
197+ when SyntaxTree ::Index ::MethodDefinition
198+ parts = [ entry . name , item . filepath , pattern , "f" ]
199+
200+ unless entry . nesting . empty?
201+ parts << "class:#{ entry . nesting . flatten . join ( "." ) } "
202+ end
203+
204+ parts . join ( "\t " )
205+ when SyntaxTree ::Index ::SingletonMethodDefinition
206+ parts = [ entry . name , item . filepath , pattern , "F" ]
207+
208+ unless entry . nesting . empty?
209+ parts << "class:#{ entry . nesting . flatten . join ( "." ) } "
210+ end
211+
212+ parts . join ( "\t " )
213+ when SyntaxTree ::Index ::AliasMethodDefinition
214+ parts = [ entry . name , item . filepath , pattern , "a" ]
215+
216+ unless entry . nesting . empty?
217+ parts << "class:#{ entry . nesting . flatten . join ( "." ) } "
218+ end
219+
220+ parts . join ( "\t " )
221+ when SyntaxTree ::Index ::ConstantDefinition
222+ parts = [ entry . name , item . filepath , pattern , "C" ]
223+
224+ unless entry . nesting . empty?
225+ parts << "class:#{ entry . nesting . flatten . join ( "." ) } "
226+ end
227+
228+ parts . join ( "\t " )
229+ end
230+ end
231+ end
232+
233+ def success
234+ puts ( <<~HEADER )
235+ !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
236+ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
237+ HEADER
238+
239+ entries . sort . each { |entry | puts ( entry ) }
240+ end
241+ end
242+
157243 # An action of the CLI that formats the source twice to check if the first
158244 # format is not idempotent.
159245 class Debug < Action
@@ -488,6 +574,8 @@ def run(argv)
488574 AST . new ( options )
489575 when "c" , "check"
490576 Check . new ( options )
577+ when "ctags"
578+ CTags . new ( options )
491579 when "debug"
492580 Debug . new ( options )
493581 when "doc"
0 commit comments