knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE )
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:
Install from CRAN:
install.packages("contextFind")
Or get the development version from GitHub:
devtools::install_github("s87jackson/contextFind")
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
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)
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")
Control whether to search subdirectories:
# Search only the current directory (no subdirectories) contextFind("TODO", recursive = FALSE) # Search all subdirectories (default) contextFind("TODO", recursive = TRUE)
The contextFind package includes an RStudio addin that provides an interactive interface for searching your code.
Install and restart RStudio after installing contextFind
Assign a keyboard shortcut:
Ctrl+Shift+F or Cmd+Shift+F on Mac)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.
# Find all function definitions contextFind("<- function") # Find a specific function contextFind("calculate_metrics <- function")
# Find where a variable is used contextFind("user_data") # Find reactive values in Shiny apps contextFind("reactiveVal")
# Find specific input widgets contextFind("selectInput") # Find output renderers contextFind("renderPlot")
# Find all TODO comments contextFind("TODO") # Find FIXME or bug markers contextFind("FIXME") # Find deprecated functions contextFind(".Deprecated")
# Find all uses of a package contextFind("dplyr::") # Find library calls contextFind("library(") # Find specific ggplot geoms contextFind("geom_point")
# Find browser() calls you may have left in code contextFind("browser()") # Find print statements contextFind("print(") # Find error handling contextFind("tryCatch")
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")
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(")
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.
For large Shiny apps or packages:
# Find all observers contextFind("observe(") # Find all event handlers contextFind("observeEvent") # Find module calls contextFind("Module(")
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)))
Remember that contextFind is case-sensitive:
# These are different searches: contextFind("data") # lowercase contextFind("Data") # uppercase
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/")
# 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))
# Find potential hardcoded file paths contextFind("C:/") contextFind("/Users/") # Find hardcoded credentials (be careful!) contextFind("password") contextFind("api_key")
# 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(")
If contextFind returns no results:
path parameter points to the correct directoryrecursive = TRUE if searching subdirectoriesTo narrow down results:
path = "R/"recursive = FALSE for current directory onlycontextLines to see less contextClickable links require:
file:// linksFound a bug or have a feature request? Please visit the GitHub repository to open an issue or submit a pull request.
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.