Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"cSpell.words": [
"canbus",
"canivore",
"coppercore",
"ctre",
"dists",
Expand Down
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ jinja2 = "*"
robotvibecoder = {file = ".", editable = true}
mypy = "*"
pylint = "*"
pick = "*"
prompt-toolkit = "*"

[dev-packages]

Expand Down
49 changes: 48 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dependencies = ["jinja2==3.1.6"]
dependencies = ["jinja2==3.1.6", "pick==2.4.0", "prompt_toolkit==3.0.51"]

[project.urls]
Documentation = "https://github.com/team401/robotvibecoder#readme"
Expand Down
32 changes: 29 additions & 3 deletions src/robotvibecoder/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from dataclasses import dataclass
import sys
from typing import TextIO
from typing import TextIO, List
import pick


@dataclass
Expand All @@ -28,7 +29,7 @@ def print_err(message: str, file: TextIO = sys.stderr):
:param message: The error message.
:type message: str
:param file: File to print the error message to, defaults to sys.stderr
:type file: _type_, optional
:type file: TextIO, optional
"""
print(f"{Colors.fg_red}{Colors.bold}Error{Colors.reset}: {message}", file=file)

Expand All @@ -39,6 +40,31 @@ def print_warning(message: str, file: TextIO = sys.stderr):
:param message: The warning message.
:type message: str
:param file: File to print the warning message to, defaults to sys.stderr
:type file: _type_, optional
:type file: TextIO, optional
"""
print(f"{Colors.fg_red}{Colors.bold}Warning{Colors.reset}: {message}", file=file)


def rvc_pick(options: List[str], title: str, spoof_input: bool = True) -> str:
"""Make the user select an option from options using arrow keys/enter

This is a custom wrapper around the pick library.

:param options: The options to select from
:type options: list[str]
:param title: The title message to print above the picker
:type title: str
:param spoof_input: Print a prompt with the selected option? Defaults to true.
:type spoof_input: bool, optional
"""

selection, _ = pick.pick(options, title)
assert isinstance(
selection, str
), """Pick selection wasn't a string. This is a robotvibecoder issue!
Please report this on github: https://github.com/team401/robotvibecoder"""

if spoof_input:
print(f"{title}\n> {selection}")

return selection
61 changes: 40 additions & 21 deletions src/robotvibecoder/subcommands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,32 @@
import json
import os
import sys
from prompt_toolkit import prompt
from prompt_toolkit.completion import Completer, Completion

from robotvibecoder import constants
import robotvibecoder.cli
from robotvibecoder.config import MechanismConfig, MechanismKind


class AppendCompleter(Completer):
"""
An auto-completer that adds a string to the end of the input text.
"""

def __init__(self, text: str):
"""
Create an AppendCompleter

:param text: The text to suggest completing
:type text: str
"""
self.text = text

def get_completions(self, document, complete_event):
yield Completion(self.text, start_position=0)


def new_config_interactive() -> MechanismConfig:
"""
Prompt the user for each field of a config to generate one interactively
Expand All @@ -21,25 +41,22 @@ def new_config_interactive() -> MechanismConfig:
"Interactively generating new config. Please enter each field and press [Enter]."
)
print("Package: will come after frc.robot (e.g. `subsystems.scoring`)")
package: str = input("> ")
package: str = prompt("> ", default="subsystems.")
print(
"Name: should be capitalized and should not end in Mechanism or Subsystem, as this is automatically added" # pylint: disable=line-too-long
)
name: str = input("> ")

print("Kind: Should be either 'Elevator', 'Arm', or 'Flywheel'")
kind: str = ""
while MechanismKind.try_into(kind) is None:
kind = input("> ")
if MechanismKind.try_into(kind) is None:
print("Please input either Elevator, Arm, or Flywheel.")
name: str = prompt("> ")

kind_choices = ["Elevator", "Arm", "Flywheel"]
kind: str = robotvibecoder.cli.rvc_pick(kind_choices, "Mechanism Kind:")

kind_try = MechanismKind.try_into(kind)
kind_enum: MechanismKind = (
kind_try if kind_try is not None else MechanismKind.ELEVATOR
)

print("CAN Bus: whatever the name of the mechanism's bus is (e.g. `canivore`)")
canbus: str = input("> ")
canbus: str = prompt("> ", default="canivore")

num_motors: int = -1
while num_motors == -1:
Expand All @@ -54,20 +71,22 @@ def new_config_interactive() -> MechanismConfig:
motors: list[str] = []
for i in range(num_motors):
motors.append(
input(f"Motor {i + 1} name: a camelcase motor name (e.g. leadMotor)\n> ")
prompt(
f"Motor {i + 1} name: a camelcase motor name (e.g. leadMotor)\n> ",
completer=AppendCompleter("Motor"),
complete_while_typing=True,
)
)

lead_motor: str = ""

while lead_motor not in motors:
lead_motor = input("Lead motor (must be one of previously defined motors)\n> ")

if lead_motor not in motors:
print("Please select one of the previously defined motors:")
for motor in motors:
print(f" - {motor}")
lead_motor: str = robotvibecoder.cli.rvc_pick(
motors, "Lead Motor: (Up/Down/K/J to move, Enter to select)"
)

encoder: str = input("Encoder name: a camelcase encoder name (e.g. armEncoder)\n> ")
encoder: str = prompt(
"Encoder name: a camelcase encoder name (e.g. armEncoder)\n> ",
completer=AppendCompleter("Encoder"),
complete_while_typing=True,
)

return MechanismConfig(
package, name, kind_enum, canbus, motors, lead_motor, encoder
Expand Down