Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion PSFzf.Functions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ function Invoke-PsFzfRipgrep() {
# this function is adapted from https://github.com/junegunn/fzf/blob/master/ADVANCED.md#switching-between-ripgrep-mode-and-fzf-mode
param([Parameter(Mandatory)]$SearchString, [switch]$NoEditor)

$RG_PREFIX = "rg --column --line-number --no-heading --color=always --smart-case "
$DEFAULT_RG_PREFIX = "rg --column --line-number --no-heading --color=always --smart-case "
$RG_PREFIX = if ($env:PSFZF_RG_PREFIX) { $env:PSFZF_RG_PREFIX } else { $DEFAULT_RG_PREFIX }
$INITIAL_QUERY = $SearchString

$script:OverrideFzfDefaultCommand = [FzfDefaultCmd]::new('')
Expand Down
126 changes: 126 additions & 0 deletions PSFzf.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,132 @@ Describe "Find-CurrentPath" {
}
}

Describe 'Invoke-PsFzfRipgrep' {
InModuleScope PsFzf {
$OriginalPSFZF_RG_PREFIX = $null
$script:CapturedCommand = $null
$script:MockedFzfDefaultCmd = $null

BeforeEach {
# Store and clear environment variable
$OriginalPSFZF_RG_PREFIX = $env:PSFZF_RG_PREFIX
$env:PSFZF_RG_PREFIX = $null

# Reset captured command
$script:CapturedCommand = $null

# Mock Invoke-Expression to capture the command
Mock Invoke-Expression {
param($Command)
$script:CapturedCommand = $Command
# Simulate fzf returning no selection to allow the function to complete
return $null
} -ModuleName PsFzf

# Mock Get-EditorLaunch to prevent actual editor launch
Mock Get-EditorLaunch {
param($FileList, $LineNum = 0)
# Do nothing, just prevent original function call
return "MockedEditorLaunch $FileList $LineNum"
} -ModuleName PsFzf

# Mock Resolve-Path for -NoEditor switch
Mock Resolve-Path {
param($Path)
return "Resolved_$Path" # Simulate path resolution
} -ModuleName PsFzf

# Mock FzfDefaultCmd - new and Restore.
$script:MockedFzfDefaultCmd = @{ Restored = $false }
Mock ([FzfDefaultCmd]::new) {
param([string]$Cmd)
return @{
OriginalCommand = $Cmd
Restore = {
$script:MockedFzfDefaultCmd.Restored = $true
# Write-Warning "MockedFzfDefaultCmd Restore() called." # Uncomment for debugging
}
ToString = { "MockedFzfDefaultCmdInstance" }
}
} -ModuleName PsFzf
}

AfterEach {
# Restore environment variable
$env:PSFZF_RG_PREFIX = $OriginalPSFZF_RG_PREFIX

# Mocks are generally cleaned up by Pester between Describe blocks or by re-mocking.
# If explicit removal is needed, uncomment these:
# Remove-Mock -CommandName 'Invoke-Expression' -ModuleName PsFzf -ErrorAction SilentlyContinue
# Remove-Mock -CommandName 'Get-EditorLaunch' -ModuleName PsFzf -ErrorAction SilentlyContinue
# Remove-Mock -CommandName 'Resolve-Path' -ModuleName PsFzf -ErrorAction SilentlyContinue
# Remove-Mock -CommandName '([FzfDefaultCmd]::new)' -ModuleName PsFzf -ErrorAction SilentlyContinue # Note: Mocking type constructors might need specific syntax for removal if supported
}

Context 'Default rg command' {
It 'Should use the default rg prefix when PSFZF_RG_PREFIX is not set' {
Invoke-PsFzfRipgrep -SearchString 'testsearch' | Out-Null

$defaultRgPrefix = "rg --column --line-number --no-heading --color=always --smart-case "
# Check that the default rg prefix is part of the command passed to Invoke-Expression (indirectly, via $env:FZF_DEFAULT_COMMAND)
# This specifically checks the 'reload' part of the fzf --bind arguments
$script:CapturedCommand | Should -Match ([regex]::Escape($defaultRgPrefix))
$script:MockedFzfDefaultCmd.Restored | Should -BeTrue ("FzfDefaultCmd.Restore() was not called.")
}
}

Context 'Custom rg command via PSFZF_RG_PREFIX' {
It 'Should use the custom rg prefix when PSFZF_RG_PREFIX is set' {
$customRgPrefix = 'my-custom-rg --awesome '
$env:PSFZF_RG_PREFIX = $customRgPrefix

Invoke-PsFzfRipgrep -SearchString 'testsearch' | Out-Null

$script:CapturedCommand | Should -Match ([regex]::Escape($customRgPrefix))
$script:CapturedCommand | Should -Not -Match ([regex]::Escape("rg --column --line-number"))
$script:MockedFzfDefaultCmd.Restored | Should -BeTrue ("FzfDefaultCmd.Restore() was not called.")
}
}

Context 'NoEditor switch' {
It 'Should call Resolve-Path and not Get-EditorLaunch when -NoEditor is used and fzf returns a value' {
# Override Invoke-Expression mock for this specific test to return a value
Mock Invoke-Expression {
param($Command)
$script:CapturedCommand = $Command
return "somefile.txt:123:content" # Simulate fzf selection
} -ModuleName PsFzf

$result = Invoke-PsFzfRipgrep -SearchString 'testsearch' -NoEditor

$result | Should -Be "Resolved_somefile.txt"
Should -Invoke 'Resolve-Path' -Times 1 -ModuleName PsFzf -ParameterFilter { $Path -eq 'somefile.txt' }
Should -Not -Invoke 'Get-EditorLaunch' -ModuleName PsFzf
$script:MockedFzfDefaultCmd.Restored | Should -BeTrue ("FzfDefaultCmd.Restore() was not called.")
}
}

Context 'Editor launch' {
It 'Should call Get-EditorLaunch when -NoEditor is not used and fzf returns a value' {
# Override Invoke-Expression mock for this specific test to return a value
Mock Invoke-Expression {
param($Command)
$script:CapturedCommand = $Command
return "anotherfile.txt:45:foobar" # Simulate fzf selection
} -ModuleName PsFzf

Invoke-PsFzfRipgrep -SearchString 'testsearch' | Out-Null

Should -Invoke 'Get-EditorLaunch' -Times 1 -ModuleName PsFzf -ParameterFilter {
$FileList -eq 'anotherfile.txt' -and $LineNum -eq '45'
}
Should -Not -Invoke 'Resolve-Path' -ModuleName PsFzf
$script:MockedFzfDefaultCmd.Restored | Should -BeTrue ("FzfDefaultCmd.Restore() was not called.")
}
}
}
}

Describe 'Invoke-FuzzySetLocation' {
InModuleScope PsFzf {

Expand Down
12 changes: 12 additions & 0 deletions docs/Invoke-PsFzfRipgrep.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,17 @@ This cmdlet does not generate any output.
## NOTES
This function is adapted from [Fzf's advanced document](https://github.com/junegunn/fzf/blob/master/ADVANCED.md#switching-between-ripgrep-mode-and-fzf-mode).
This function requires the installation of [ripgrep](https://github.com/BurntSushi/ripgrep) and [bat](https://github.com/sharkdp/bat).

## CUSTOMIZATION
### `PSFZF_RG_PREFIX`
You can customize the `rg` command used by `Invoke-PsFzfRipgrep` by setting the `PSFZF_RG_PREFIX` environment variable. This allows you to add default arguments to `rg`, such as enabling hidden file search or excluding specific directories.

For example, to make `rg` search hidden files and exclude the `node_modules` directory, you can set the environment variable as follows:

```powershell
$env:PSFZF_RG_PREFIX = "rg --hidden --glob '!node_modules'"
```
The default `rg` command is `"rg --column --line-number --no-heading --color=always --smart-case "`.

## RELATED LINKS

Loading