---
title: "Introduction to contextFind"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to contextFind}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)
```

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

-   **Context-aware results**: See surrounding lines of code for each match
-   **Clickable navigation**: Jump directly to the exact line in your source files
-   **Smart ordering**: Results sorted by modification time, so recent changes appear last (easier to read in console)
-   **Highlighted matches**: Visual emphasis on the search term within results
-   **RStudio integration**: Fast access via keyboard shortcuts

## Installation

Install from CRAN:

```{r}
install.packages("contextFind")
```

Or get the development version from GitHub:

```{r}
devtools::install_github("s87jackson/contextFind")
```

## Basic Usage

### The contextFind() Function

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

```{r}
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:

```{r}
# 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:

```{r}
# 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:

```{r}
# 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

```{r}
# Find all function definitions
contextFind("<- function")

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

### Tracking Variable Usage

```{r}
# Find where a variable is used
contextFind("user_data")

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

### Locating UI Components

```{r}
# Find specific input widgets
contextFind("selectInput")

# Find output renderers
contextFind("renderPlot")
```

### Code Review and TODOs

```{r}
# Find all TODO comments
contextFind("TODO")

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

# Find deprecated functions
contextFind(".Deprecated")
```

### Library and Package Usage

```{r}
# Find all uses of a package
contextFind("dplyr::")

# Find library calls
contextFind("library(")

# Find specific ggplot geoms
contextFind("geom_point")
```

### Debugging

```{r}
# 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:

```{r}
# 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:

```{r}
# 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:

```{r}
# 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.

### 3. Navigate Large Projects

For large Shiny apps or packages:

```{r}
# Find all observers
contextFind("observe(")

# Find all event handlers
contextFind("observeEvent")

# Find module calls
contextFind("Module(")
```

### 4. Batch Searches

Use the function in scripts or reports:

```{r}
# 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:

```{r}
# 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:

```{r}
# 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

-   **Advantages of contextFind**:
    -   Shows context without opening files
    -   Clickable links in console output
    -   Programmatic access to results
    -   Quick keyboard shortcut access
    -   Sorted by modification time
-   **When to use RStudio's Find in Files**:
    -   Need regex patterns
    -   Want to replace text
    -   Need to search non-R files

### vs. grep/ripgrep

-   **Advantages of contextFind**:
    -   R-native interface
    -   Automatically finds R and Rmd files
    -   Formatted output with clickable links
    -   Integrated with RStudio
-   **When to use grep/ripgrep**:
    -   Need advanced regex
    -   Search across all file types
    -   Working in terminal

## Advanced Examples

### Find All Exported Functions in a Package

```{r}
# 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

```{r}
# Find potential hardcoded file paths
contextFind("C:/")
contextFind("/Users/")

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

### Analyze Shiny App Structure

```{r}
# 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

### Clickable Links Not Working

Clickable links require:

-   A terminal/console that supports ANSI escape sequences
-   RStudio (recommended)
-   Some external terminals may not support `file://` links

## Contributing

Found a bug or have a feature request? Please visit the [GitHub repository](https://github.com/s87jackson/contextFind) to open an issue or submit a pull request.
