Ultisnips: `:UltiSnipsEdit` and snippet search paths have unmatching and weird semantics

Created on 20 Jun 2016  ·  37Comments  ·  Source: SirVer/ultisnips

Hi fellows,

I've installed UltiSnips and it did not start up well.

I use Vundle to manage plugins and installed UltiSnips. I typed :UltiSnipsEdit and could get into the Edit panel, so I assumed it should work fine.

But when I type snip and <tab> with it, it did not expand to the built-in snippet format. So I'm not sure it is working correctly and guessing my own snippets won't work either.

my env (I've got restricted internet access at work, so excuse me for using hand write presenting below):
vim version: 7.4.1859
has python

python version: 2.7.3

.vimrc:

set nocompatible
filetype off
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
Plugin 'VundleVim/Vundle.vim'
Plugin 'Lokaltog/vim-powerline'
Plugin 'SirVer/ultisnips'
call vundle#end()
filetype plugin indent on

let g:UltiSnipsUsePythonVersion = 2             " according to ultisnips/doc
let g:UltiSnipsExpandTrigger='<tab>'            " tried <c-a> and failed too
let g:UltiSnipsJumpForwardTrigger='<tab>'  " tried <c-j> and failed too
let g:UltiSnipsJumpBackwardTrigger='<s-tab>'
let g:UltiSnipsEditSplit='vertical'

Really appreciate some help here

Thank you!

answered or workaround exists medium

Most helpful comment

@seletskiy You might wanna change the workaround to

let g:UltiSnipsSnippetDirectories = ['~/.vim/UltiSnips', 'UltiSnips']

and Yes the workaround works. Thanks

All 37 comments

Also, I've tried ultisnips/test_all.py and It raised an exception and exit non-successfully.

Would it be some problem with my local python libraries/modules?

But when I type 'snip' and '' with it, it did not expand to the built-in snippet format. So I'm not sure it is working correctly and guessing my own snippets won't work either.

I don't understand what are you exactly mean by "when I type 'snip' and ''"?

Thanks for replying.

What I mean is:

After :UltiSnipsEdit, we get into the snippet edit panel. According to the screencast made by SirVer (http://www.sirver.net/blog/2012/01/08/second-episode-of-ultisnips-screencast/), we could type snip and expand it (with a tab), that is:

snip<tab>

then we could get:

snippet 's' "Desc..." b
endsnippet

It should be a built-in snippets but I failed to do so.

BTW, I got everything working and fine on my Macbook Air at home.

@xorange: snippets are not coming with UltiSnips plugin distribution. Also, snippet 's' definition is wrong, use snippet s.

@seletskiy Thanks. I understand that UltiSnips does not come with snippets. I did not add extra snippets on my macbook either but snip+<tab> also worked.

I've tried the snippet below, and it doesn't work:

snippet s "Test"
tryout
endsnippet

@xorange: Where do you store snippet definitions file?

@seletskiy Do you mean g:UltiSnipsSnippetsDir? I did not specify any.

A folder called UltiSnips created under my current dir and contains snippets I wrote with :UltiSnipsEdit in it.

@xorange: So, type :UltiSnipsEdit and then :echo expand('%:p'). What is the output?

@seletskiy ${CURDIR}/UltiSnips/all.snippets

Filename is test

@xorange: what is ${CURDIR}?

@seletskiy

:echo expand('%:p') gives /home/oliver/workspace/vim_testing/UltiSnips/all.snippets
test file I'm using: /home/oliver/workspace/vim_testing/test

@xorange: OK, I confirm the bug. @kovetskiy, as last contributor to the code belonging to erroneous logic, you might be interested in this issue.

@xorange: As a temporary workaround, set let g:UltiSnipsSnippetDirectories = ['.vim/UltiSnips', 'UltiSnips'].

@seletskiy You might wanna change the workaround to

let g:UltiSnipsSnippetDirectories = ['~/.vim/UltiSnips', 'UltiSnips']

and Yes the workaround works. Thanks

@xorange: Yes, thank you for noting that.

Also seem to be experiencing this bug.

I had exactly this problem and now the workaround solved it.

I also had to set runtimepath to the directory that contained my snippets directory, called UltiSnips.
So:

set runtimepath+=~/projects/dotfiles/snippets
let g:UltiSnipsSnippetsDir = "~/projects/dotfiles/snippets/UltiSnips"

Any update on a fix for this instead of the workaround so that arbitrary paths can be specified to g:UltiSnipsSnippetDirectories?

Also experiencing this bug using Neovim. Work around doesn't seem to work for me.

Does not work for me on MacVim

Managed to get custom snippets loading on MacVim via the fix suggested above, but found I had to use a fully-qualified path (i.e. without using ~ to represent my home directory):

let g:UltiSnipsSnippetDirectories = ["/Users/<<myusername>>/.vim/my-snippets/Ultisnips", "Ultisnips"]

It would be great to have a fix for this as it now means my .vimrc is no longer machine agnostic.

@lawrence-berry You can still have multiple configurations in one file by simply ifing for hostnames or operation systems

@lawrence-berry

Using Vim 7.4 on Ubuntu 16.04 and having installed UltiSnips using Pathogen.

I was having the same issue as described. Plugin was loading, but my snippets were not expanding. Typing :UltiSnipsEdit opened the expected snippets file in the expected directory.

I want to keep my snippets separate from my vim-config, as I have that source controlled.

This is the setup that worked for me:

~/.vim/ftdetect - Directory created, but not doing anything more there.
~/.ultisnips/UltiSnips/ - for hosting the Snippets
~/.ultisnips/ultisnips_rep/ftdetect -> ~/.vim/ftdetect - Symlinked as described in UltiSnips.txt

My vimrc has the following configuration, specific to UltiSnips:

set runtimepath+=~/.ultisnips/

let g:UltiSnipsSnippetsDir="~/.ultisnips/UltiSnips"

let g:UltiSnipsExpandTrigger="<Tab>"
let g:UltiSnipsJumpForwardTrigger="<Tab>"
let g:UltiSnipsJumpBackwardTrigger="<c-z>"

let g:UltiSnipsEditSplit="vertical"

To note, the UltiSnips.txt file recommends set runtimepath+=~/.vim/ultisnips_rep, where set runtimepath+=~/.ultisnips/ultisnips_rep did not work for me.

Dropping the ultisnips_rep from that runtimepath did the trick for me.

I've investigated this, but the project was without activity and I didn't presented the results.

The problem is here snippet_manager.py#L730-L774

  1. If g:UltiSnipsSnippetsDir is set, then it will try to open an existing file. If no file is found, snippet_dir will be set to g:UltiSnipsSnippetsDir, which will result in creating an empty file in g:UltiSnipsSnippetsDir at the end of the function.

    So, when g:UltiSnipsSnippetsDir is set everything almost works (an existing file in g:UltiSnipsSnippetDirectories will be ignored, see below).

  2. Now, if g:UltiSnipsSnippetsDir is not set, then g:UltiSnipsSnippetDirectories is checked. And here is where the problem appears.

    By default g:UltiSnipsSnippetDirectories is set to ['UltiSnips'], so in the for loop _get_file_to_edit(dir, requested_ft, bang) is called with a relative directory, which in turn calls find_snippet_files('<ft>', 'UltiSnips') and no snippets files will be found.

    But the actual problem is that snippet_dir is set anyway to 'UltiSnips' at the end of the loop, and this will bypass the next checks where a default directory ~/.vim/UltiSnips is set.

    So, by the end of the function, a new file will be created in ./UltiSnips/<ft>.snippets.

    Note that if g:UltiSnipsSnippetDirectories is set to a single directory with absolute path, then get_file_to_edit will find an existing file, or an empty file will be created in the right absolute directory (because snippet_dir is always set by the end of the loop).

The solution would be to to loop over the actual snippet directories, like:

    dir = _find_all_snippet_directories()

But I am not sure if it is the right approach. It may end up editing a file distributed by a plugin, which the user may not want to change.

After reading the updates to the documentation, I still think that it is not the right approach.

If the user sets g:UltiSnipsSnippetsDir then a matching snippets file in g:UltiSnipsSnippetDirectories should not be considered, unless bang is passed. For example, I have honza/vim-snippets in the rtp, but I don't want to edit those files, they are part of the plugins, not my custom snippets. Then I can set g:UltiSnipsSnippetsDir to always use my snippets directory and keep global snippets unchanged.

I think the algorithm could be:

  1. If bang is not set (:UltiSnipsEdit):

    • If g:UltiSnipsSnippetsDir is set, open an existing snippet file or create a new one in g:UltiSnipsSnippetsDir. Do not consider g:UltiSnipsSnippetDirectories nor the fallback directories. The user was clear to ignore those directories by setting the variable (which is the current behavior because the algorithm is buggy).

    • If g:UltiSnipsSnippetsDir is not set, try to open an existing snippets file in g:UltiSnipsSnippetDirectories. If no file found, fallback to opening or creating a snippets file
      in ~/.vim/UltiSnips (or the equivalent Windows/nvim directory).

  2. If bang is set (:UltiSnipsEdit!):

    • Collect all snippets files in g:UltiSnipsSnippetsDir, g:UltiSnipsSnippetDirectories and fallback directories, and let the user pick one.

    • If no existing files found, create a new one in g:UltiSnipsSnippetsDir if set, otherwise create a new one in the fallback directory.

If the user wants to edit snippets files distributed by the plugins when calling :UltiSnipsEdit, but also keep a directory with custom snippets, then they may use this:

let g:UltiSnipsSnippetDirectories = ['customDir', 'UltiSnips']

or keep them in ~/.vim/UltiSnips. No need to set g:UltiSnipsSnippetsDir in that case.

I can help with a PR if you agree with the algorithm.

Is this bug hard to fix?

@ptsteadman 我在windows上使用gvim遇到了相同的问题,你的答案非常有效,thank you vary much!

This bug is still there with NVIM v0.3.8 on 1a99766b73783bafb08cfa07d7e29e5387c55189.

Workaround was to do let g:UltiSnipsSnippetDirectories=[$HOME . "./custom_snippets", "UltiSnips"], which is machine agnostic for me since I always have a .custom_snippets directory in my $HOME.

This bug is still there with NVIM v0.3.8 on 1a99766.

Workaround was to do let g:UltiSnipsSnippetDirectories=[$HOME . "./custom_snippets", "UltiSnips"], which is machine agnostic for me since I always have a .custom_snippets directory in my $HOME.

I also faced this issue today with vim 8.1 and pathogen. Your workaround saved my day.

Also still encountering this bug. I don't know how it is possible to have custom snippets.

My UltiSnips config is:

" UltiSnips triggering
let g:UltiSnipsExpandTrigger='<C-e>'
let g:UltiSnipsSnippetsDir=$HOME.'/.vim/UltiSnips'
let g:UltiSnipsEditSplit='vertical'

When I type :UltiSnipsEdit it opens ~/.vim/UltiSnips/<file-type>.snippets, which is exactly what I would expect. I can make edits to the snippets, but they are not picked up. I run :call UltiSnips#RefreshSnippets() and that doesn't help pick up changes. I'm running out of ideas. Any progress on how custom snippets can be used? Is there any info on how to debug issues?

@mrinterweb What happens if you do not set let g:UltiSnipsSnippetsDir=$HOME.'/.vim/UltiSnips'.

@SirVer I unset that variable and it created a directory in <current-editor-path>/UltiSnips. The problem is identical regardless of setting the custom directory or unsetting it. I am unable to use any custom snippets. I can even copy snippets that are defined in vim-snippets/UltiSnips, rename the snippet, and it will not be found. I know the syntax for the snippet is correct.

revelant comment describing my current understanding of how g:UltiSnipsSnippetDirectories is supposed to be working is here: https://github.com/SirVer/ultisnips/issues/1117#issuecomment-550021966. I am yet unclear how g:UltiSnipsSnippetDir is supposed to be working going forward.

Please test and provide feedback on #1138. The functionality was simplified (in a backwards incompatible way), but should now be more consistent. It is a simplification of https://github.com/SirVer/ultisnips/issues/711#issuecomment-382517607. See PR description for explanation of the algorithm.

@SirVer I realize this is a bit late, but your #1138 PR fixed my problems. Thank you for that.

@mrinterweb Thanks!

Was this page helpful?
0 / 5 - 0 ratings