Getting Started with climenu

library(climenu)

Introduction

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.

Key Features

Installation

# Install from GitHub
# install.packages("remotes")
remotes::install_github("PetrCala/climenu")

# For optimal keyboard support, also install keypress:
install.packages("keypress")

Basic Usage

Single Selection Menu

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?"
)

Multiple Selection Menu

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")

Advanced Features

Pre-selection

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:"
)

Returning Indices Instead of Values

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.

Keyboard Controls

Without keypress (Fallback Mode)

If keypress is not available, climenu falls back to readline() mode. You’ll need to type commands and press Enter:

climenu will show a one-time message suggesting to install keypress for better keyboard support.

Practical Examples

Configuration Wizard

# 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)

Data Processing Pipeline

# 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 ...
}

File Selection with Indices

# 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")
    }
  }
}

Handling User Cancellation

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.

Non-Interactive Environments

When climenu detects it’s not running in an interactive session (e.g., in Rscript, automated testing, or R CMD check), it:

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

Integration with Packages

If you’re building an R package and want to use climenu:

DESCRIPTION File

Add climenu to your Imports:

Imports:
    climenu
Suggests:
    keypress

Using in Package Functions

#' 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)
}

Tips and Best Practices

  1. Keep choices concise - Long choice text may not display well in narrow terminals

  2. Provide clear prompts - Tell users what they’re selecting and what will happen

  3. Use pre-selection wisely - Pre-select sensible defaults to improve UX

  4. Handle cancellation - Always check for NULL returns

  5. Test non-interactive behavior - Ensure your code works in automated contexts

  6. Recommend keypress - Consider mentioning in your package README that users should install keypress for the best experience

  7. Consider sort order - Present choices in a logical order (alphabetical, by frequency, by importance)

API Reference

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.

Troubleshooting

Arrow keys not working

Install the keypress package for proper arrow key support:

install.packages("keypress")

Returns NULL unexpectedly

Further Reading

Conclusion

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!

mirror server hosted at Truenetwork, Russian Federation.