Compare commits
1 Commits
main
...
feat/follow-cwd
| Author | SHA1 | Date | |
|---|---|---|---|
| fe4bcaee44 |
@@ -127,7 +127,7 @@ end
|
||||
function M.display_image_info(file_path, bufnr, reason)
|
||||
local info = {}
|
||||
|
||||
local stat = vim.loop.fs_stat(file_path)
|
||||
local stat = vim.uv.fs_stat(file_path)
|
||||
if stat then
|
||||
table.insert(info, string.format('📁 File: %s', vim.fn.fnamemodify(file_path, ':t')))
|
||||
table.insert(info, string.format('📏 Size: %d bytes', stat.size))
|
||||
|
||||
@@ -157,7 +157,7 @@ end
|
||||
--- @param file_path string Path to the file
|
||||
--- @return table File information
|
||||
function M.get_file_info(file_path)
|
||||
local stat = vim.loop.fs_stat(file_path)
|
||||
local stat = vim.uv.fs_stat(file_path)
|
||||
if not stat then return nil end
|
||||
|
||||
local info = {
|
||||
@@ -554,7 +554,7 @@ function M.preview(file_path, bufnr, file)
|
||||
M.state.current_file = file_path
|
||||
M.state.bufnr = bufnr
|
||||
|
||||
local stat = vim.loop.fs_stat(file_path)
|
||||
local stat = vim.uv.fs_stat(file_path)
|
||||
if not stat then
|
||||
M.clear_buffer_completely(bufnr)
|
||||
safe_set_buffer_lines(bufnr, 0, -1, false, {
|
||||
|
||||
@@ -15,6 +15,7 @@ M.get_keyword_range = rust_module.get_keyword_range
|
||||
M.guess_edit_range = rust_module.guess_edit_range
|
||||
M.get_words = rust_module.get_words
|
||||
M.init_file_picker = rust_module.init_file_picker
|
||||
M.restart_index_in_path = rust_module.restart_index_in_path
|
||||
M.scan_files = rust_module.scan_files
|
||||
M.get_cached_files = rust_module.get_cached_files
|
||||
M.fuzzy_search_files = rust_module.fuzzy_search_files
|
||||
|
||||
+66
-77
@@ -126,7 +126,7 @@ function M.setup_global_file_tracking()
|
||||
if file_path and file_path ~= '' and not vim.startswith(file_path, 'term://') then
|
||||
-- never block the UI
|
||||
vim.schedule(function()
|
||||
local stat = vim.loop.fs_stat(file_path)
|
||||
local stat = vim.uv.fs_stat(file_path)
|
||||
if stat and stat.type == 'file' then
|
||||
local relative_path = vim.fn.fnamemodify(file_path, ':.')
|
||||
pcall(fuzzy.access_file, relative_path)
|
||||
@@ -136,6 +136,26 @@ function M.setup_global_file_tracking()
|
||||
end,
|
||||
desc = 'Track file access for FFF frecency',
|
||||
})
|
||||
|
||||
-- make sure that this won't work correctly if autochdir plugins are enabled
|
||||
-- using a pure :cd command but will work using lua api or :e command
|
||||
vim.api.nvim_create_autocmd('DirChanged', {
|
||||
group = group,
|
||||
callback = function()
|
||||
local new_cwd = vim.v.event.cwd
|
||||
if M.is_initialized() and new_cwd and new_cwd ~= M.config.base_path then
|
||||
vim.schedule(function()
|
||||
local ok, err = pcall(M.change_indexing_directory, new_cwd)
|
||||
if not ok then
|
||||
vim.notify('FFF: Failed to change indexing directory: ' .. tostring(err), vim.log.levels.ERROR)
|
||||
else
|
||||
M.config.base_path = new_cwd
|
||||
end
|
||||
end)
|
||||
end
|
||||
end,
|
||||
desc = 'Automatically sync FFF directory changes',
|
||||
})
|
||||
end
|
||||
|
||||
function M.setup_commands()
|
||||
@@ -234,12 +254,7 @@ function M.find_in_git_root()
|
||||
return
|
||||
end
|
||||
|
||||
local picker_ok, picker_ui = pcall(require, 'fff.picker_ui')
|
||||
if picker_ok then
|
||||
picker_ui.open({ title = 'Git Files', cwd = git_root })
|
||||
else
|
||||
vim.notify('Failed to load picker UI', vim.log.levels.ERROR)
|
||||
end
|
||||
M.find_files_in_dir(git_root)
|
||||
end
|
||||
|
||||
--- Trigger rescan of files in the current directory
|
||||
@@ -331,76 +346,6 @@ function M.get_preview(file_path)
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
function M.debug_file_ordering()
|
||||
print('FFF Debug File Ordering')
|
||||
print('=======================')
|
||||
|
||||
if not M.is_initialized() then
|
||||
print('File picker not initialized. Run :FFFScan first.')
|
||||
return
|
||||
end
|
||||
|
||||
local picker = M.picker or M.core
|
||||
print('Getting top 10 files with debug info...')
|
||||
|
||||
-- Enable debug mode temporarily
|
||||
local old_debug = M.config.debug.show_scores
|
||||
M.config.debug.show_scores = true
|
||||
|
||||
-- Search with empty query to get default ordering
|
||||
local files = picker.search_files('', 10)
|
||||
|
||||
print('🏆 TOP FILES (in order they appear):')
|
||||
print('=' .. string.rep('=', 70))
|
||||
|
||||
for i, file in ipairs(files) do
|
||||
local frecency_stars = ''
|
||||
if file.frecency_score > 0 then frecency_stars = ' ⭐' .. file.frecency_score end
|
||||
|
||||
-- Extract directory information
|
||||
local dir = vim.fn.fnamemodify(file.relative_path, ':h')
|
||||
local filename = vim.fn.fnamemodify(file.relative_path, ':t')
|
||||
local dir_display = (dir == '.' or dir == '') and 'root' or dir
|
||||
|
||||
-- Get score information for this file
|
||||
local score = picker.get_file_score(i)
|
||||
|
||||
print(string.format('%2d. %s%s', i, filename, frecency_stars))
|
||||
print(string.format(' Path: %s/', dir_display))
|
||||
print(string.format(' Debug: %s', score and score.match_type or 'no debug info'))
|
||||
if score then
|
||||
print(
|
||||
string.format(
|
||||
' Total Score: %d (base=%d, name_bonus=%d, special_bonus=%d, frec=%d, dist=%d)',
|
||||
score.total,
|
||||
score.base_score,
|
||||
score.filename_bonus,
|
||||
score.special_filename_bonus,
|
||||
score.frecency_boost,
|
||||
score.distance_penalty
|
||||
)
|
||||
)
|
||||
else
|
||||
print(' Total Score: N/A (no score data)')
|
||||
end
|
||||
|
||||
local now = os.time()
|
||||
local age_hours = math.floor((now - file.modified) / 3600)
|
||||
local age_days = math.floor(age_hours / 24)
|
||||
print(string.format(' Age: %d hours (%d days) since last modified', age_hours, age_days))
|
||||
print('')
|
||||
end
|
||||
|
||||
print('💡 EXPLANATION:')
|
||||
print('• Files are sorted by FRECENCY first (⭐ score), then by modification time')
|
||||
print('• Frecency combines how often AND how recently you accessed files')
|
||||
print('• The file at #1 has either:')
|
||||
print(' - Highest frecency score, OR')
|
||||
print(' - Same frecency as others but most recent modification')
|
||||
|
||||
M.config.debug.show_scores = old_debug
|
||||
end
|
||||
|
||||
function M.health_check()
|
||||
local health = {
|
||||
ok = true,
|
||||
@@ -460,4 +405,48 @@ end
|
||||
|
||||
function M.is_initialized() return M.state and M.state.initialized or false end
|
||||
|
||||
--- Find files in a specific directory
|
||||
--- @param directory string Directory path to search in
|
||||
function M.find_files_in_dir(directory)
|
||||
if not directory then
|
||||
vim.notify('Directory path required for find_files_in_dir', vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
M.change_indexing_directory(directory)
|
||||
|
||||
local picker_ok, picker_ui = pcall(require, 'fff.picker_ui')
|
||||
if picker_ok then
|
||||
picker_ui.open({ title = 'Files in ' .. vim.fn.fnamemodify(directory, ':t') })
|
||||
else
|
||||
vim.notify('Failed to load picker UI', vim.log.levels.ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
--- Change the base directory for the file picker
|
||||
--- @param new_path string New directory path to use as base
|
||||
--- @return boolean `true` if successful, `false` otherwise
|
||||
function M.change_indexing_directory(new_path)
|
||||
if not new_path or new_path == '' then
|
||||
vim.notify('Directory path is required', vim.log.levels.ERROR)
|
||||
return false
|
||||
end
|
||||
|
||||
local expanded_path = vim.fn.expand(new_path)
|
||||
|
||||
if vim.fn.isdirectory(expanded_path) ~= 1 then
|
||||
vim.notify('Directory does not exist: ' .. expanded_path, vim.log.levels.ERROR)
|
||||
return false
|
||||
end
|
||||
|
||||
local ok, result = pcall(fuzzy.restart_index_in_path, expanded_path)
|
||||
if not ok then
|
||||
vim.notify('Failed to change directory: ' .. result, vim.log.levels.ERROR)
|
||||
return false
|
||||
end
|
||||
|
||||
M.config.base_path = expanded_path
|
||||
return true
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -930,7 +930,6 @@ function M.scroll_preview_down()
|
||||
preview.scroll(scroll_lines)
|
||||
end
|
||||
|
||||
--- Select current item
|
||||
function M.select(action)
|
||||
if not M.state.active then return end
|
||||
|
||||
@@ -960,7 +959,6 @@ function M.select(action)
|
||||
end
|
||||
end
|
||||
|
||||
--- Close picker
|
||||
function M.close()
|
||||
if not M.state.active then return end
|
||||
|
||||
|
||||
@@ -46,6 +46,37 @@ pub fn init_file_picker(_: &Lua, base_path: String) -> LuaResult<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn reinit_file_picker_internal(path: std::path::PathBuf) -> Result<(), Error> {
|
||||
let mut file_picker = FILE_PICKER.write().map_err(|_| Error::AcquireItemLock)?;
|
||||
|
||||
// drop should clean it anyway but just to be extra sure
|
||||
if let Some(picker) = file_picker.take() {
|
||||
picker.stop_background_monitor();
|
||||
}
|
||||
|
||||
let new_picker = FilePicker::new(path.to_string_lossy().to_string())?;
|
||||
*file_picker = Some(new_picker);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restart_index_in_path(_: &Lua, new_path: String) -> LuaResult<bool> {
|
||||
let path = std::path::PathBuf::from(&new_path);
|
||||
if !path.exists() {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Path does not exist: {}",
|
||||
new_path
|
||||
)));
|
||||
}
|
||||
|
||||
let canonical_path = path.canonicalize().map_err(|e| {
|
||||
LuaError::RuntimeError(format!("Failed to canonicalize path '{}': {}", new_path, e))
|
||||
})?;
|
||||
|
||||
reinit_file_picker_internal(canonical_path)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn scan_files(_: &Lua, _: ()) -> LuaResult<()> {
|
||||
let file_picker = FILE_PICKER.read().map_err(|_| Error::AcquireItemLock)?;
|
||||
let picker = file_picker
|
||||
@@ -163,6 +194,10 @@ fn create_exports(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
exports.set("init_db", lua.create_function(init_db)?)?;
|
||||
exports.set("destroy_db", lua.create_function(destroy_db)?)?;
|
||||
exports.set("init_file_picker", lua.create_function(init_file_picker)?)?;
|
||||
exports.set(
|
||||
"restart_index_in_path",
|
||||
lua.create_function(restart_index_in_path)?,
|
||||
)?;
|
||||
exports.set("scan_files", lua.create_function(scan_files)?)?;
|
||||
exports.set("get_cached_files", lua.create_function(get_cached_files)?)?;
|
||||
exports.set(
|
||||
|
||||
Reference in New Issue
Block a user