Tab Completion

The library provides generic tab completion functionality. This can either be automatic (for example, parameters of type bool) or provided by the business logic of the application. Consider the sample program below:

import recline
from recline.arg_types.choices import Choices
from recline.formatters.table_formatter import TableFormat

# A stand-in for a database or some other form of persistence
ORDERS = {}
MENU = ['black bean', 'choirizo', 'steak']

def get_customers():
    return list(ORDERS.keys())

def get_order_types():
    return [o["type"] for o in ORDERS.values()]

@recline.command(name="order burrito")
def order_burrito(
    customer_name: str,
    type: Choices.define(available_choices=MENU),
    grilled: bool = True,
) -> None:
    """Place an order for a delicious burrito

    Arguments:
        cusomter_name: The name of the customer who is ordering
        type: Describes the fillings of the burrito
        grilled: If the burrito should be browned on the grill
    """

    ORDERS[customer_name] = {"type": type, "grilled": grilled}
    print("One order for a %s burrito, coming up!" % type)

@recline.command(name="show orders")
def show_orders(
    customer_name: Choices.define(available_choices=get_customers) = None,
    type: Choices.define(available_choices=get_order_types) = None,
    grilled: bool = None,
) -> TableFormat:
    """List all of the orders that match the given query

    Arguments:
        cusomter_name: The name of the customer who made the order
        type: The type of burrito that was ordered
        grilled: List only burritos with this grilling status

    Returns:
        A list of all orders matching the query
    """

    matching_orders = []
    for customer, order in ORDERS.items():
        if customer_name and customer != customer_name:
            continue
        if type and type != order["type"]:
            continue
        if grilled is not None and grilled != order["grilled"]:
            continue
        matching_orders.append({"customer": customer, "type": order["type"], "grilled": order["grilled"]})

    return matching_orders

recline.relax(prompt="tacos galore> ")

Note

In the examples below, I will put the string [Tab] in the output to show where the [Tab] key was typed. The characters are not literally displayed when running the program.

Command Completion

The first level of tab completion is command completion. This means that the user can press the [Tab] key in order to show the list of commands the matches the current input on the command line. For example, if there was nothing typed yet, the program above would display this:

tacos galore> [Tab]
?              debug          exit
fg             help           man
order burrito  q              quit
show orders
tacos galore>

Here, all of the available commands, including the builtin commands are shown. If the user started typing the command they wanted to execute and then hit [Tab], it might look like this:

tacos galore> ord[Tab]
tacos galore> order burrito

Hard to show here, but there would not be two lines on the display. The library knows that the only command that matches the prefix ord is order burrito and completes the rest of the words.

Argument Completion

Continuing from the last section, if the user presses [Tab] immediately, they will be shown a list of available arguments:

tacos galore> order burrito [Tab]
-customer_name  -grilled        -type
tacos galore> order burrito -

Here, we can see that the list is shown starting on the next line and then the library reprinted what was already typed and started filling in the common prefix that all of the arguments have in common (in this case, just a -). If there had been more of a common prefix, it would have included that as well.

Knowing that they want to fill in the type field, the user types a t and presses [Tab] again:

tacos galore> order burrito -t[Tab]
tacos galore> order burrito -type

Again, this would not appear on two lines on the display.

Value Completion

Continuing from the last section, the user wants to complete an order so they press [Tab] once more to determine which types are available:

tacos galore> order burrito -type [Tab]
black\ bean  choirizo     steak
tacos galore> order burrito -type ch[Tab]
tacos galore> order burrito -type chorizo -cust[Tab]
tacos galore> order burrito -type chorizo -customer_name Suzane
One order for a choirizo burrito, coming up!
tacos galore>

After finishing our order, we can see the current orders by again pressing [Tab] as we navigate the show command:

tacos galore> sh[Tab]
tacos galore> show orders [Tab]
-customer_name  -grilled        -type
tacos galore> show orders -cu[Tab]
tacos galore> show orders -customer_name [Tab]
tacos galore> show orders -customer_name Suzane
+----------+----------+---------+
| Customer | Type     | Grilled |
+----------+----------+---------+
| Suzane   | choirizo | True    |
+----------+----------+---------+
tacos galore>

Since we pressed [Tab] to find the possible choices for customer name and there was only one, the library filled it in for us. If there was more than one value available, it would have showed us choices like this:

tacos galore> order burrito -type choirizo -customer_name Sue
One order for a choirizo burrito, coming up!
tacos galore> show orders -customer_name [Tab]
Sue     Suzane
tacos galore> show orders -customer_name Su

We can see that this time, since they share a prefix, the library filled in the common parts of the name and waits for the user to give more uniqueness.