id = "ctags" name = "Universal Ctags" homepage = "https://ctags.io/" description = "Generate an index (or tag) file of language objects found in source files." # The green tag mark the Universal Ctags organisation uses as its avatar; # the project publishes no separate logo file. icon = "https://github.com/universal-ctags.png" executables = ["ctags"] [dotfiles] # https://docs.ctags.io/en/latest/option-file.html: "At start-up time, ctags # loads files having .ctags as a file extension under the following statically # defined directories: # 1. $XDG_CONFIG_HOME/ctags/, or $HOME/.config/ctags/ if $XDG_CONFIG_HOME is # not defined # 2. $HOME/.ctags.d/ # 3. $HOMEDRIVE$HOMEPATH/ctags.d/ (on Windows)" # The first reads the variable itself, so it is [configHome]. The other two are # home-directory directories; $HOMEDRIVE$HOMEPATH is the Windows user profile, # which resolves to the same place as ~. The remaining two entries on that list, # ./.ctags.d/ and ./ctags.d/, are per-project and not user level. # # The same page says Universal Ctags "doesn't load any of the files Exuberant # Ctags loads at start-up", so ~/.ctags is Exuberant Ctags' file — its man page # (https://ctags.sourceforge.net/ctags.html, FILES) lists $HOME/.ctags — and it # is here because on many machines the binary called `ctags` is still Exuberant. paths = [ "[configHome]/ctags/", "~/.ctags.d/", "~/ctags.d/", "~/.ctags", ] # ctags writes nothing back into these directories; the tags file it produces # goes wherever the user asked for it. secret = [] # ctags reads these files once per run and exits, so rewriting one between runs # cannot disturb anything. side_effect = false # No machine_lines: these files hold --langdef, --regex- and --exclude # options, which are the definitions a user wants on every machine. An # --options=/absolute/path line exists but is rare, and a prefix rule on # "--options" would strand the common relative form with it. [commands] format = 1 features = ["standard_streams"] label = "Generate tags" description = "Index source files into a tags file with Universal Ctags. Per-language kinds, fields and extras, regex parsers and option files are left out." quality = "ai-draft" parser = { end_of_options = "--", interleave = "permute", long_equals = true, short_attached = true, short_bundles = true } [[commands.source]] id = "manual" kind = "manual" url = "https://docs.ctags.io/en/latest/man/ctags.1.html" revision = "2026-10-27" evidence = """ ``--exclude=`` ``--recurse[=(yes|no)]`` ``-R`` Equivalent to ``--recurse``. ``-L `` ``--append[=(yes|no)]`` ``-a`` Equivalent to ``--append``. ``-f `` ``--output-format=(u-ctags|e-ctags|etags|xref|json)`` ``--sort=(yes|no|foldcase)`` ``--languages=[+|-](|all)`` """ [[commands.field]] id = "files" label = "Files or directories" description = "With Recurse on and nothing listed, the current directory is indexed." type = "path" position = 0 multiple = true path = { kind = "any", role = "input" } sources = ["manual"] [[commands.field]] id = "recurse" label = "Recurse into directories" type = "boolean" option = ["--recurse", "-R"] sources = ["manual"] [[commands.field]] id = "output" label = "Tag file" description = "Defaults to tags; - writes to standard output." type = "path" option = ["-f"] path = { kind = "file", role = "output", must_exist = false, standard_stream = true } effect = "overwrite" sources = ["manual"] [[commands.field]] id = "append" label = "Append to existing tag file" type = "boolean" option = ["--append", "-a"] sources = ["manual"] [[commands.field]] id = "exclude" label = "Exclude pattern" type = "string" option = ["--exclude"] multiple = true sources = ["manual"] [[commands.field]] id = "languages" label = "Languages" description = "Comma-separated list, or all." type = "string" option = ["--languages"] sources = ["manual"] [[commands.field]] id = "sort" label = "Sort tags" type = "enum" option = ["--sort"] choices = [{ value = "yes", label = "Yes" }, { value = "no", label = "No" }, { value = "foldcase", label = "Case-folded" }] sources = ["manual"] [[commands.field]] id = "output_format" label = "Output format" type = "enum" option = ["--output-format"] choices = [{ value = "u-ctags", label = "u-ctags" }, { value = "e-ctags", label = "e-ctags" }, { value = "etags", label = "etags" }, { value = "xref", label = "xref" }, { value = "json", label = "JSON" }] sources = ["manual"] [[commands.field]] id = "file_list" label = "File list" description = "Read the names of files to index from a file; - reads standard input." type = "path" option = ["-L"] path = { kind = "file", role = "input", standard_stream = true } sources = ["manual"] [[commands.task]] id = "project" label = "Index this project" fields = ["files", "recurse", "exclude", "languages"] required = [] set = { recurse = [true] } [[commands.task]] id = "json" label = "Print JSON to stdout" fields = ["files", "recurse", "exclude"] required = [] set = { recurse = [true], output = ["-"], output_format = ["json"] } lock = ["output", "output_format"] [[commands.group]] id = "basic" label = "Basic" fields = ["files", "recurse", "output", "exclude", "languages"] [[commands.group]] id = "advanced" label = "Advanced" fields = ["append", "sort", "output_format", "file_list"]