telescope.nvim icon indicating copy to clipboard operation
telescope.nvim copied to clipboard

Opening files leads to problems with restoring views and treesitter

Open jghauser opened this issue 3 years ago • 35 comments

Description

When I open a file from telescope, views aren't restored (e.g. cursor position, folds) and tree-sitter highlighting isn't used. Instead syntax highlighting is used. I can't create new folds either.

Expected Behavior When I open a file from telescope, views should be restored in the same way as when I open a file directly. Treesitter should be enabled just as it is when normally opening a file.

Actual Behavior Views aren't restored and treesitter isn't used. In order to get treesitter to work correctly and my views restored, I need to reload the buffer (:e) after opening the file. If I do just :loadview my view is restored, but treesitter highlighting is not. You can see that :e restores treesitter highlighting as doing :syntax before will give you the syntax items, whereas after :e it gives No Syntax items defined for this buffer.

Details

Reproduce
  1. open some file with folding and tree-sitter highlighting (e.g. a lua file)
  2. Move the cursor, open/close some folds
  3. close nvim
  4. run nvim
  5. open telescope with e.g. :Telescope find_files
  6. search for previous file and open it
Environment
  • nvim --version: NVIM v0.5.0-dev+1109-g6b7cc45c4
  • Operating system: Latest Arch Linux
  • Telescope commit: e2696d6
Configuration

if !filereadable('/tmp/plug.vim')
  silent !curl --insecure -fLo /tmp/plug.vim
    \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
endif

source /tmp/plug.vim
call plug#begin('/tmp/plugged')
Plug 'nvim-lua/popup.nvim'
Plug 'nvim-lua/plenary.nvim'
Plug 'nvim-telescope/telescope.nvim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} "treesitter
Plug 'zhimsel/vim-stay' "restore settings
call plug#end()

autocmd VimEnter * PlugClean! | PlugUpdate --sync | close

lua << EOF

require('telescope').setup{
  defaults = {
    vimgrep_arguments = {
      'rg',
      '--color=never',
      '--no-heading',
      '--with-filename',
      '--line-number',
      '--column',
      '--smart-case'
    },
    prompt_position = "bottom",
    prompt_prefix = ">",
    selection_strategy = "reset",
    sorting_strategy = "descending",
    layout_strategy = "horizontal",
    layout_defaults = {},
    file_ignore_patterns = {},
    shorten_path = true,
    winblend = 0,
    width = 0.75,
    preview_cutoff = 120,
    results_height = 1,
    results_width = 0.8,
    border = {},
    borderchars = { '─', '│', '─', '│', '╭', '╮', '╯', '╰'},
    color_devicons = true,
    use_less = true,
  }
}

require'nvim-treesitter.configs'.setup({
  ensure_installed = "maintained",     -- one of "all", "maintained", or a list of languages
  highlight = {
    enable = true,              -- false will disable the whole extension
    disable = {},               -- list of language that will be disabled
  },
})

EOF

" folding
set foldmethod=expr
set foldexpr=nvim_treesitter#foldexpr()

" view restore
set viewoptions=cursor,folds,slash,unix

jghauser avatar Feb 26 '21 12:02 jghauser

Thats a bug that i actually newer understood. I can totally reproduce it. Not all tho. Treesitter hightlighting works fine on my side. But everything with fold doesn't. I usually just do :e to fix it tho. If you are using treesitter you will never have syntax items. syntax should be off tho.

About folds. We have a huge discussion over there: https://github.com/nvim-telescope/telescope.nvim/pull/541#issuecomment-786077728

I can have folds if i don't do actions.center afterwards. So i have this in my config:

    mappings = {
      i = {
        -- ["<CR>"] = actions.select_default,
      },
    },

and i can use my fold. view is still not restored. Which is sooooooo weird. All we do is vim.cmd("edit relative/file/path/file.lua") (thats the lua version of :edit)

Conni2461 avatar Feb 26 '21 13:02 Conni2461

Yeah, that's what I meant with syntax. I get syntax items when I first open the file from Telescope, but once I reload, the syntax items disappear (indicating that treesitter was not used at first, but is used after reloading). Interestingly, this happens even if I have set syntax=off in init.vim (it must get switched on somewhere?). Are you sure that treesitter works for you? Because for me, even with the minimal config, I get this result.

I tried fixing this with a variety of autocmds, but none of them seem to work...

Thanks for the trick with folds, that's useful! Though I really mostly need the views restored (I use it for almost all files). If there's anything I can do to help debug this, let me know!

Btw. folds for me start working when I edit the newly opened file (so some folds appear when I press e.g. o). Recalculating the folds (with zx) also works.

jghauser avatar Feb 26 '21 14:02 jghauser

I don't know how to debug it. I already removed everything in the action besides like vim.cmd and i still reproduce it but highlighting works. Even the previewers are using tree sitter nowadays. See https://streamable.com/qpq1xx

Edit: i also tried the provided minimal rc. both highlighting and cursor restoring works

Conni2461 avatar Feb 26 '21 14:02 Conni2461

You're right. Disabling treesitter highlights does change highlights for me too. What's odd though is that on first loading the file, standard syntax highlighting is working also, somehow superimposed. When I do :set syntax I first get syntax=lua and after reloading I get syntax=. This is mostly invisible because highlights from treesitter+syntax look very similar to those from just treesitter. I noticed the difference with the (not enabled by default) markdown treesitter, where the differences are quite obvious.

And yes, I was wrong about cursor restore. That does work.

I'll let you know if I notice anything else.

jghauser avatar Feb 26 '21 15:02 jghauser

Hey @Conni2461 ! Any news on this one ?

This is the only remaining reason why I havn't completly switched to telescope from fzf.vim. And I would sooooo love to adopt telescope and only telescope !!

(On my side, the 'workaround' having ["<CR>"] = actions.select_default to respect folds seems not to work :/ )

PS: Thanks for all the work done up until now, it's amazingly good !

gjeusel avatar Apr 16 '21 11:04 gjeusel

I managed to make it work somehow by using attach_mappings to overwrite the last action (center in my case):

local telescope = require("telescope")
local builtin = require("telescope.builtin")
local actions = require("telescope.actions")

telescope.setup({
  defaults = {
    mapping = {
      ["<cr>"] = actions.select_default + actions.center,  -- is the telescope default btw
    },
  },
})

local find_files_opts = {
  attach_mappings = function(_)
    actions.center:replace(function(_)
      vim.wo.foldmethod = vim.wo.foldmethod or "expr"
      vim.wo.foldexpr = vim.wo.foldexpr or "nvim_treesitter#foldexpr()"
      vim.cmd(":normal! zx")
      vim.cmd(":normal! zz")
      pcall(vim.cmd, ":loadview") -- silent load view
    end)
    return true
  end,
}

builtin.my_find_files = function(opts)
  opts = opts or {}
  return builtin.find_files(vim.tbl_extend("error", find_files_opts, opts))
end

vim.api.nvim_set_keymap(
  "n",
  "<leader>ff",
  "<cmd>lua require('telescope.builtin').my_find_files()<cr>",
  { noremap = true }
)

Beware that the loadview should only be done on file finding.

gjeusel avatar Jun 20 '21 10:06 gjeusel

@gjeusel: Not sure if I'm doing something wrong, but it doesn't seem to work for me. I copied and pasted your exact config and folds aren't closed when i first open a file with telescope :/.

jghauser avatar Jun 20 '21 12:06 jghauser

@gjeusel: Not sure if I'm doing something wrong, but it doesn't seem to work for me. I copied and pasted your exact config and folds aren't closed when i first open a file with telescope :/.

Updated the sample (The mapping was not calling my_find_files)

gjeusel avatar Jun 21 '21 06:06 gjeusel

Thank you! With some adjustments it worked for telescope-frecency, too!

extensions.frecency.my_frecency = function(opts)
  opts = opts or {}
  return extensions.frecency.frecency(vim.tbl_extend("error", find_files_opts, opts))
end

nvim_set_keymap('n', '<leader>fm', "<Cmd>lua require('telescope').extensions.frecency.my_frecency()<CR>", {noremap = true, silent = true})

jghauser avatar Jun 21 '21 07:06 jghauser

I had the same issue with disabled folds and came up with this solution. It works for any kind of selection, including vertical, horizontal or opening in the current buffer.

local action_set = require('telescope.actions.set')

require('telescope').setup {
  pickers = {
    find_files = {
      hidden = true,
      attach_mappings = function(prompt_bufnr)
        action_set.select:enhance({
          post = function()
            vim.cmd(":normal! zx")
          end
        })
        return true
      end
    },
  }
}

rainerborene avatar Jul 24 '21 23:07 rainerborene

Thank you @rainerborene. I did have success in applying your solution: https://github.com/nvim-telescope/telescope.nvim/issues/559#issuecomment-886123429

I had to make a few adjustments to get it to apply to the other pickers (wasn't able to find a way to fix all of them without calling them out individually).

local telescope_actions = require("telescope.actions.set")

local fixfolds = {
	hidden = true,
	attach_mappings = function(_)
		telescope_actions.select:enhance({
			post = function()
				vim.cmd(":normal! zx")
			end,
		})
		return true
	end,
}

require('telescope').setup {
	pickers = {
		buffers = fixfolds,
		file_browser = fixfolds,
		find_files = fixfolds,
		git_files = fixfolds,
		grep_string = fixfolds,
		live_grep = fixfolds,
		oldfiles = fixfolds,
		-- I probably missed some
	},
}

bockel avatar Oct 05 '21 19:10 bockel

I have been looking at this. I think it happens because telescope opens the file while being in insert mode. The neovim function foldUpdate has a conditional that disallows folds to update when in insert mode.

This bug doesn't occur if you are already in normal mode in the telescope window.

Currently this patch works

diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua
index 3e10c63..daff02e 100644
--- a/lua/telescope/actions/init.lua
+++ b/lua/telescope/actions/init.lua
@@ -131,6 +131,10 @@ function actions.drop_all(prompt_bufnr)
   end)
 end
 
+function actions.goto_normal(prompt_bufnr)
+  vim.cmd[[stopinsert]]
+end
+
 --- Toggle multi selection for all entries.
 --- - Note: toggled entries may include results not visible in the results popup.
 ---@param prompt_bufnr number: The prompt bufnr
diff --git a/lua/telescope/mappings.lua b/lua/telescope/mappings.lua
index 27e5d07..e1d87e2 100644
--- a/lua/telescope/mappings.lua
+++ b/lua/telescope/mappings.lua
@@ -17,7 +17,7 @@ mappings.default_mappings = config.values.default_mappings
       ["<Down>"] = actions.move_selection_next,
       ["<Up>"] = actions.move_selection_previous,
 
-      ["<CR>"] = actions.select_default,
+      ["<CR>"] = actions.goto_normal + actions.select_default,
       ["<C-x>"] = actions.select_horizontal,
       ["<C-v>"] = actions.select_vertical,
       ["<C-t>"] = actions.select_tab,

Interestingly putting the vim.cmd[[stopinsert]] line in pre field of actions.select_default doesn't. I would be happy to work on a PR if someone points me in the right direction.

cc @Conni2461

abelmul avatar Dec 29 '21 22:12 abelmul

Can y'all test if #1643 fixes the issue for you?

abelmul avatar Dec 31 '21 12:12 abelmul

Just tried it out and it works!

Saecki avatar Jan 03 '22 08:01 Saecki

I had to revert the PR :(

Conni2461 avatar Jan 09 '22 20:01 Conni2461

Unfortinutly the https://github.com/nvim-telescope/telescope.nvim/issues/559#issuecomment-886123429 solution does not work for me.

I use the next solution:

autocmd BufRead * autocmd BufWinEnter * ++once normal! zx

or the same but with new autocmd API:

vim.api.nvim_create_autocmd('BufRead', {
   callback = function()
      vim.api.nvim_create_autocmd('BufWinEnter', {
         once = true,
         command = 'normal! zx'
      })
   end
})

BufWinEnter is needed to take into account modeline settings. And why it is not used alone but after BufRead, is due to need to execute BufWinEnter autocommand only once for each buffer.

anuvyklack avatar Mar 21 '22 15:03 anuvyklack

Unfortinutly the #559 (comment) solution does not work for me.

I use the next solution:

autocmd BufRead * autocmd BufWinEnter * ++once normal! zx zM

or the same but with new autocmd API:

vim.api.nvim_create_autocmd('BufRead', {
   callback = function()
      vim.api.nvim_create_autocmd('BufWinEnter', {
         once = true,
         command = 'normal! zx zM'
      })
   end
})

BufWinEnter is needed to take into account modeline settings. And why it is not used alone but after BufRead, is due to need to execute BufWinEnter autocommand only once for each buffer.

Yes,

  augroup _fold_bug_solution  " https://github.com/nvim-telescope/telescope.nvim/issues/559
    autocmd!
    autocmd BufRead * autocmd BufWinEnter * ++once normal! zx
  augroup end

works when open a file by telescope. However, I find it makes

augroup remember_folds
  autocmd!
  autocmd BufWinLeave *.* mkview
  autocmd BufWinEnter *.* silent! loadview
augroup END

can not remember the folds anymore.

xyecoding avatar May 06 '22 06:05 xyecoding

All of the solutions seem to not work with nvim-ufo. Anyone have any ideas about a workaround to get the workaround to work? :rofl:

jghauser avatar Jul 20 '22 18:07 jghauser

I use ufo with treesitter provider and this autocommand:

vim.api.nvim_create_autocmd('BufRead', {
   callback = function()
      vim.api.nvim_create_autocmd('BufWinEnter', {
         once = true,
         callback = function()
            vim.defer_fn(function()
               vim.api.nvim_feedkeys('zM', 'm', false)
            end, 70)
         end
      })
   end
})

anuvyklack avatar Jul 20 '22 18:07 anuvyklack

Thanks a lot @anuvyklack! I modified it a bit to get my desired behaviour, namely to restore views:

vim.api.nvim_create_autocmd("BufRead", {
	callback = function()
		vim.api.nvim_create_autocmd("BufWinEnter", {
			once = true,
			callback = function()
				vim.defer_fn(function()
					vim.cmd([[:silent! loadview]])
				end, 60)
			end,
		})
	end,
})

EDIT: actually the above fails sometimes for some files... As clunky as feedkeys is it seems to be essential. Use this instead inside defer_fn:

local str = vim.api.nvim_replace_termcodes(":silent! loadview<cr>", true, false, true)
vim.api.nvim_feedkeys(str, "m", false)

EDIT2: After some changes implemented by the ufo dev, no more special workarounds are needed!

jghauser avatar Jul 20 '22 19:07 jghauser

May be problem is in colon inside vim.cmd. Colon needs to enter command mode, it is not needed inside vim.cmd.

anuvyklack avatar Jul 20 '22 21:07 anuvyklack

Thanks for the idea, but I don't think that's it. The colon isn't needed, but I think it's simply ignored. In any case, the result is the same: with vim.cmd it mostly works but some files' (especially markdown? hard to pin down exactly) folds aren't restored. With your feedkeys workaround it seems to work :crossed_fingers:

jghauser avatar Jul 20 '22 22:07 jghauser

@anuvyklack, the developer of ufo has implemented a change, so that now i'm able to go back to a simple vim.cmd commands, no more iffy feedkeys stuff needed!

jghauser avatar Jul 23 '22 14:07 jghauser

None of the above worked for me so thanks to the discovery of @abelmul I fixed it like this: Edit: My custom fold text didn't work with foldmethod: indent when opening files with Telescope.

require('telescope').setup {
    defaults = {
        mappings = {
            i = {
                ["<CR>"] = function()
                    vim.cmd [[:stopinsert]]
                    vim.cmd [[call feedkeys("\<CR>")]]
                end
            }
        }
    }
}

C-Rmoser avatar Jul 26 '22 19:07 C-Rmoser

Is anyone working on an actual fix within Telescope for this problem?

lervag avatar Aug 18 '22 12:08 lervag

this works for me

  • approach n. 1
["<CR>"] = function(prompt_bufnr)
    vim.cmd.stopinsert()
    vim.defer_fn(function() actions.select_default(prompt_bufnr) end, 10)
end
  • approach n. 2
local function use_normal_mapping(key)
    return function()
        vim.cmd.stopinsert()
        local key_code = vim.api.nvim_replace_termcodes(key, true, false, true)
        vim.api.nvim_feedkeys(key_code, "m", false)
    end
end

...

["<CR>"] = use_normal_mapping("<CR>")

idk which one is the least hackish, but the fact that approach n. 1 works using a deferred function means the internal mode cannot be overridden while evaluating the body of an insert mode mapping (?? makes sense?)

eg:

    ["<CR>"] = function(prompt_bufnr)
        vim.cmd.stopinsert()
        print(vim.fn.mode())
        vim.defer_fn(function()
            print(vim.fn.mode())
            actions.select_default(prompt_bufnr)
        end, 10)
    end,

EDIT:

final take:

local function stopinsert(callback)
    return function(prompt_bufnr)
        vim.cmd.stopinsert()
        vim.schedule(function()
            callback(prompt_bufnr)
        end)
    end
end

...

["<CR>"] = stopinsert(actions.select_default)

rebelot avatar Aug 19 '22 18:08 rebelot

Below is extended configuration using schedule() proposed by @rebelot which

  • applies the workaround to other go-to key bindings such as <C-x>, <C-v>, <C-t>,
  • treats directories differently in the file_browser extension (no stopinsert in this case),
  • adds <C-t> key binding for files in the file_browser extension (open in a tab), while preserving its original purpose (change_cwd) for directories.
local function stopinsert(callback)
  return function(prompt_bufnr)
    vim.cmd.stopinsert()
    vim.schedule(function() callback(prompt_bufnr) end)
  end
end

local function stopinsert_fb(callback, callback_dir)
  return function(prompt_bufnr)
    local entry = require'telescope.actions.state'.get_selected_entry()
    if entry and not entry.Path:is_dir() then
      stopinsert(callback)(prompt_bufnr)
    elseif callback_dir then
      callback_dir(prompt_bufnr)
    end
  end
end

local actions = require'telescope.actions'
local actions_fb = require'telescope'.extensions.file_browser.actions

require'telescope'.setup {
  defaults = {
    mappings = {
      i = {
        ["<CR>"]  = stopinsert(actions.select_default),
        ["<C-x>"] = stopinsert(actions.select_horizontal),
        ["<C-v>"] = stopinsert(actions.select_vertical),
        ["<C-t>"] = stopinsert(actions.select_tab)
      }
    }
  },
  extensions = {
    file_browser = {
      mappings = {
        i = {
          ["<CR>"]  = stopinsert_fb(actions.select_default, actions.select_default),
          ["<C-x>"] = stopinsert_fb(actions.select_horizontal),
          ["<C-v>"] = stopinsert_fb(actions.select_vertical),
          ["<C-t>"] = stopinsert_fb(actions.select_tab, actions_fb.change_cwd)
        }
      }
    }
  }
}

lyokha avatar Nov 11 '22 09:11 lyokha

I'm coming to this cold and I don't know the internals of Telescope, but all of these symptoms and hacky solutions leads to me wonder if the code is running in the context of an autocmd that does not allow other autocmds to run?

:h autocmd-nested

cseickel avatar Dec 02 '22 13:12 cseickel

I guess this might not be a problem of telescope, and instead it might be a bug of neovim (or treesitter):

this is a minimal example:

suppose I am at my neovim root directory (~/.config/nvim), and I have defined the following command:

vim.o.foldmethod = 'expr'
vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
vim.keymap.set('i', '<C-x>', function() vim.cmd.edit 'lua/conf/builtin_extend.lua' end)

and typing <C-x> within any file (say init.lua) and then the fold is not activated in the builtin_extend.lua just opened.

It is also worthy to note that telescope plays nicely with set foldmethod=indent.

milanglacier avatar May 04 '23 06:05 milanglacier

folds were fixed in #2726 fix is applied to latest master, 0.1.x and the latest stable release 0.1.4

Conni2461 avatar Oct 11 '23 06:10 Conni2461