I like this very much, but I’d like to add one more feature. When I chose the file, I’d like to be in the directory where its located.
To implement this feature, we need to ensure that when you select a file from the fzf
results, ranger navigates to the directory where the file is located before opening it. This can be easily achieved by using self.fm.cd()
to change the working directory to the file’s directory before invoking the editor.
nvim ~/.config/ranger/commands.py
Here’s the updated fzf_content_open
script with this feature:
Updated fzf_content_open
class fzf_content_open(Command):
"""
:fzf_content_open
Pre-requisites: fzf, rg, bat, awk, vim or neovim.
Uses `rg` to search file content recursively in the current directory.
Filters with `fzf` and previews with `bat`.
Pressing `Enter` on a result opens it in (neo)vim at the matched line.
After selection, the directory is changed to where the file is located.
"""
def execute(self):
import os
import subprocess # Ensure subprocess is imported
from ranger.ext.get_executables import get_executables
# Check required executables
rg = 'rg' if 'rg' in get_executables() else None
fzf = 'fzf' if 'fzf' in get_executables() else None
bat = 'bat' if 'bat' in get_executables() else None
editor = 'nvim' if 'nvim' in get_executables() else 'vim' if 'vim' in get_executables() else None
if not all([rg, fzf, bat, editor]):
self.fm.notify("Missing required executables: rg, fzf, bat, and/or a suitable editor.", bad=True)
return
# Prevent recursive search from the home directory
if self.fm.thisdir.path == self.fm.home_path:
self.fm.notify("Searching from the home directory is not allowed.", bad=True)
return
# Run the combined rg + fzf + bat command
command = (
"rg --line-number --hidden . | "
"fzf --delimiter ':' "
"--preview 'bat --color=always --highlight-line {2} {1}' "
"| awk -F ':' '{print \"+\"$2\" \"$1}'"
)
process = self.fm.execute_command(command, universal_newlines=True, stdout=subprocess.PIPE)
stdout, _ = process.communicate()
# If a result is selected, process it
if process.returncode == 0:
if len(stdout) < 2:
return
selected_line = stdout.split()[0] # Line number
file_path = stdout.split()[1].strip() # File path
# Get the absolute path of the file
file_fullpath = os.path.abspath(file_path)
# Change the current directory to the directory of the selected file
file_dir = os.path.dirname(file_fullpath)
self.fm.cd(file_dir)
# Open the file in the editor at the selected line
editor_command = [editor, selected_line, file_fullpath]
self.fm.execute_command(editor_command)
Explanation of Changes:
Changing the Directory:
self.fm.cd(file_dir)
changes the working directory of ranger to the directory where the file is located.file_dir = os.path.dirname(file_fullpath)
extracts the directory path from the selected file’s full path.
Editor Command:
- The
editor_command
remains unchanged, but now the directory is correctly set to the file’s location before opening it with the editor.
- The
Keybinding in rc.conf
To bind this command to a hotkey (e.g., F5
), add the following line to your ~/.config/ranger/rc.conf
:
map F5 fzf_content_open
Usage
- Restart ranger.
- Press
F5
to invoke thefzf_content_open
command. - Type your search term in
fzf
. - Select a result and press
Enter
. - Ranger will change the directory to where the file is located and open the file at the matched line in your editor.