knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE # Set to FALSE since interactive examples can't run in vignettes )
library(climenu)
climenu provides interactive command-line menus, inspired by popular CLI tools like inquirer.js, Python's pick, and Go's survey. It offers an intuitive interface for users to make selections directly in the R console, making your scripts and packages more interactive and user-friendly.
# Install from GitHub # install.packages("remotes") remotes::install_github("PetrCala/climenu") # For optimal keyboard support, also install keypress: install.packages("keypress")
The simplest way to create a menu is with the menu() function:
# Basic single selection colors <- c("Red", "Green", "Blue", "Yellow", "Purple") choice <- menu(colors, prompt = "Choose your favorite color:") # The user navigates with arrow keys (↑/↓) or vi keys (j/k) # Press Enter to select # Returns: "Blue" (for example)
You can also use the select() function directly:
choice <- select( choices = c("Yes", "No", "Maybe"), prompt = "Do you agree?" )
For selecting multiple items, use type = "checkbox" or call checkbox() directly:
# Using menu() with checkbox type toppings <- c("Pepperoni", "Mushrooms", "Olives", "Onions", "Extra Cheese") selected <- menu( toppings, type = "checkbox", prompt = "Select pizza toppings:" ) # Or use checkbox() directly selected <- checkbox( choices = toppings, prompt = "Select pizza toppings:" ) # User navigates with arrow keys, toggles with Space, confirms with Enter # Returns: c("Pepperoni", "Extra Cheese", "Mushrooms")
You can pre-select items by value or by index:
# Pre-select by value selected <- checkbox( choices = c("Option A", "Option B", "Option C", "Option D"), selected = c("Option A", "Option C"), prompt = "Modify your selection:" ) # Options A and C will be checked initially
# Pre-select by index selected <- checkbox( choices = c("Option A", "Option B", "Option C", "Option D"), selected = c(1, 3), # First and third items prompt = "Modify your selection:" )
For single-selection menus, pre-selection sets the cursor position:
# Start with cursor on the second option choice <- select( choices = c("Small", "Medium", "Large"), selected = 2, # or "Medium" prompt = "Select size:" )
Sometimes you need the position of the selected item rather than its value:
# Single selection - returns integer index <- select( choices = c("First", "Second", "Third"), return_index = TRUE ) # Returns: 2 (if user selected "Second") # Multiple selection - returns integer vector indices <- checkbox( choices = c("Alpha", "Beta", "Gamma", "Delta"), return_index = TRUE ) # Returns: c(1, 3, 4) (if user selected Alpha, Gamma, Delta)
This is particularly useful when you need to map selections back to data structures or when the choice labels differ from the underlying values you want to work with.
When the keypress package is installed, you get instant keyboard feedback:
| Key | Action | |-----|--------| | ↑ or k | Move cursor up | | ↓ or j | Move cursor down | | Space | Toggle selection (checkbox only) | | Enter | Confirm selection | | Esc or q | Cancel (returns NULL) |
Install it for the best experience:
install.packages("keypress")
If keypress is not available, climenu falls back to readline() mode. You'll need to type commands and press Enter:
k or up - Move upj or down - Move downspace - Toggle selection (checkbox only)<number> - Jump directly to item number<Enter> - Confirm selectionq or quit - Cancelclimenu will show a one-time message suggesting to install keypress for better keyboard support.
# Ask user to configure application settings cat("\n=== Application Configuration ===\n") # Choose environment env <- select( choices = c("Development", "Staging", "Production"), prompt = "Select environment:" ) # Enable features features <- checkbox( choices = c("Logging", "Caching", "Analytics", "Debug Mode"), selected = c("Logging", "Caching"), # Sensible defaults prompt = "Enable features:" ) # Choose log level log_level <- select( choices = c("ERROR", "WARN", "INFO", "DEBUG", "TRACE"), selected = "INFO", prompt = "Select log level:" ) # Build configuration config <- list( environment = env, features = features, log_level = log_level ) cat("\nConfiguration complete!\n") print(config)
# Select datasets to process available_datasets <- c( "sales_2023.csv", "sales_2024.csv", "customers.csv", "products.csv", "inventory.csv" ) datasets <- checkbox( choices = available_datasets, prompt = "Select datasets to process:" ) if (is.null(datasets)) { cat("Processing cancelled.\n") } else { # Choose processing method method <- select( choices = c("Fast (approximate)", "Standard", "Thorough (slow)"), prompt = "Select processing method:" ) cat("\nProcessing", length(datasets), "datasets using", method, "method...\n") # ... processing logic here ... }
# Get list of files files <- list.files(pattern = "\\.csv$") if (length(files) == 0) { cat("No CSV files found.\n") } else { # Let user select files, get indices indices <- checkbox( choices = files, return_index = TRUE, prompt = "Select files to delete:" ) if (!is.null(indices) && length(indices) > 0) { files_to_delete <- files[indices] # Confirm deletion confirm <- select( choices = c("Yes, delete them", "No, cancel"), prompt = paste("Delete", length(files_to_delete), "file(s)?") ) if (confirm == "Yes, delete them") { file.remove(files_to_delete) cat("Deleted", length(files_to_delete), "file(s).\n") } } }
When a user cancels a selection (by pressing Esc or q), the menu functions return NULL:
choice <- select(c("Continue", "Skip", "Abort")) if (is.null(choice)) { cat("User cancelled the operation.\n") # Handle cancellation appropriately stop("Operation cancelled by user") } # Safe to proceed with choice cat("User selected:", choice, "\n")
Always check for NULL returns when user input is critical to your workflow.
When climenu detects it's not running in an interactive session (e.g., in Rscript, automated testing, or R CMD check), it:
select(): returns the first choice (or pre-selected item if specified)checkbox(): returns pre-selected items (or empty vector if none)This ensures your code can run in both interactive and automated contexts.
# This will work in both interactive and non-interactive modes choice <- select( choices = c("Option 1", "Option 2", "Option 3"), selected = 1 # Fallback for non-interactive ) # In non-interactive mode: issues warning and returns "Option 1" # In interactive mode: shows menu and waits for user input
If you're building an R package and want to use climenu:
Add climenu to your Imports:
Imports: climenu Suggests: keypress
#' Interactive configuration function #' @export configure_analysis <- function() { # Check if interactive if (!interactive()) { cli::cli_inform("Using default configuration (non-interactive mode)") return(get_default_config()) } # Show interactive menu method <- climenu::select( choices = c("Linear Model", "Random Forest", "Neural Network"), prompt = "Select analysis method:" ) if (is.null(method)) { cli::cli_abort("Configuration cancelled by user") } # ... rest of configuration logic ... return(config) }
Keep choices concise - Long choice text may not display well in narrow terminals
Provide clear prompts - Tell users what they're selecting and what will happen
Use pre-selection wisely - Pre-select sensible defaults to improve UX
Handle cancellation - Always check for NULL returns
Test non-interactive behavior - Ensure your code works in automated contexts
Recommend keypress - Consider mentioning in your package README that users should install keypress for the best experience
Consider sort order - Present choices in a logical order (alphabetical, by frequency, by importance)
menu(choices, prompt, type, selected, return_index)Main entry point for creating menus.
Arguments:
choices: Character vector of options to displayprompt: Message to display (default: "Select an item:")type: "select" for single selection, "checkbox" for multiple (default: "select")selected: Pre-selected items as indices or values (optional)return_index: Logical; return indices instead of values (default: FALSE)Returns: Selected value(s) as character vector, or indices as integer vector, or NULL if cancelled
select(choices, prompt, selected, return_index)Single selection menu. Parameters same as menu() but without type.
checkbox(choices, prompt, selected, return_index)Multiple selection menu. Parameters same as menu() but without type.
Install the keypress package for proper arrow key support:
install.packages("keypress")
interactive() returns FALSE)climenu makes it easy to add interactive menus to your R scripts and packages. Whether you're building a data analysis wizard, configuration tool, or just need better user input, climenu provides an intuitive and robust solution.
Happy menu-making!
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.