From bfce5af6420ea4a9a70ec61039b4b8eef58633f0 Mon Sep 17 00:00:00 2001 From: Holger Rapp Date: Sun, 1 Apr 2012 16:42:34 +0200 Subject: [PATCH] Implemented UltiSnipsAddFiletypes It makes it possible to add filetypes in ftplugin/ft.vim or manually while editing. --- doc/UltiSnips.txt | 23 ++++++++++ ftdetect/UltiSnips.vim | 6 +++ plugin/UltiSnips.vim | 14 +++++- plugin/UltiSnips/__init__.py | 84 +++++++++++++++++------------------- plugin/UltiSnips/_vim.py | 4 ++ 5 files changed, 84 insertions(+), 47 deletions(-) create mode 100644 ftdetect/UltiSnips.vim diff --git a/doc/UltiSnips.txt b/doc/UltiSnips.txt index d14cdc5..0898f64 100644 --- a/doc/UltiSnips.txt +++ b/doc/UltiSnips.txt @@ -179,6 +179,29 @@ g:UltiSnipsSnippetsDir 'filetype' is "cpp", then :UltiSnipsEdit will open "~/.vim/mydir/UltiSnips/cpp.snippets". + *:UltiSnipsAddFiletypes* +The UltiSnipsAddFiletypes command allows for explicit merging of other snippet +filetypes for the current buffer. For example if you edit a .rst file, but +also want the Lua snippets to be available you can issue the command > + + :UltiSnipsAddFiletypes rst.lua + +using the dotted filetype syntax. Order is important, the first filetype in +this list will be the one used for UltiSnipsEdit and the list is +ordered by evaluation priority. Consequently, you might add this to your +ftplugin/rails.vim > + + :UltiSnipsAddFiletypes rails.ruby + +I mention rails first, because I want to edit rails snippet when using +UltiSnipsEdit and because rails snippet should overwrite equivalent ruby +snippets. The priority will now be rails -> ruby -> all. If you have some +special programming snippets that should have lower priority than your ruby +snippets you can call > + + :UltiSnipsAddFiletypes ruby.programming + +The priority will then be rails -> ruby -> programming -> all. 3.2 Triggers *UltiSnips-triggers* ------------ diff --git a/ftdetect/UltiSnips.vim b/ftdetect/UltiSnips.vim new file mode 100644 index 0000000..e307ff7 --- /dev/null +++ b/ftdetect/UltiSnips.vim @@ -0,0 +1,6 @@ +" This has to be called before ftplugins are loaded. Therefore +" it is here in ftdetect though it maybe shouldn't +if has("autocmd") + autocmd FileType * call UltiSnips_FileTypeChanged() +endif + diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index 433e45d..2cbfb74 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -82,7 +82,7 @@ function! UltiSnipsEdit(...) if a:0 == 1 && a:1 != '' let type = a:1 else - exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager.filetype)" + exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager.primary_filetype)" endif exec g:_uspy "vim.command(\"let file = '%s'\" % UltiSnips_Manager.file_to_edit(vim.eval(\"type\")))" @@ -99,6 +99,14 @@ endfunction " edit snippets, default of current file type or the specified type command! -nargs=? UltiSnipsEdit :call UltiSnipsEdit() + +" Global Commands {{{ +function! UltiSnipsAddFiletypes(filetypes) + exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . a:filetypes . ".all')" + return "" +endfunction +command! -nargs=1 UltiSnipsAddFiletypes :call UltiSnipsAddFiletypes() + "" }}} " FUNCTIONS {{{ @@ -145,7 +153,8 @@ function! UltiSnips_JumpForwards() endfunction function! UltiSnips_FileTypeChanged() - exec g:_uspy "UltiSnips_Manager.ensure_snippets_loaded()" + exec g:_uspy "UltiSnips_Manager.reset_buffer_filetypes()" + exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . &ft . "')" return "" endfunction @@ -173,6 +182,7 @@ 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 diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index 274fe74..b2ea90a 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -2,7 +2,7 @@ # encoding: utf-8 from functools import wraps -from collections import deque +from collections import deque, defaultdict import glob import hashlib import os @@ -55,9 +55,9 @@ class _SnippetDictionary(object): else: return [ s for s in self.snippets if s.could_match(trigger) ] + @property def snippets(self): return self._added + self._snippets - snippets = property(snippets) def clear_snippets(self, triggers=[]): """Remove all snippets that match each trigger in triggers. @@ -74,9 +74,9 @@ class _SnippetDictionary(object): self._snippets = [] self._added = [] + @property def files(self): return self._files - files = property(files) def reset(self): self._snippets = [] @@ -374,22 +374,22 @@ class Snippet(object): return match + @property def overwrites_previous(self): return "!" in self._opts - overwrites_previous = property(overwrites_previous) + @property def description(self): return ("(%s) %s" % (self._t, self._d)).strip() - description = property(description) + @property def trigger(self): return self._t - trigger = property(trigger) + @property def matched(self): """ The last text that was matched. """ return self._matched - matched = property(matched) def launch(self, text_before, visual_content, parent, start, end): indent = self._INDENT.match(text_before).group(0) @@ -516,6 +516,7 @@ class SnippetManager(object): self._vstate = VimState() self._test_error = test_error self._snippets = {} + self._filetypes = defaultdict(lambda: ['all']) self._visual_content = VisualContentPreserver() while len(self._csnippets): @@ -780,7 +781,8 @@ class SnippetManager(object): before the cursor. If possible is True, then get all possible matches. """ - filetypes = self.ensure_snippets_loaded() + self._ensure_all_loaded() + filetypes = self._filetypes[_vim.buf.nr][::-1] found_snippets = [] for ft in filetypes: @@ -869,11 +871,11 @@ class SnippetManager(object): return True + @property def _cs(self): if not len(self._csnippets): return None return self._csnippets[-1] - _cs = property(_cs) def _parse_snippets(self, ft, fn, file_data=None): self.add_snippet_file(ft, fn) @@ -915,19 +917,15 @@ class SnippetManager(object): return ret - def _filetypes(self, dotft=None): - if dotft is None: - dotft = _vim.eval("&filetype") + @property + def primary_filetype(self): + """ Property for the primary filetype. This filetype + will be edited when UltiSnipsEdit is called + without any arguments. + """ + return self._filetypes[_vim.buf.nr][0] - fts = dotft.split(".") + [ "all" ] - 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): + def file_to_edit(self, ft): """ Gets a file to edit based on the given filetype. If no filetype is given, uses the current filetype from Vim. @@ -935,9 +933,6 @@ class SnippetManager(object): If a non-shipped file already exists, it uses it. Otherwise uses a file in ~/.vim/ or ~/vimfiles """ - if not ft: - ft = self.filetype - edit = None existing = self.base_snippet_files_for(ft, False) filename = ft + ".snippets" @@ -966,21 +961,6 @@ class SnippetManager(object): return edit - - 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) - - for ft in filetypes: - ret += self.base_snippet_files_for(ft) - - return ret - # Loading def _load_snippets_for(self, ft): self.snippet_dict(ft).reset() @@ -1027,16 +1007,30 @@ class SnippetManager(object): self._ensure_loaded(parent, checked) - def ensure_snippets_loaded(self): + def _ensure_all_loaded(self): + for ft in self._filetypes[_vim.buf.nr]: + self._ensure_loaded(ft) + + def reset_buffer_filetypes(self): + if _vim.buf.nr in self._filetypes: + del self._filetypes[_vim.buf.nr] + + def add_buffer_filetypes(self, ft): """ Checks for changes in the list of snippet files or the contents of the snippet files and reloads them if necessary. """ - filetypes = self._filetypes() + buf_fts = self._filetypes[_vim.buf.nr] + idx = -1 + for ft in ft.split("."): + ft = ft.strip() + if not ft: continue + try: + idx = buf_fts.index(ft) + except ValueError: + self._filetypes[_vim.buf.nr].insert(idx + 1, ft) + idx += 1 - for ft in filetypes: - self._ensure_loaded(ft) - - return filetypes + self._ensure_all_loaded() def _find_snippets(self, ft, trigger, potentially = False, seen=None): """ diff --git a/plugin/UltiSnips/_vim.py b/plugin/UltiSnips/_vim.py index 2b57d3c..b2e9a3f 100755 --- a/plugin/UltiSnips/_vim.py +++ b/plugin/UltiSnips/_vim.py @@ -41,6 +41,10 @@ class VimBuffer(object): before, after = as_unicode(line[:col]), as_unicode(line[col:]) return before, after + @property + def nr(self): + return int(eval("bufnr('%')")) + def cursor(): """ The current windows cursor. Note that this is 0 based in col and 0