Internal Commands Utility#

click-repl allows usage of certain prefixes to execute system shell commands via REPL. It also provides other pre-defined, helpful internal commands registered within it. These commands are not of type Command.

Internal Commands#

The internal commands can be invoked with a prefix associated with their name (Default: :). Run :help in the REPL to know about its usage.

> :help
REPL help:

  External/System Commands:
    Prefix External/System commands with "!".

  Internal Commands:
    Prefix Internal commands with ":".
    :clear, :cls      Clears screen.
    :?, :h, :help     Displays general help information.
    :exit, :q, :quit  Exits the REPL.

InternalCommandSystem#

All the internal commands are defined and accessed from InternalCommandSystem object. You can get this object from the internal_command_system attribute of the current REPL session’s ReplContext object.

1 from click_repl.globals_ import get_current_repl_ctx
2
3 ics_obj = get_current_repl_ctx().internal_command_system # <class 'InternalCommandSystem'>

Add/Remove Internal Commands#

This object can also be used to define and add your own internal command. It’s done by using the register_command() decorator. It takes a function, names/aliases and description for it. The provided function’s name and docstring is the command’s only name and description by default.

To remove an internal command, pass any one of the aliases of the command into remove_command() to remove the command, along with all of its other aliases.

Note

  • You can register and delete internal commands from anywhere, as long as you can access the current REPL session’s ReplContext object.

  • The callback function for your custom internal command must be of type Callable[[], None]. That is, it shouldn’t take in any arguments, and return nothing.

  • remove_command() removes all the aliases of the given alias of a command, by default. To remove only the mentioned alias, set remove_all_aliases to False to the method.

For this example, we register the hi function as an internal command, and delete it later on.

 1 import click
 2 import click_repl
 3
 4 @click.group(invoke_without_command=True)
 5 @click.pass_context
 6 def main(ctx):
 7     click_repl.repl(ctx)
 8
 9 @main.command()
10 @click_repl.pass_context
11 def add_internal_command(repl_ctx: click_repl.ReplContext):
12     ics_obj = repl_ctx.internal_command_system
13
14 @ics_obj.register_command(names=["hi", "greet", "hola"])
15 def hi():
16     print("Hi!")
17
18 @main.command()
19 @click_repl.pass_context
20 def del_internal_command(repl_ctx: click_repl.ReplContext):
21     ics_obj = repl_ctx.internal_command_system
22     ics_obj.remove_command("hi", remove_all_aliases=False) # Removes only alias 'hi'
23     # ics_obj.remove_command("hi") # Removes all the aliases that belong to command 'hi'
24
25
26 main()
> add-internal-command
> :hi
Hi!
> del-internal-command
> :hi
Hi!
'hi', command not found

Default Internal Commands#

There are 3 internal commands registered by default. They are:

  1. clear - Clears the terminal screen.

    Aliases: clear, cls

  2. help - Displays general help information about the internal commands.

    Aliases: ?, h, help

    > :help
    REPL help:
    
    External/System Commands:
      Prefix External/System commands with "!".
    
    Internal Commands:
      Prefix Internal commands with ":".
      :clear, :cls      Clears screen.
      :?, :h, :help     Displays general help information.
      :exit, :q, :quit  Exits the REPL.
    
  3. exit - Exits the REPL.

    Aliases: exit, q, quit

    Note

    You need to raise ExitReplException anywhere from your code to exit out of the REPL.

System Commands#

click-repl also allows shell escape to run underlying system’s shell commands by using its specified prefix in the REPL (Default: !).

> !echo hi
hi

Assigning Custom Prefixes#

You can use custom prefixes for the internal command utility by passing in those prefixes explicitly into repl() function.

 1 import click
 2 from click_repl import repl
 3
 4 @click.group(invoke_without_command=True)
 5 @click.option('-i', '--interactive', flag=True)
 6 @click.pass_context
 7 def main(ctx, interactive):
 8     if interactive:
 9         repl(
10             internal_command_prefix='-',
11             system_command_prefix='$'
12         )
13
14
15 main()
> -help
REPL help:

External/System Commands:
    Prefix External/System commands with "-".

Internal Commands:
    Prefix Internal commands with "$".
    :clear, :cls      Clears screen.
    :?, :h, :help     Displays general help information.
    :exit, :q, :quit  Exits the REPL.

> $echo hi
hi

Enabling/Disabling Internal and System Commands#

Assigning None as prefix disables the appropriate internal command utility. But you need to assign it explicitly for both internal command and system command prefixes to remove them both. Assigning None to the system command disables shell escape utilty.

Note

Make sure you have a way to exit out of the REPL to avoid getting stuck in it after doing either -

  • Disabling internal commands, or

  • Deleting the exit internal command.

If you’ve forgotten to so, then, well… good luck on getting out of the REPL. (Just close the terminal).

 1import click
 2from click_repl import repl
 3
 4@click.group(invoke_without_command=True)
 5@click.pass_context
 6def main(ctx):
 7    repl(
 8        internal_command_prefix=None,  # Disables access to internal commands.
 9        system_command_prefix=None  # Disables shell escape from the REPL.
10    )
11
12
13main()
> !echo
main: No such command '!echo'
> :help
main: No such command ':help'