mirror of
https://github.com/zoriya/telescope.nvim.git
synced 2026-08-16 02:45:09 +00:00
feat: Support Line Column in file pickers
Original issue: When selecting files in telescope iti is impossible to enter paths from compiler that includes cursor locations, you need to clear it from the path. This commit fixes the problem by stripping out the location from path (important: only for file pickes) and using this location to set the cursor when openning the file and highlight the line or poisition in the previewer. This feature requires a new option for a picker, whichi for now is basically enabling location stripping but it is helpful for any file picker builtin or external one. By default equals `false` becuase most of pickers like live grep, current buffer fuzy are messed up with locations stripping. It is only useful for file searches. Added test suite that covers alghoritm of stripping the location to the `utils_spec.lua`
This commit is contained in:
@@ -384,6 +384,7 @@ files.find_files = function(opts)
|
||||
pickers
|
||||
.new(opts, {
|
||||
prompt_title = "Find Files",
|
||||
files_picker = true,
|
||||
finder = finders.new_oneshot_job(find_command, opts),
|
||||
previewer = conf.file_previewer(opts),
|
||||
sorter = conf.file_sorter(opts),
|
||||
|
||||
@@ -46,6 +46,7 @@ git.files = function(opts)
|
||||
pickers
|
||||
.new(opts, {
|
||||
prompt_title = "Git Files",
|
||||
files_picker = true,
|
||||
finder = finders.new_oneshot_job(
|
||||
vim.tbl_flatten {
|
||||
opts.git_command,
|
||||
|
||||
@@ -319,6 +319,8 @@ function Picker:new(opts)
|
||||
cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)),
|
||||
|
||||
__scrolling_limit = tonumber(vim.F.if_nil(opts.temp__scrolling_limit, 250)),
|
||||
|
||||
allow_location_input = opts.files_picker or false,
|
||||
}, self)
|
||||
|
||||
obj.create_layout = opts.create_layout or config.values.create_layout or default_create_layout
|
||||
@@ -626,6 +628,24 @@ function Picker:find()
|
||||
local start_time = vim.loop.hrtime()
|
||||
|
||||
local prompt = self:_get_next_filtered_prompt()
|
||||
if self.allow_location_input == true then
|
||||
local filename, line_number, column_number = utils.separate_file_path_location(prompt)
|
||||
|
||||
if line_number or column_number then
|
||||
state.set_global_key("prompt_location", { row = line_number, col = column_number })
|
||||
self:refresh_previewer()
|
||||
elseif state.get_global_key "prompt_location" then
|
||||
state.set_global_key("prompt_location", nil)
|
||||
self:refresh_previewer()
|
||||
end
|
||||
|
||||
-- it is important to continue behaving as if there is no location in prompt
|
||||
prompt = filename
|
||||
elseif state.get_global_key "prompt_location" then
|
||||
-- in case new picker that does not support locations is opened clear the location
|
||||
-- without refreshing previewer
|
||||
state.set_global_key("prompt_location", nil)
|
||||
end
|
||||
|
||||
-- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display
|
||||
if self.cache_picker == false or self.cache_picker.is_cached ~= true then
|
||||
@@ -1046,6 +1066,13 @@ function Picker:set_selection(row)
|
||||
end
|
||||
|
||||
local entry = self.manager:get_entry(self:get_index(row))
|
||||
|
||||
local prompt_location = state.get_global_key "prompt_location"
|
||||
if entry and prompt_location then
|
||||
entry.lnum = prompt_location.row or 0
|
||||
entry.col = prompt_location.col or 0
|
||||
end
|
||||
|
||||
state.set_global_key("selected_entry", entry)
|
||||
|
||||
if not entry then
|
||||
|
||||
@@ -4,6 +4,7 @@ local utils = require "telescope.utils"
|
||||
local putils = require "telescope.previewers.utils"
|
||||
local Previewer = require "telescope.previewers.previewer"
|
||||
local conf = require("telescope.config").values
|
||||
local global_state = require "telescope.state"
|
||||
|
||||
local pscan = require "plenary.scandir"
|
||||
|
||||
@@ -345,8 +346,6 @@ previewers.new_buffer_previewer = function(opts)
|
||||
|
||||
local old_bufs = {}
|
||||
local bufname_table = {}
|
||||
|
||||
local global_state = require "telescope.state"
|
||||
local preview_window_id
|
||||
|
||||
local function get_bufnr(self)
|
||||
@@ -489,6 +488,29 @@ end
|
||||
previewers.cat = defaulter(function(opts)
|
||||
opts = opts or {}
|
||||
local cwd = opts.cwd or vim.loop.cwd()
|
||||
local function jump_to_line(bufnr, winid)
|
||||
pcall(vim.api.nvim_buf_clear_namespace, bufnr, ns_previewer, 0, -1)
|
||||
local location = global_state.get_global_key "prompt_location"
|
||||
|
||||
if location and location.row > 0 then
|
||||
local highlight_range = location.col and location.col > 0 and { location.col - 1, location.col } or { 0, -1 }
|
||||
|
||||
pcall(
|
||||
vim.api.nvim_buf_add_highlight,
|
||||
bufnr,
|
||||
ns_previewer,
|
||||
"TelescopePreviewLine",
|
||||
location.row - 1,
|
||||
highlight_range[1],
|
||||
highlight_range[2]
|
||||
)
|
||||
|
||||
pcall(vim.api.nvim_win_set_cursor, winid, { location.row, location.col })
|
||||
vim.api.nvim_buf_call(bufnr, function()
|
||||
vim.cmd "norm! zz"
|
||||
end)
|
||||
end
|
||||
end
|
||||
return previewers.new_buffer_previewer {
|
||||
title = "File Preview",
|
||||
dyn_title = function(_, entry)
|
||||
@@ -509,6 +531,9 @@ previewers.cat = defaulter(function(opts)
|
||||
winid = self.state.winid,
|
||||
preview = opts.preview,
|
||||
file_encoding = opts.file_encoding,
|
||||
callback = function(bufnr)
|
||||
jump_to_line(bufnr, self.state.winid)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
}
|
||||
|
||||
@@ -567,4 +567,45 @@ utils.list_find = function(func, list)
|
||||
end
|
||||
end
|
||||
|
||||
--- Takes the path and parses optional cursor location `$file:$line:$column`
|
||||
--- If line or column not present `0` returne returned.
|
||||
--- @param path string
|
||||
utils.separate_file_path_location = function(path)
|
||||
local location_numbers = {}
|
||||
-- Split the 2 last `:` separated parts and if they are numbers treat
|
||||
-- as line and columnd numbers
|
||||
for i = #path, 1, -1 do
|
||||
if path:sub(i, i) == ":" then
|
||||
-- If this is the last `:` we ignore it for a case when user
|
||||
-- just entered it with intention to enter a line or column number
|
||||
-- to not display "No results" immediately.
|
||||
if i == #path then
|
||||
path = path:sub(1, i - 1)
|
||||
else
|
||||
local location_value = tonumber(path:sub(i + 1))
|
||||
if location_value then
|
||||
table.insert(location_numbers, location_value)
|
||||
path = path:sub(1, i - 1)
|
||||
|
||||
if #location_numbers == 2 then
|
||||
-- There couldn't be more than 2 : separated number
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #location_numbers == 2 then
|
||||
-- because of the reverse the line number will be second
|
||||
return path, location_numbers[2], location_numbers[1]
|
||||
end
|
||||
|
||||
if #location_numbers == 1 then
|
||||
return path, location_numbers[1], 0
|
||||
end
|
||||
|
||||
return path, 0, 0
|
||||
end
|
||||
|
||||
return utils
|
||||
|
||||
@@ -78,3 +78,48 @@ describe("is_uri", function()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("separates file path location", function()
|
||||
local suites = {
|
||||
{
|
||||
input = "file.txt:12:4",
|
||||
file = "file.txt",
|
||||
row = 12,
|
||||
col = 4,
|
||||
},
|
||||
{
|
||||
input = "file.txt:12",
|
||||
file = "file.txt",
|
||||
row = 12,
|
||||
col = 0,
|
||||
},
|
||||
{
|
||||
input = "file:12:4",
|
||||
file = "file",
|
||||
row = 12,
|
||||
col = 4,
|
||||
},
|
||||
{
|
||||
input = "file:12:",
|
||||
file = "file",
|
||||
row = 12,
|
||||
col = 0,
|
||||
},
|
||||
{
|
||||
input = "file:",
|
||||
file = "file",
|
||||
row = 0,
|
||||
col = 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, suite in ipairs(suites) do
|
||||
it("separtates file path for " .. suite.input, function()
|
||||
local file, row, col = utils.separate_file_path_location(suite.input)
|
||||
|
||||
assert.are.equal(file, suite.file)
|
||||
assert.are.equal(row, suite.row)
|
||||
assert.are.equal(col, suite.col)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user