From dbeecdbe24a79e26d76bc505044f7ffd0f0b89bc Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 12:37:07 -0300 Subject: [PATCH 1/6] use consistent spacing in vim file --- plugin/UltiSnips.vim | 159 ++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index e742a61..2501cd7 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -17,46 +17,46 @@ endif " The trigger used to expand a snippet. " NOTE: expansion and forward jumping can, but needn't be the same trigger if !exists("g:UltiSnipsExpandTrigger") - let g:UltiSnipsExpandTrigger = "" + let g:UltiSnipsExpandTrigger = "" endif " The trigger used to display all triggers that could possible " match in the current position. if !exists("g:UltiSnipsListSnippets") - let g:UltiSnipsListSnippets = "" + let g:UltiSnipsListSnippets = "" endif " The trigger used to jump forward to the next placeholder. " NOTE: expansion and forward jumping can, but needn't be the same trigger if !exists("g:UltiSnipsJumpForwardTrigger") - let g:UltiSnipsJumpForwardTrigger = "" + let g:UltiSnipsJumpForwardTrigger = "" endif " The trigger to jump backward inside a snippet if !exists("g:UltiSnipsJumpBackwardTrigger") - let g:UltiSnipsJumpBackwardTrigger = "" + let g:UltiSnipsJumpBackwardTrigger = "" endif " Should UltiSnips unmap select mode mappings automagically? if !exists("g:UltiSnipsRemoveSelectModeMappings") - let g:UltiSnipsRemoveSelectModeMappings = 1 + let g:UltiSnipsRemoveSelectModeMappings = 1 end " If UltiSnips should remove Mappings, which should be ignored if !exists("g:UltiSnipsMappingsToIgnore") - let g:UltiSnipsMappingsToIgnore = [] + let g:UltiSnipsMappingsToIgnore = [] endif " UltiSnipsEdit will use this variable to decide if a new window " is opened when editing. default is "normal", allowed are also " "vertical", "horizontal" if !exists("g:UltiSnipsEditSplit") - let g:UltiSnipsEditSplit = 'normal' + let g:UltiSnipsEditSplit = 'normal' endif " A list of directory names that are searched for snippets. if !exists("g:UltiSnipsSnippetDirectories") - let g:UltiSnipsSnippetDirectories = [ "UltiSnips" ] + let g:UltiSnipsSnippetDirectories = [ "UltiSnips" ] endif " }}} @@ -66,35 +66,35 @@ endif command! -nargs=0 UltiSnipsReset :py UltiSnips_Manager.reset() function! UltiSnipsEdit(...) - if a:0 == 1 && a:1 != '' - let type = a:1 - elseif &filetype != '' - let type = split(&filetype, '\.')[0] - else - let type = 'all' - endif + if a:0 == 1 && a:1 != '' + let type = a:1 + elseif &filetype != '' + let type = split(&filetype, '\.')[0] + else + let type = 'all' + endif - if exists('g:UltiSnipsSnippetsDir') - let mode = 'e' - if exists('g:UltiSnipsEditSplit') - if g:UltiSnipsEditSplit == 'vertical' - let mode = 'vs' - elseif g:UltiSnipsEditSplit == 'horizontal' - let mode = 'sp' - endif - endif - exe ':'.mode.' '.g:UltiSnipsSnippetsDir.'/'.type.'.snippets' - else - for dir in g:UltiSnipsSnippetDirectories - for p in reverse(split(&runtimepath, ',')) - if isdirectory(p.'/'.dir) - let g:UltiSnipsSnippetsDir = p.'/'.dir - call UltiSnipsEdit(type) - break - endif - endfor - endfor - endif + if exists('g:UltiSnipsSnippetsDir') + let mode = 'e' + if exists('g:UltiSnipsEditSplit') + if g:UltiSnipsEditSplit == 'vertical' + let mode = 'vs' + elseif g:UltiSnipsEditSplit == 'horizontal' + let mode = 'sp' + endif + endif + exe ':'.mode.' '.g:UltiSnipsSnippetsDir.'/'.type.'.snippets' + else + for dir in g:UltiSnipsSnippetDirectories + for p in reverse(split(&runtimepath, ',')) + if isdirectory(p.'/'.dir) + let g:UltiSnipsSnippetsDir = p.'/'.dir + call UltiSnipsEdit(type) + break + endif + endfor + endfor + endif endfunction " edit snippets, default of current file type or the specified type @@ -104,46 +104,46 @@ command! -nargs=? UltiSnipsEdit :call UltiSnipsEdit() "" FUNCTIONS {{{ function! CompensateForPUM() - """ The CursorMovedI event is not triggered while the popup-menu is visible, - """ and it's by this event that UltiSnips updates its vim-state. The fix is - """ to explicitly check for the presence of the popup menu, and update - """ the vim-state accordingly. - if pumvisible() - py UltiSnips_Manager.cursor_moved() - endif + """ The CursorMovedI event is not triggered while the popup-menu is visible, + """ and it's by this event that UltiSnips updates its vim-state. The fix is + """ to explicitly check for the presence of the popup menu, and update + """ the vim-state accordingly. + if pumvisible() + py UltiSnips_Manager.cursor_moved() + endif endfunction function! UltiSnips_ExpandSnippet() - py UltiSnips_Manager.expand() - return "" + py UltiSnips_Manager.expand() + return "" endfunction function! UltiSnips_ExpandSnippetOrJump() - call CompensateForPUM() - py UltiSnips_Manager.expand_or_jump() - return "" + call CompensateForPUM() + py UltiSnips_Manager.expand_or_jump() + return "" endfunction function! UltiSnips_ListSnippets() - py UltiSnips_Manager.list_snippets() - return "" + py UltiSnips_Manager.list_snippets() + return "" endfunction function! UltiSnips_JumpBackwards() - call CompensateForPUM() - py UltiSnips_Manager.jump_backwards() - return "" + call CompensateForPUM() + py UltiSnips_Manager.jump_backwards() + return "" endfunction function! UltiSnips_JumpForwards() - call CompensateForPUM() - py UltiSnips_Manager.jump_forwards() - return "" + call CompensateForPUM() + py UltiSnips_Manager.jump_forwards() + return "" endfunction function! UltiSnips_AddSnippet(trigger, value, descr, options, ...) - " Takes the same arguments as SnippetManager.add_snippet: - " (trigger, value, descr, options, ft = "all", globals = None) + " Takes the same arguments as SnippetManager.add_snippet: + " (trigger, value, descr, options, ft = "all", globals = None) py << EOB args = vim.eval("a:000") trigger = vim.eval("a:trigger") @@ -153,38 +153,38 @@ options = vim.eval("a:options") UltiSnips_Manager.add_snippet(trigger, value, descr, options, *args) EOB - return "" + return "" endfunction function! UltiSnips_Anon(value, ...) - " Takes the same arguments as SnippetManager.expand_anon: - " (value, trigger="", descr="", options="", globals = None) + " Takes the same arguments as SnippetManager.expand_anon: + " (value, trigger="", descr="", options="", globals = None) py << EOB args = vim.eval("a:000") value = vim.eval("a:value") UltiSnips_Manager.expand_anon(value, *args) EOB - return "" + return "" endfunction function! UltiSnips_MapKeys() - " Map the keys correctly - if g:UltiSnipsExpandTrigger == g:UltiSnipsJumpForwardTrigger - exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips_ExpandSnippetOrJump()" - exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips_ExpandSnippetOrJump()" - else - exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips_ExpandSnippet()" - exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips_ExpandSnippet()" - exec "inoremap " . g:UltiSnipsJumpForwardTrigger . " =UltiSnips_JumpForwards()" - exec "snoremap " . g:UltiSnipsJumpForwardTrigger . " :call UltiSnips_JumpForwards()" - endif - exec "inoremap " . g:UltiSnipsJumpBackwardTrigger . " =UltiSnips_JumpBackwards()" - exec "snoremap " . g:UltiSnipsJumpBackwardTrigger . " :call UltiSnips_JumpBackwards()" - exec "inoremap " . g:UltiSnipsListSnippets . " =UltiSnips_ListSnippets()" - exec "snoremap " . g:UltiSnipsListSnippets . " :call UltiSnips_ListSnippets()" + " Map the keys correctly + if g:UltiSnipsExpandTrigger == g:UltiSnipsJumpForwardTrigger + exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips_ExpandSnippetOrJump()" + exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips_ExpandSnippetOrJump()" + else + exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips_ExpandSnippet()" + exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips_ExpandSnippet()" + exec "inoremap " . g:UltiSnipsJumpForwardTrigger . " =UltiSnips_JumpForwards()" + exec "snoremap " . g:UltiSnipsJumpForwardTrigger . " :call UltiSnips_JumpForwards()" + endif + exec "inoremap " . g:UltiSnipsJumpBackwardTrigger . " =UltiSnips_JumpBackwards()" + exec "snoremap " . g:UltiSnipsJumpBackwardTrigger . " :call UltiSnips_JumpBackwards()" + exec "inoremap " . g:UltiSnipsListSnippets . " =UltiSnips_ListSnippets()" + exec "snoremap " . g:UltiSnipsListSnippets . " :call UltiSnips_ListSnippets()" - " Do not remap this. - snoremap :py UltiSnips_Manager.backspace_while_selected() + " Do not remap this. + snoremap :py UltiSnips_Manager.backspace_while_selected() endf " }}} @@ -207,7 +207,8 @@ au CursorMovedI * py UltiSnips_Manager.cursor_moved() au InsertEnter * py UltiSnips_Manager.entered_insert_mode() call UltiSnips_MapKeys() - + let did_UltiSnips_vim=1 " }}} +" vim: ts=8 sts=4 sw=4 From ad84c346d01228824079e63829007eef135376d0 Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 15:26:12 -0300 Subject: [PATCH 2/6] - extracted and cleaned up searching for snippets files - cleaned up UltiSnipsEdit by rewriting in python reusing existing code --- plugin/UltiSnips.vim | 32 ++++-------- plugin/UltiSnips/__init__.py | 95 ++++++++++++++++++++++++++++++------ 2 files changed, 91 insertions(+), 36 deletions(-) diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index 2501cd7..098efbd 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -68,33 +68,21 @@ command! -nargs=0 UltiSnipsReset :py UltiSnips_Manager.reset() function! UltiSnipsEdit(...) if a:0 == 1 && a:1 != '' let type = a:1 - elseif &filetype != '' - let type = split(&filetype, '\.')[0] else - let type = 'all' + python vim.command("let type = '%s'" % UltiSnips_Manager.filetype) endif - if exists('g:UltiSnipsSnippetsDir') - let mode = 'e' - if exists('g:UltiSnipsEditSplit') - if g:UltiSnipsEditSplit == 'vertical' - let mode = 'vs' - elseif g:UltiSnipsEditSplit == 'horizontal' - let mode = 'sp' - endif + python vim.command("let file = '%s'" % UltiSnips_Manager.file_to_edit(vim.eval("type"))) + + let mode = 'e' + if exists('g:UltiSnipsEditSplit') + if g:UltiSnipsEditSplit == 'vertical' + let mode = 'vs' + elseif g:UltiSnipsEditSplit == 'horizontal' + let mode = 'sp' endif - exe ':'.mode.' '.g:UltiSnipsSnippetsDir.'/'.type.'.snippets' - else - for dir in g:UltiSnipsSnippetDirectories - for p in reverse(split(&runtimepath, ',')) - if isdirectory(p.'/'.dir) - let g:UltiSnipsSnippetsDir = p.'/'.dir - call UltiSnipsEdit(type) - break - endif - endfor - endfor endif + exe ':'.mode.' '.file endfunction " edit snippets, default of current file type or the specified type diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index 393bc6d..ddcefd6 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -556,10 +556,10 @@ class VimState(object): # Check if any mappings where found all_maps = filter(len, vim.eval(r"_tmp_smaps").splitlines()) if (len(all_maps) == 1 and all_maps[0][0] not in " sv"): - # "No maps found". String could be localized. Hopefully - # it doesn't start with any of these letters in any - # language - continue + # "No maps found". String could be localized. Hopefully + # it doesn't start with any of these letters in any + # language + continue # Only keep mappings that should not be ignored maps = [m for m in all_maps if @@ -870,9 +870,8 @@ class SnippetManager(object): feedkeys(feedkey, mode) def _ensure_snippets_loaded(self): - filetypes = vim.eval("&filetype").split(".") + [ "all" ] - for ft in filetypes[::-1]: - if len(ft) and ft not in self._snippets: + for ft in self._filetypes(): + if ft not in self._snippets: self._load_snippets_for(ft) return filetypes @@ -1066,17 +1065,85 @@ class SnippetManager(object): def _parse_snippets(self, ft, fn, file_data=None): _SnippetsFileParser(ft, fn, self, file_data).parse() + def base_snippet_files_for(self, ft, default=True): + snippet_dirs = vim.eval("g:UltiSnipsSnippetDirectories") + base_snippets = os.path.realpath(os.path.join(__file__, "../../../UltiSnips")) + ret = [] + + for rtp in vim.eval("&runtimepath").split(',')[::-1]: + for snippet_dir in snippet_dirs: + pth = os.path.realpath(os.path.join(rtp, snippet_dir)) + + patterns = ["%s.snippets", "*_%s.snippets"] # TODO: doc this + if not default and pth == base_snippets: + patterns.remove("%s.snippets") + + for pattern in patterns: + for fn in glob.glob(os.path.join(pth, pattern % ft)): + if fn not in ret: + ret.append(fn) + + return ret + + def _filetypes(self, dotft=None): + if dotft is None: + dotft = vim.eval("&filetype") + + fts = dotft.split(".") + [ "all" ] + return [ft for ft in fts[::-1] if ft] + + def filetype(self): + return self._filetypes()[-1] + filetype = property(filetype) + + def file_to_edit(self, ft=None): + if not ft: + ft = self.filetype + + edit = None + existing = self.base_snippet_files_for(ft, False) + filename = ft + ".snippets" + + if vim.eval("exists('g:UltiSnipsSnippetsDir')") == 1: # TODO: doc this + snipdir = vim.eval("g:UltiSnipsSnippetsDir") + edit = os.path.join(snipdir, filename) + elif existing: + edit = existing[-1] # last sourced/highest priority + else: + home = vim.eval("$HOME") + rtp = vim.eval("&rtp").split(",") + snippet_dirs = ["UltiSnips"] + vim.eval("g:UltiSnipsSnippetDirectories") + us = snippet_dirs[-1] + + path = os.path.join(home, ".vim", us) + for dirname in [".vim", "vimfiles"]: + pth = os.path.join(home, dirname) + if pth in rtp: + path = os.path.join(pth, us) + + if not os.path.isdir(path): + os.mkdir(path) + + edit = os.path.join(path, filename) + + return edit + + + def base_snippet_files(self, dotft=None): + ret = [] + filetypes = self._filetypes(dotft) + + for ft in filetypes: + ret += self.base_snippet_files_for(ft) + + return ret + # Loading def _load_snippets_for(self, ft): self._snippets[ft] = _SnippetDictionary() - snippet_dirs = vim.eval("g:UltiSnipsSnippetDirectories") - for p in vim.eval("&runtimepath").split(',')[::-1]: - for snippet_dir in snippet_dirs: - pattern = os.path.join(p, snippet_dir, "*%s.snippets" % ft) - - for fn in glob.glob(pattern): - self._parse_snippets(ft, fn) + for fn in self.base_snippet_files_for(ft): + self._parse_snippets(ft, fn) # Now load for the parents for p in self._snippets[ft].extends: From ce6efdd95c1fde167873fcbc6bcc76109d2a2688 Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 15:37:12 -0300 Subject: [PATCH 3/6] added in-code documentation --- plugin/UltiSnips/__init__.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index ddcefd6..a280a5f 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -1066,6 +1066,16 @@ class SnippetManager(object): _SnippetsFileParser(ft, fn, self, file_data).parse() def base_snippet_files_for(self, ft, default=True): + """ Returns a list of snippet files matching the given filetype (ft). + If default is set to false, it doesn't include shipped files. + + Searches through each path in 'runtimepath' in reverse order, + in each of these, it searches each directory name listed in + 'g:UltiSnipsSnippetDirectories' in order, then looks for files in these + directories called 'ft.snippets' or '*_ft.snippets' replacing ft with + the filetype. + """ + snippet_dirs = vim.eval("g:UltiSnipsSnippetDirectories") base_snippets = os.path.realpath(os.path.join(__file__, "../../../UltiSnips")) ret = [] @@ -1093,10 +1103,18 @@ class SnippetManager(object): return [ft for ft in fts[::-1] if ft] def filetype(self): + """ Property for the current (undotted) filetype. """ return self._filetypes()[-1] filetype = property(filetype) def file_to_edit(self, ft=None): + """ Gets a file to edit based on the given filetype. + If no filetype is given, uses the current filetype from vim. + + Checks 'g:UltiSnipsSnippetsDir' and uses it if it exists + If a non-shipped file already exists, it uses it. + Otherwise uses a file in ~/.vim/ or ~/vimfiles + """ if not ft: ft = self.filetype @@ -1130,6 +1148,11 @@ class SnippetManager(object): def base_snippet_files(self, dotft=None): + """ Returns a list of all snippet files for the given filetype. + If no filetype is given, uses furrent filetype. + If the filetype is dotted (e.g. 'cuda.cpp.c') then it is split and + each filetype is checked. + """ ret = [] filetypes = self._filetypes(dotft) From b54300a82ed8b51b1dfda14fed9dfe7c9149f70c Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 15:51:04 -0300 Subject: [PATCH 4/6] added documentation for new search --- doc/UltiSnips.txt | 25 +++++++++++++++++-------- plugin/UltiSnips/__init__.py | 4 ++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/doc/UltiSnips.txt b/doc/UltiSnips.txt index 9a99a38..4ebe29f 100644 --- a/doc/UltiSnips.txt +++ b/doc/UltiSnips.txt @@ -121,17 +121,24 @@ To Update an installation, simply pull the latest revision: > 3.1 Commands *UltiSnips-commands* ------------ -UltiSnips defines two Commands, the first one is UltiSnipsReset, which will + *:UltiSnipsReset* +UltiSnips defines two commands, the first one is UltiSnipsReset, which will reload the snippets definitions and is useful while you are tweaking a snippet. -UltiSnipsEdit is the second one. It opens your private snippet definition file -for the current filetype. You can easily open them manually of course, this is -just a shortcut. There is also a variable called: > + *:UltiSnipsEdit* +The second command is UltiSnipsEdit. It opens or creates your private snippet +definition file for the current filetype. You can easily open them manually of +course, this is just a shortcut. There is also a variable called: > g:UltiSnipsEditSplit - which can be set to "normal" (default), "horizontal" or "vertical" that -defines if a new window should be opened for the edit. +defines if a new window should be opened for the edit. There is also a +variable called: > + g:UltiSnipsSnippetsDir +that, when set to a directory like "~/.vim/mydir/UltiSnips", becomes the base +directory for the snippet file to open. For example, if it is set to +"~/.vim/mydir/UltiSnips" and the current 'filetype' is "cpp", then +:UltiSnipsEdit will open "~/.vim/mydir/UltiSnips/cpp.snippets". 3.2 Triggers *UltiSnips-triggers* ------------ @@ -237,9 +244,11 @@ See |UltiSnips-snippet-search-path| for an explanation of where directories with snippet definitions are expected. While iterating over the snippet definition directories found, files are -looked for called ft.snippets, for example: > +looked for called ft.snippets or *_ft.snippets where "ft" is the current +'filetype', and the "*" matches anything, for example: > ruby.snippets c.snippets + my_c.snippets perl.snippets These files contain the snippet definitions for the various file types. A special file is > @@ -248,7 +257,7 @@ which contains snippets that are always expanded, no matter what file type is defined. For example, I keep mail signatures and date insertion snippets here. The dotted file type syntax of vim is supported. For example, for my cpp or -CUDA files, i keep the file type set to ":set ft=cpp.c" or ":set +CUDA files, I keep the file type set to ":set ft=cpp.c" or ":set ft=cuda.cpp.c". This activates all snippets for each file type in the order specified. diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index a280a5f..aaf75da 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -1084,7 +1084,7 @@ class SnippetManager(object): for snippet_dir in snippet_dirs: pth = os.path.realpath(os.path.join(rtp, snippet_dir)) - patterns = ["%s.snippets", "*_%s.snippets"] # TODO: doc this + patterns = ["%s.snippets", "*_%s.snippets"] if not default and pth == base_snippets: patterns.remove("%s.snippets") @@ -1122,7 +1122,7 @@ class SnippetManager(object): existing = self.base_snippet_files_for(ft, False) filename = ft + ".snippets" - if vim.eval("exists('g:UltiSnipsSnippetsDir')") == 1: # TODO: doc this + if vim.eval("exists('g:UltiSnipsSnippetsDir')") == 1: snipdir = vim.eval("g:UltiSnipsSnippetsDir") edit = os.path.join(snipdir, filename) elif existing: From fe896cffb36aa238193f4835e93cdd8b65bb7afc Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 15:58:42 -0300 Subject: [PATCH 5/6] fixed return for method - tests all pass now --- plugin/UltiSnips/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index aaf75da..f904528 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -870,7 +870,9 @@ class SnippetManager(object): feedkeys(feedkey, mode) def _ensure_snippets_loaded(self): - for ft in self._filetypes(): + filetypes = self._filetypes() + + for ft in filetypes: if ft not in self._snippets: self._load_snippets_for(ft) From 424b817338803ba67d01037ee30b3d08d225e4ef Mon Sep 17 00:00:00 2001 From: "rygwdn@gmail.com" <> Date: Wed, 27 Apr 2011 16:09:33 -0300 Subject: [PATCH 6/6] look through filetypes in the right order --- plugin/UltiSnips/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index f904528..4bbc25d 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -899,7 +899,7 @@ class SnippetManager(object): filetypes = self._ensure_snippets_loaded() found_snippets = [] - for ft in filetypes[::-1]: + for ft in filetypes: found_snippets += self._find_snippets(ft, before, possible) # Search if any of the snippets overwrites the previous