#!/usr/bin/env perl
our $VERSION = "1.04";
use strict;
use warnings;
use App::chot;

exit App::chot->new->run(splice @ARGV);

=encoding utf-8

=head1 NAME

chot - Command Heuristic Omni-Tracer

=head1 VERSION

Version 1.04

=head1 SYNOPSIS

    chot [options] command/library

  OPTIONS
     -1   --one           Stop at the first match
     -d   --debug         Show debug output
     -i   --info          Show command trace info
     -n   --dryrun        Show command without executing
     -h   --help          Print this message
     -l   --list          Print file path (-ll for ls -l)
     -L   --deref         Dereference symlinks (with -ll)
     -m   --man           Show documentation
     -N   --[no-]number   Line number display (default: off)
     -r   --raw           Don't resolve symlinks/wrappers
     -v   --version       Print version
     -C   --column[=#]    Use nup for multi-column display
     -p   --pager=#       Specify pager command
     -t   --type=#        Specify handler (Command:Perl:Python:Ruby:Node)
          --py            Shortcut for --type Python
          --pl            Shortcut for --type Perl
          --rb            Shortcut for --type Ruby
          --nd            Shortcut for --type Node
          --bat-theme     Set bat theme per mode (light=X dark=X)

  EXAMPLES
    chot greple              # Look at a script command
    chot Getopt::Long        # Look at a Perl module
    chot --py json           # Look at a Python module
    chot --rb json           # Look at a Ruby library
    chot --nd express        # Look at a Node.js module
    chot -l greple           # Show file path only
    chot --py -m json        # Show documentation

=head1 DESCRIPTION

B<chot> is a utility to locate and display command or library source files.

It is convenient to see a command file written in shell or any other
script language.

For library files, Perl modules are fully supported, and support
for Python, Ruby, and Node.js libraries is included.

The program searches through all file type handlers (Command, Perl, Python,
Ruby, Node by default) and displays all matches found using a pager.

For Homebrew-installed commands, both the wrapper script in C<bin/> and
the actual executable (typically in C<libexec/>) are displayed. This is
useful for understanding how wrapper scripts delegate to their
implementations.

For L<optex|App::optex> commands (symlinks in C<~/.optex.d/bin/>
pointing to the C<optex> binary), the actual command is resolved by
searching C<$PATH>.  If an alias is defined in
C<~/.optex.d/config.toml>, the alias target is followed.
Configuration files (C<~/.optex.d/NAME.rc>) are also included in
the results.  Use C<-i> to see the full resolution chain including
alias definitions.

=head1 TRACING MECHANISM

B<chot> traces commands and libraries through multiple layers of
indirection to find the actual source files.

=head2 Command Tracing

The Command handler resolves commands through the following pipeline:

    PATH search → optex resolution → pyenv shim resolution → Homebrew wrapper resolution

=over 4

=item 1. B<PATH search>

Searches C<$PATH> directories for executable files matching the given
name.

=item 2. B<optex resolution>

If the found path is a symlink to the L<optex|App::optex> binary
(typically in C<~/.optex.d/bin/>), resolves it to the actual command
by searching C<$PATH> (skipping other optex symlinks).  Alias
definitions in C<~/.optex.d/config.toml> and configuration files
(C<~/.optex.d/NAME.rc>) are also included.

=item 3. B<pyenv shim resolution>

If the path is a pyenv shim (in C<~/.pyenv/shims/>), resolves it to
the actual executable using C<pyenv which>.  Both the shim and the
resolved path are included in the output.

=item 4. B<Homebrew wrapper resolution>

If the path is in a Homebrew prefix (e.g., C</opt/homebrew/bin/>),
checks whether it is a shell wrapper that delegates to another
script within the same Homebrew prefix (e.g., in C<libexec/bin/> or
C<libexec/venv/bin/>).  If so, both the wrapper and the actual script
are included.

=back

=head2 Python Module Tracing

The Python handler performs additional resolution to locate meaningful
source files:

=over 4

=item B<Name normalization>

Hyphens in command names are converted to underscores for Python
module lookup (e.g., C<pandoc-embedz> is searched as C<pandoc_embedz>).
This follows the Python packaging convention where distribution names
use hyphens but module names use underscores.

=item B<Interpreter fallback>

When the default C<python3> cannot import a module (e.g., packages
installed only in a Homebrew venv or a specific virtual environment),
the handler examines shebang lines of previously discovered paths to
find the appropriate Python interpreter and retries the import.
This enables tracing of Homebrew-installed Python commands whose
packages are isolated in C<libexec/venv/>.

=item B<Entry point resolution>

When the Python module resolves to an C<__init__.py> file, the handler
searches for a more substantive source file in this order:

=over 4

=item 1. A file matching the module name (e.g., C<gpty.py> for C<gpty>)

=item 2. C<main.py> (common entry point for CLI tools)

=item 3. C<__main__.py>

=item 4. The first non-empty C<.py> file in the package directory

=back

If C<__init__.py> is empty, only the alternative file is returned.
If C<__init__.py> has content, both files are included.

=back

=head2 Examples

For a Homebrew-installed Python command C<pandoc-embedz>:

    $ chot -l pandoc-embedz
    /opt/homebrew/bin/pandoc-embedz               # Homebrew wrapper
    .../libexec/venv/bin/pandoc-embedz            # venv entry point
    .../pandoc_embedz/__init__.py                 # package init
    .../pandoc_embedz/main.py                     # main source

For a pyenv-installed Python command:

    $ chot -l gpty
    /Users/you/.pyenv/shims/gpty                  # pyenv shim
    /Users/you/.pyenv/versions/.../bin/gpty       # actual entry point
    .../gpty/gpty.py                              # main source

=head1 OPTIONS

=over 7

=item B<-1>, B<--one>

Stop at the first handler that finds a match, instead of searching
all handlers (which is the default behavior).

=item B<-d>, B<--debug>

Show debug output on stderr. Displays which handlers are tried
and how paths are resolved.

=item B<-i>, B<--info>

Show command trace information without displaying file contents.
For each command found, displays its type (optex symlink, Homebrew
wrapper, plain command, etc.), file type (perl, bash, binary, etc.),
and resolution chain. For optex commands, also shows alias
definitions and rc file locations.

=item B<-n>, B<--dryrun>

Show the command that would be executed without actually running it.

=item B<-h>, B<--help>

Display this help message and exit.

=item B<-l>, B<--list>

Print file path instead of displaying the file contents.
Use multiple times (C<-ll>) to call C<ls -l> for detailed file information.

=item B<-L>, B<--deref>

Dereference symlinks when listing with C<-ll>.
Passes C<-L> to C<ls> so that the target file's information is shown
instead of the symlink itself.

=item B<-m>, B<--man>

Display manual/documentation using the appropriate tool for each
language:

    Command:  man
    Perl:     perldoc
    Python:   pydoc
    Ruby:     ri
    Node.js:  npm docs

If the first handler's documentation is not available (e.g., no man
page exists), the next handler is tried automatically.  For example,
a Python command without a man page will fall back to C<pydoc>.

=item B<-N>, B<--number>, B<--no-number>

Enable or disable line number display in the pager.  Default is
C<--no-number>.

For C<bat>, C<--number> uses C<--style=full> and C<--no-number>
uses C<--style=header,grid,snip>.  For C<less>, C<--number> adds
C<-N> option.

=item B<-r>, B<--raw>

Show raw paths without resolving optex symlinks, pyenv shims, or
Homebrew wrapper scripts to their actual executables.

=item B<-v>, B<--version>

Display version information and exit.

=item B<-C>, B<--column>[=I<N>]

Use L<nup|App::nup> for multi-column display.
If I<N> is specified, it is passed to C<nup> as the number of columns.

    chot -C greple           # multi-column with default layout
    chot -C2 greple          # 2-column layout

The source files are shown with syntax highlighting and formatted
into multi-column pages, equivalent to C<nup chot greple>.

=item B<-p>, B<--pager> I<command>

Specify the pager command to use for displaying files.
Defaults to the C<$CHOT_PAGER> environment variable, or C<bat> if available,
otherwise C<less>.

When multiple files are found, C<bat> displays all files continuously
with syntax highlighting. With C<less>, use C<:n> to navigate to the
next file and C<:p> for the previous file.

=item B<-t>, B<--type> I<handler[:handler:...]>

Specify which file type handlers to use and in what order.
Handlers are specified as colon-separated names (case-insensitive).

Default: C<Command:Perl:Python:Ruby:Node>

Available handlers:

    Command   Search for executable commands in $PATH
    Perl      Search for Perl modules in @INC
    Python    Search for Python libraries using inspect module
    Ruby      Search for Ruby libraries using $LOADED_FEATURES
    Node      Search for Node.js modules using require.resolve

Examples:

    chot --type Perl Getopt::Long       # Only search Perl modules
    chot --type python json             # Only search Python modules
    chot --type ruby yaml               # Only search Ruby libraries
    chot --type node express            # Only search Node.js modules

=item B<--py>

Shortcut for C<--type Python>. Search only Python modules.

=item B<--pl>

Shortcut for C<--type Perl>. Search only Perl modules.

=item B<--rb>

Shortcut for C<--type Ruby>. Search only Ruby libraries.

=item B<--nd>

Shortcut for C<--type Node>. Search only Node.js modules.

=item B<--bat-theme> I<mode>=I<theme>

Specify the default bat theme for light or dark terminal backgrounds.
Can be used multiple times.

    --bat-theme light=GitHub --bat-theme dark=Monokai

If C<bat> is used as the pager and C<BAT_THEME> is not set, the
terminal background luminance is detected and the appropriate theme
is applied.  Built-in defaults are C<Coldark-Cold> for light and
C<Coldark-Dark> for dark backgrounds.

=item B<--suffix> I<extension>

Specify file suffix/extension to search for (mainly for Perl modules).

Default: C<.pm>

=item B<--skip> I<pattern>

Specify directory patterns to skip during search.
Can be used multiple times to specify multiple patterns.

Default: none (optex symlinks are resolved automatically)

=back

=head1 HANDLER MODULES

The program uses a plugin architecture where different file type handlers
are dynamically loaded based on the C<--type> option. Each handler must
implement a C<get_path($app, $name)> method.

=over 7

=item B<App::chot::Command>

Handler for executable commands. Searches through C<$PATH> environment
variable to find executable files.

For L<optex|App::optex> symlinks (commands that are symlinks pointing
to the C<optex> binary), the handler resolves them to the actual
command by searching C<$PATH> (skipping other optex symlinks). If the
command has an alias defined in C<~/.optex.d/config.toml>, the alias
target is used for resolution. When a C<~/.optex.d/NAME.rc>
configuration file exists, it is included in the results.

=item B<App::chot::Perl>

Handler for Perl modules. Searches through C<@INC> paths to find
Perl module files (.pm and .pl files).

=item B<App::chot::Python>

Handler for Python libraries. Executes Python's C<inspect.getsourcefile()>
function to locate Python module files.  When the default C<python3>
cannot find a module, falls back to interpreters discovered from
shebang lines of previously found paths (e.g., Homebrew venv Python).

=item B<App::chot::Ruby>

Handler for Ruby libraries. Loads the specified library with C<require>
and inspects C<$LOADED_FEATURES> to find the actual file path.
Documentation is displayed using C<ri>.

=item B<App::chot::Node>

Handler for Node.js modules. Uses C<require.resolve> with global paths
to locate module entry points.
Documentation is opened via C<npm docs>.

=back

=head1 EXAMPLES

    # Display a script command (brew is a shell script)
    chot brew

    # Display a Perl module
    chot List::Util

    # Display a Python module
    chot --py json

    # Just show the file path
    chot -l brew

    # Show detailed file information
    chot -ll Getopt::Long

    # Show documentation (perldoc for Perl, pydoc for Python, ri for Ruby, etc.)
    chot -m List::Util
    chot --py -m json
    chot --rb -m json
    chot -m ls

    # Only search for Perl modules
    chot --pl Data::Dumper

    # Only search for Python modules
    chot --py os.path

    # Display a Ruby library
    chot --rb yaml

    # Display a Node.js module
    chot --nd express

    # Trace a Homebrew venv Python command
    chot -l pandoc-embedz

    # Show documentation with fallback (man → pydoc)
    chot -m speedtest-z

    # Multi-column display using nup
    chot -C greple
    chot -C2 greple

    # Use a custom pager
    chot --pager "vim -R" List::Util

    # Pass options to the pager (use -- to separate)
    chot -- +10 List::Util  # Open at line 10

=head1 INSTALLATION

    # Homebrew
    brew tap tecolicom/tap
    brew install app-chot

    # From CPAN
    cpanm App::chot

    # From GitHub
    cpanm https://github.com/tecolicom/App-chot.git

=head1 ENVIRONMENT

=over 7

=item B<CHOT_PAGER>

Default pager command to use when displaying files.
If not set, C<bat> is used if available, otherwise C<less>.

=item B<BAT_THEME>

Theme for C<bat> pager.  If set, takes precedence over C<--bat-theme>
option and automatic detection.  See C<bat --list-themes> for available
themes.

=item B<OPTEX_ROOT>

Root directory for optex configuration.  Defaults to C<~/.optex.d>.
Used to locate C<config.toml> and C<*.rc> files for optex command
resolution.

=back

=head1 BUGS

When inspecting itself with C<chot chot>, the display order of the
wrapper script and the actual executable may be reversed.  This is
because the wrapper adds C<libexec/bin> to C<$PATH>, causing the
raw executable to be found before the wrapper during path search.

=head1 SEE ALSO

L<App::chot>, L<App::optex>, L<Getopt::EX>, L<Getopt::EX::Hashed>

=head1 AUTHOR

Kazumasa Utashiro

=head1 LICENSE

Copyright 2021-2026 Kazumasa Utashiro.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
