Introduction to contextFind

Overview

contextFind is a convenient code search tool designed for R developers who work with multi-file projects such as Shiny applications, R packages, or complex analysis workflows. Unlike basic text search, contextFind provides:

Installation

Install from CRAN:

install.packages("contextFind")

Or get the development version from GitHub:

devtools::install_github("s87jackson/contextFind")

Basic Usage

The contextFind() Function

The core function contextFind() searches for text across your R and Rmd files:

library(contextFind)

# Search for all function definitions in your project
contextFind("<- function")

This will output results like:

Found 15 matches for "<- function"

==============================
Match 15 of 15
server.R (line 42)
Last Modified: 2024-10-15 14:32:10
------------------------------
   Line 40:
   Line 41: # Define server logic
   Line 42: server <- function(input, output, session) {
   Line 43:
   Line 44:   # Reactive values

Each match shows: - File name and line number (clickable in supported terminals) - Last modification time of the file - Context lines around the match (default: 2 before and 2 after) - The matching line highlighted

Key Parameters

contextLines

Control how much surrounding code to display:

# No context - just the matching line
contextFind("renderPlot", contextLines = 0)

# More context for complex functions
contextFind("reactive", contextLines = 5)

path

Limit your search to specific directories:

# Search only in the R/ directory
contextFind("validate", path = "R")

# Search in a subdirectory
contextFind("test", path = "tests/testthat")

recursive

Control whether to search subdirectories:

# Search only the current directory (no subdirectories)
contextFind("TODO", recursive = FALSE)

# Search all subdirectories (default)
contextFind("TODO", recursive = TRUE)

Using the RStudio Addin

The contextFind package includes an RStudio addin that provides an interactive interface for searching your code.

Setup

  1. Install and restart RStudio after installing contextFind

  2. Assign a keyboard shortcut:

    • Go to Tools > Modify Keyboard Shortcuts
    • Search for “contextFind”
    • Assign a shortcut (recommended: Ctrl+Shift+F or Cmd+Shift+F on Mac)

Using the Addin

  1. Highlight text in your script (optional but convenient)
  2. Press your keyboard shortcut to open the contextFind dialog
  3. Configure your search:
    • Search string (pre-filled if you highlighted text)
    • Directory (click “Choose directory” to change)
    • Recursive search checkbox
    • Number of context lines
  4. Click “contextFind” to see results in the console

The addin will pre-fill the search box with any highlighted text, making it fast to search for variables or function names you’re currently working with.

Common Use Cases

Finding Function Definitions

# Find all function definitions
contextFind("<- function")

# Find a specific function
contextFind("calculate_metrics <- function")

Tracking Variable Usage

# Find where a variable is used
contextFind("user_data")

# Find reactive values in Shiny apps
contextFind("reactiveVal")

Locating UI Components

# Find specific input widgets
contextFind("selectInput")

# Find output renderers
contextFind("renderPlot")

Code Review and TODOs

# Find all TODO comments
contextFind("TODO")

# Find FIXME or bug markers
contextFind("FIXME")

# Find deprecated functions
contextFind(".Deprecated")

Library and Package Usage

# Find all uses of a package
contextFind("dplyr::")

# Find library calls
contextFind("library(")

# Find specific ggplot geoms
contextFind("geom_point")

Debugging

# Find browser() calls you may have left in code
contextFind("browser()")

# Find print statements
contextFind("print(")

# Find error handling
contextFind("tryCatch")

Working with Results Programmatically

contextFind() invisibly returns a list of results that you can work with:

# Store results
results <- contextFind("ggplot")

# Access the first match
results[[1]]$file         # Full file path
results[[1]]$match_line   # Line number where match was found
results[[1]]$mtime        # File modification time
results[[1]]$context      # Named character vector of context lines

# Get all matching files
unique(sapply(results, function(x) x$file))

# Count matches per file
table(sapply(results, function(x) basename(x$file)))

# Find most recently modified files with matches
recent <- results[[length(results)]]
cat("Most recent match in:", basename(recent$file),
    "at line", recent$match_line, "\n")

Tips and Tricks

1. Search for Partial Patterns

Since contextFind uses literal string matching (not regex), you can search for partial code patterns:

# Find all assignments to variables starting with "df_"
contextFind("df_")

# Find function calls (including arguments)
contextFind("function(")

2. Combine with Version Control

Search for recent changes in modified files:

# After modifying files, find where you used a new function
contextFind("new_function")

The results are sorted by modification time, so your recent changes appear last - right where you’re reading in the console.

4. Batch Searches

Use the function in scripts or reports:

# Find all functions that need documentation
results <- contextFind("<- function", contextLines = 0)

# Check if they have roxygen comments
documented <- sapply(results, function(r) {
  lines <- readLines(r$file)
  line_before <- lines[max(1, r$match_line - 1)]
  grepl("#'", line_before)
})

cat(sprintf("%d of %d functions have documentation\n",
            sum(documented), length(documented)))

5. Case-Sensitive Searching

Remember that contextFind is case-sensitive:

# These are different searches:
contextFind("data")       # lowercase
contextFind("Data")       # uppercase

6. Work with File Patterns

While contextFind searches both .R and .Rmd files automatically, you can narrow results by path:

# Search only source files
contextFind("function", path = "R/")

# Search only test files
contextFind("expect_", path = "tests/testthat/")

# Search only vignettes
contextFind("knitr", path = "vignettes/")

Comparison with Other Tools

vs. RStudio’s Find in Files

vs. grep/ripgrep

Advanced Examples

Find All Exported Functions in a Package

# Search for roxygen @export tags
results <- contextFind("@export", path = "R/")

# Find what functions are exported
exported_functions <- sapply(results, function(r) {
  lines <- readLines(r$file)
  # Look ahead for function definition
  func_line <- lines[r$match_line + 1]
  if (grepl("<- function", func_line)) {
    trimws(gsub("<-.*", "", func_line))
  } else {
    NA
  }
})

cat("Exported functions:\n")
print(na.omit(exported_functions))

Check for Hardcoded Values

# Find potential hardcoded file paths
contextFind("C:/")
contextFind("/Users/")

# Find hardcoded credentials (be careful!)
contextFind("password")
contextFind("api_key")

Analyze Shiny App Structure

# Count UI elements
ui_results <- contextFind("Input(", path = ".")
cat("Number of input widgets:", length(ui_results), "\n")

# Count outputs
output_results <- contextFind("render", path = ".")
cat("Number of render functions:", length(output_results), "\n")

# Find reactive chains
contextFind("reactive(")
contextFind("observe(")

Troubleshooting

No Results Found

If contextFind returns no results:

  1. Check your search term for typos
  2. Verify the path parameter points to the correct directory
  3. Ensure recursive = TRUE if searching subdirectories
  4. Remember that searches are case-sensitive

Too Many Results

To narrow down results:

  1. Use more specific search terms
  2. Limit the search path: path = "R/"
  3. Use recursive = FALSE for current directory only
  4. Reduce contextLines to see less context

Contributing

Found a bug or have a feature request? Please visit the GitHub repository to open an issue or submit a pull request.