Example #1
0
    def __init__(self, expand_trigger, forward_trigger, backward_trigger):
        self.expand_trigger = expand_trigger
        self.forward_trigger = forward_trigger
        self.backward_trigger = backward_trigger
        self._inner_state_up = False
        self._supertab_keys = None

        self._active_snippets = []
        self._added_buffer_filetypes = defaultdict(lambda: [])

        self._vstate = VimState()
        self._visual_content = VisualContentPreserver()

        self._snippet_sources = []

        self._snip_expanded_in_action = False
        self._inside_action = False

        self._last_change = ("", 0)

        self._added_snippets_source = AddedSnippetsSource()
        self.register_snippet_source("ultisnips_files", UltiSnipsFileSource())
        self.register_snippet_source("added", self._added_snippets_source)

        enable_snipmate = "1"
        if vim_helper.eval("exists('g:UltiSnipsEnableSnipMate')") == "1":
            enable_snipmate = vim_helper.eval("g:UltiSnipsEnableSnipMate")
        if enable_snipmate == "1":
            self.register_snippet_source("snipmate_files", SnipMateFileSource())

        self._should_update_textobjects = False
        self._should_reset_visual = False

        self._reinit()
Example #2
0
    def _handle_failure(self, trigger):
        """Mainly make sure that we play well with SuperTab."""
        if trigger.lower() == "<tab>":
            feedkey = "\\" + trigger
        elif trigger.lower() == "<s-tab>":
            feedkey = "\\" + trigger
        else:
            feedkey = None
        mode = "n"
        if not self._supertab_keys:
            if vim_helper.eval("exists('g:SuperTabMappingForward')") != "0":
                self._supertab_keys = (
                    vim_helper.eval("g:SuperTabMappingForward"),
                    vim_helper.eval("g:SuperTabMappingBackward"),
                )
            else:
                self._supertab_keys = ["", ""]

        for idx, sttrig in enumerate(self._supertab_keys):
            if trigger.lower() == sttrig.lower():
                if idx == 0:
                    feedkey = r"\<Plug>SuperTabForward"
                    mode = "n"
                elif idx == 1:
                    feedkey = r"\<Plug>SuperTabBackward"
                    mode = "p"
                # Use remap mode so SuperTab mappings will be invoked.
                break

        if feedkey in (r"\<Plug>SuperTabForward", r"\<Plug>SuperTabBackward"):
            vim_helper.command("return SuperTab(%s)" % vim_helper.escape(mode))
        elif feedkey:
            vim_helper.command("return %s" % vim_helper.escape(feedkey))
Example #3
0
def find_all_snippet_directories() -> List[str]:
    """Returns a list of the absolute path of all potential snippet
    directories, no matter if they exist or not."""

    if vim_helper.eval("exists('b:UltiSnipsSnippetDirectories')") == "1":
        snippet_dirs = vim_helper.eval("b:UltiSnipsSnippetDirectories")
    else:
        snippet_dirs = vim_helper.eval("g:UltiSnipsSnippetDirectories")

    if len(snippet_dirs) == 1:
        # To reduce confusion and increase consistency with
        # `UltiSnipsSnippetsDir`, we expand ~ here too.
        full_path = os.path.expanduser(snippet_dirs[0])
        if os.path.isabs(full_path):
            return [full_path]

    all_dirs = []
    check_dirs = vim_helper.eval("&runtimepath").split(",")
    for rtp in check_dirs:
        for snippet_dir in snippet_dirs:
            if snippet_dir == "snippets":
                raise PebkacError(
                    "You have 'snippets' in UltiSnipsSnippetDirectories. This "
                    "directory is reserved for snipMate snippets. Use another "
                    "directory for UltiSnips snippets.")
            pth = normalize_file_path(
                os.path.expanduser(os.path.join(rtp, snippet_dir)))
            # Runtimepath entries may contain wildcards.
            all_dirs.extend(glob.glob(pth))
    return all_dirs
Example #4
0
 def reset(self):
     """Gets the spacing properties from Vim."""
     self.shiftwidth = int(
         vim_helper.eval(
             "exists('*shiftwidth') ? shiftwidth() : &shiftwidth"))
     self._expandtab = vim_helper.eval("&expandtab") == "1"
     self._tabstop = int(vim_helper.eval("&tabstop"))
Example #5
0
def _find_all_snippet_directories():
    """Returns a list of the absolute path of all snippet directories to
    search."""

    if vim_helper.eval("exists('b:UltiSnipsSnippetDirectories')") == "1":
        snippet_dirs = vim_helper.eval("b:UltiSnipsSnippetDirectories")
    else:
        snippet_dirs = vim_helper.eval("g:UltiSnipsSnippetDirectories")

    if len(snippet_dirs) == 1:
        # To reduce confusion and increase consistency with
        # `UltiSnipsSnippetsDir`, we expand ~ here too.
        full_path = os.path.expanduser(snippet_dirs[0])
        if os.path.isabs(full_path):
            return [full_path]

    all_dirs = []
    check_dirs = vim_helper.eval("&runtimepath").split(",")
    for rtp in check_dirs:
        for snippet_dir in snippet_dirs:
            if snippet_dir == "snippets":
                raise RuntimeError(
                    "You have 'snippets' in UltiSnipsSnippetDirectories. This "
                    "directory is reserved for snipMate snippets. Use another "
                    "directory for UltiSnips snippets."
                )
            pth = os.path.realpath(os.path.expanduser(os.path.join(rtp, snippet_dir)))
            if os.path.isdir(pth):
                all_dirs.append(pth)
    return all_dirs
Example #6
0
 def opt(self, option, default=None):  # pylint:disable=no-self-use
     """Gets a Vim variable."""
     if vim_helper.eval("exists('%s')" % option) == "1":
         try:
             return vim_helper.eval(option)
         except vim_helper.error:
             pass
     return default
Example #7
0
    def _file_to_edit(self, requested_ft, bang):
        """Returns a file to be edited for the given requested_ft.

        If 'bang' is empty a reasonable first choice is opened (see docs), otherwise
        all files are considered and the user gets to choose.
        """
        filetypes = []
        if requested_ft:
            filetypes.append(requested_ft)
        else:
            if bang:
                filetypes.extend(self.get_buffer_filetypes())
            else:
                filetypes.append(self.get_buffer_filetypes()[0])

        potentials = set()

        all_snippet_directories = find_all_snippet_directories()
        has_storage_dir = (vim_helper.eval(
            "exists('g:UltiSnipsSnippetStorageDirectoryForUltiSnipsEdit')") ==
                           "1")
        if has_storage_dir:
            snippet_storage_dir = vim_helper.eval(
                "g:UltiSnipsSnippetStorageDirectoryForUltiSnipsEdit")
            full_path = os.path.expanduser(snippet_storage_dir)
            potentials.update(
                _get_potential_snippet_filenames_to_edit(full_path, filetypes))
        if len(all_snippet_directories) == 1:
            # Most likely the user has set g:UltiSnipsSnippetDirectories to a
            # single absolute path.
            potentials.update(
                _get_potential_snippet_filenames_to_edit(
                    all_snippet_directories[0], filetypes))

        if (len(all_snippet_directories) != 1
                and not has_storage_dir) or (has_storage_dir and bang):
            # Likely the array contains things like ["UltiSnips",
            # "mycoolsnippets"] There is no more obvious way to edit than in
            # the users vim config directory.
            dot_vim_dir = vim_helper.get_dot_vim()
            for snippet_dir in all_snippet_directories:
                if Path(dot_vim_dir) != Path(snippet_dir).parent:
                    continue
                potentials.update(
                    _get_potential_snippet_filenames_to_edit(
                        snippet_dir, filetypes))

        if bang:
            for ft in filetypes:
                potentials.update(find_all_snippet_files(ft))
        else:
            if not potentials:
                _show_user_warning(
                    "UltiSnips was not able to find a default directory for snippets. "
                    "Do you have a .vim directory? Try :UltiSnipsEdit! instead of :UltiSnipsEdit."
                )
                return ""
        return _select_and_create_file_to_edit(potentials)
Example #8
0
    def _update(self, done, buf):
        regex = 'indent\([\'"]\.[\'"]\)'
        # don't update current line for express 'indent(".")'
        if not self._replaced and re.match(regex, self._code):
            line = vim_helper.eval('line(".")')
            self._code = re.sub(regex, 'indent("' + line + '")', self._code)
            self._replaced = line

        self.overwrite(buf, vim_helper.eval(self._code))
        return True
Example #9
0
    def _track_change(self):
        self._should_update_textobjects = True

        try:
            inserted_char = vim_helper.eval("v:char")
        except UnicodeDecodeError:
            return

        if isinstance(inserted_char, bytes):
            return

        try:
            if inserted_char == "":
                before = vim_helper.buf.line_till_cursor

                if (before and self._last_change[0] != ""
                        and before[-1] == self._last_change[0]):
                    self._try_expand(autotrigger_only=True)
        finally:
            self._last_change = (inserted_char, vim_helper.buf.cursor)

        if self._should_reset_visual and self._visual_content.mode == "":
            self._visual_content.reset()

        self._should_reset_visual = True
Example #10
0
    def _track_change(self):
        self._should_update_textobjects = True

        try:
            inserted_char = vim_helper.as_unicode(vim_helper.eval("v:char"))
        except UnicodeDecodeError:
            return

        if sys.version_info >= (3, 0):
            if isinstance(inserted_char, bytes):
                return
        else:
            if not isinstance(inserted_char, unicode):
                return

        try:
            if inserted_char == "":
                before = vim_helper.buf.line_till_cursor

                if (
                    before
                    and before[-1] == self._last_change[0]
                    or self._last_change[1] != vim.current.window.cursor[0]
                ):
                    self._try_expand(autotrigger_only=True)
        finally:
            self._last_change = (inserted_char, vim.current.window.cursor[0])

        if self._should_reset_visual and self._visual_content.mode == "":
            self._visual_content.reset()

        self._should_reset_visual = True
Example #11
0
 def _parse_snippets(self, ft, filename):
     """Parse the 'filename' for the given 'ft'."""
     with open(filename, "r", encoding="utf-8-sig") as to_read:
         file_data = to_read.read()
     self._snippets[ft]  # Make sure the dictionary exists
     for event, data in self._parse_snippet_file(file_data, filename):
         if event == "error":
             msg, line_index = data
             filename = vim_helper.eval(
                 """fnamemodify(%s, ":~:.")""" % vim_helper.escape(filename)
             )
             raise SnippetSyntaxError(filename, line_index, msg)
         elif event == "clearsnippets":
             priority, triggers = data
             self._snippets[ft].clear_snippets(priority, triggers)
         elif event == "extends":
             # TODO(sirver): extends information is more global
             # than one snippet source.
             (filetypes,) = data
             self.update_extends(ft, filetypes)
         elif event == "snippet":
             (snippet,) = data
             self._snippets[ft].add_snippet(snippet)
         else:
             assert False, "Unhandled %s: %r" % (event, data)
Example #12
0
    def _teardown_inner_state(self):
        """Reverse _setup_inner_state."""
        if not self._inner_state_up:
            return
        try:
            vim_helper.command(
                "silent doautocmd <nomodeline> User UltiSnipsExitLastSnippet")
            if self.expand_trigger != self.forward_trigger:
                vim_helper.command("iunmap <buffer> %s" % self.forward_trigger)
                vim_helper.command("sunmap <buffer> %s" % self.forward_trigger)
            vim_helper.command("iunmap <buffer> %s" % self.backward_trigger)
            vim_helper.command("sunmap <buffer> %s" % self.backward_trigger)
            vim_helper.command("augroup UltiSnips")
            vim_helper.command("autocmd!")
            vim_helper.command("augroup END")

            if vim_helper.eval(
                    'g:UltiSnipsDisablePreviewWindowInSnips') == '1':
                # restore completeopt
                vim_helper.command(
                    'let &completeopt = g:ultisnips_completopt_old')

        except vim_helper.error:
            # This happens when a preview window was opened. This issues
            # CursorMoved, but not BufLeave. We have no way to unmap, until we
            # are back in our buffer
            pass
        finally:
            self._inner_state_up = False
Example #13
0
    def _update(self, done, buf):
        path = vim_helper.eval('expand("%")') or ""
        ct = self.current_text
        self._locals.update({
            "t": _Tabs(self._parent),
            "fn": os.path.basename(path),
            "path": path,
            "cur": ct,
            "res": ct,
            "snip": self._snip,
        })
        self._snip._reset(ct)  # pylint:disable=protected-access

        for code in self._codes:
            try:
                exec(code, self._locals)  # pylint:disable=exec-used
            except Exception as exception:
                exception.snippet_code = code
                raise

        rv = str(
            self._snip.rv if self._snip._rv_changed else self._locals["res"])  # pylint:disable=protected-access

        if ct != rv:
            self.overwrite(buf, rv)
            return False
        return True
Example #14
0
    def conserve(self):
        """Save the last visual selection and the mode it was made in."""
        sl, sbyte = map(int, (vim_helper.eval("""line("'<")"""),
                              vim_helper.eval("""col("'<")""")))
        el, ebyte = map(int, (vim_helper.eval("""line("'>")"""),
                              vim_helper.eval("""col("'>")""")))
        sc = byte2col(sl, sbyte - 1)
        ec = byte2col(el, ebyte - 1)
        self._mode = vim_helper.eval("visualmode()")

        # When 'selection' is 'exclusive', the > mark is one column behind the
        # actual content being copied, but never before the < mark.
        if vim_helper.eval("&selection") == "exclusive":
            if not (sl == el and sbyte == ebyte):
                ec -= 1

        _vim_line_with_eol = lambda ln: vim_helper.buf[ln] + "\n"

        if sl == el:
            text = _vim_line_with_eol(sl - 1)[sc:ec + 1]
        else:
            text = _vim_line_with_eol(sl - 1)[sc:]
            for cl in range(sl, el - 1):
                text += _vim_line_with_eol(cl)
            text += _vim_line_with_eol(el - 1)[:ec + 1]
        self._text = text
Example #15
0
    def matches(self, before, visual_content=None):
        """Returns True if this snippet matches 'before'."""
        # If user supplies both "w" and "i", it should perhaps be an
        # error, but if permitted it seems that "w" should take precedence
        # (since matching at word boundary and within a word == matching at word
        # boundary).
        self._matched = ""

        words = _words_for_line(self._trigger, before)

        if "r" in self._opts:
            try:
                match = self._re_match(before)
            except Exception as e:
                self._make_debug_exception(e)
                raise

        elif "w" in self._opts:
            words_len = len(self._trigger)
            words_prefix = words[:-words_len]
            words_suffix = words[-words_len:]
            match = words_suffix == self._trigger
            if match and words_prefix:
                # Require a word boundary between prefix and suffix.
                boundary_chars = escape(words_prefix[-1:] + words_suffix[:1],
                                        r"\"")
                match = vim_helper.eval(
                    '"%s" =~# "\\\\v.<."' % boundary_chars) != "0"
        elif "i" in self._opts:
            match = words.endswith(self._trigger)
        else:
            match = words == self._trigger

        # By default, we match the whole trigger
        if match and not self._matched:
            self._matched = self._trigger

        # Ensure the match was on a word boundry if needed
        if "b" in self._opts and match:
            text_before = before.rstrip()[:-len(self._matched)]
            if text_before.strip(" \t") != "":
                self._matched = ""
                return False

        self._context = None
        if match and self._context_code:
            self._context = self._context_match(visual_content)
            if not self.context:
                match = False

        return match
Example #16
0
    def _setup_inner_state(self):
        """Map keys and create autocommands that should only be defined when a
        snippet is active."""
        if self._inner_state_up:
            return
        if self.expand_trigger != self.forward_trigger:
            vim_helper.command("inoremap <buffer><nowait><silent> " +
                               self.forward_trigger +
                               " <C-R>=UltiSnips#JumpForwards()<cr>")
            vim_helper.command("snoremap <buffer><nowait><silent> " +
                               self.forward_trigger +
                               " <Esc>:call UltiSnips#JumpForwards()<cr>")
        vim_helper.command("inoremap <buffer><nowait><silent> " +
                           self.backward_trigger +
                           " <C-R>=UltiSnips#JumpBackwards()<cr>")
        vim_helper.command("snoremap <buffer><nowait><silent> " +
                           self.backward_trigger +
                           " <Esc>:call UltiSnips#JumpBackwards()<cr>")

        if vim_helper.eval('g:UltiSnipsDisablePreviewWindowInSnips') == '1':
            # backup completeopt
            vim_helper.command('let g:ultisnips_completopt_old = &completeopt')
            # and remove the preview option
            vim_helper.command('set completeopt-=preview')

        # Setup the autogroups.
        vim_helper.command("augroup UltiSnips")
        vim_helper.command("autocmd!")
        vim_helper.command(
            "autocmd CursorMovedI * call UltiSnips#CursorMoved()")
        vim_helper.command(
            "autocmd CursorMoved * call UltiSnips#CursorMoved()")

        vim_helper.command(
            "autocmd InsertLeave * call UltiSnips#LeavingInsertMode()")

        vim_helper.command("autocmd BufEnter * call UltiSnips#LeavingBuffer()")
        vim_helper.command(
            "autocmd CmdwinEnter * call UltiSnips#LeavingBuffer()")
        vim_helper.command(
            "autocmd CmdwinLeave * call UltiSnips#LeavingBuffer()")

        # Also exit the snippet when we enter a unite complete buffer.
        vim_helper.command(
            "autocmd Filetype unite call UltiSnips#LeavingBuffer()")

        vim_helper.command("augroup END")

        vim_helper.command(
            "silent doautocmd <nomodeline> User UltiSnipsEnterFirstSnippet")
        self._inner_state_up = True
Example #17
0
    def _file_to_edit(self, requested_ft, bang):
        """Returns a file to be edited for the given requested_ft.

        If 'bang' is
        empty only private files in g:UltiSnipsSnippetsDir are considered,
        otherwise all files are considered and the user gets to choose.
        """
        snippet_dir = ""
        if vim_helper.eval("exists('g:UltiSnipsSnippetsDir')") == "1":
            dir = vim_helper.eval("g:UltiSnipsSnippetsDir")
            file = self._get_file_to_edit(dir, requested_ft, bang)
            if file:
                return file
            snippet_dir = dir

        if vim_helper.eval("exists('g:UltiSnipsSnippetDirectories')") == "1":
            dirs = vim_helper.eval("g:UltiSnipsSnippetDirectories")
            for dir in dirs:
                file = self._get_file_to_edit(dir, requested_ft, bang)
                if file:
                    return file
                if not snippet_dir:
                    snippet_dir = dir

        home = vim_helper.eval("$HOME")
        if platform.system() == "Windows":
            dir = os.path.join(home, "vimfiles", "UltiSnips")
            file = self._get_file_to_edit(dir, requested_ft, bang)
            if file:
                return file
            if not snippet_dir:
                snippet_dir = dir

        if vim_helper.eval("has('nvim')") == "1":
            xdg_home_config = vim_helper.eval("$XDG_CONFIG_HOME") or os.path.join(
                home, ".config"
            )
            dir = os.path.join(xdg_home_config, "nvim", "UltiSnips")
            file = self._get_file_to_edit(dir, requested_ft, bang)
            if file:
                return file
            if not snippet_dir:
                snippet_dir = dir

        dir = os.path.join(home, ".vim", "UltiSnips")
        file = self._get_file_to_edit(dir, requested_ft, bang)
        if file:
            return file
        if not snippet_dir:
            snippet_dir = dir

        return self._get_file_to_edit(snippet_dir, requested_ft, bang, True)
Example #18
0
    def remember_unnamed_register(self, text_to_expect):
        """Save the unnamed register.

        'text_to_expect' is text that we expect
        to be contained in the register the next time this method is called -
        this could be text from the tabstop that was selected and might have
        been overwritten. We will not cache that then.

        """
        self._unnamed_reg_cached = True
        escaped_text = self._text_to_expect.replace("'", "''")
        res = int(vim_helper.eval('@" != ' + "'" + escaped_text + "'"))
        if res:
            vim_helper.command('let g:_ultisnips_unnamed_reg_cache = @"')
        self._text_to_expect = text_to_expect
Example #19
0
def _snipmate_files_for(ft):
    """Returns all snipMate files we need to look at for 'ft'."""
    if ft == "all":
        ft = "_"
    patterns = [
        "%s.snippets" % ft,
        os.path.join(ft, "*.snippets"),
        os.path.join(ft, "*.snippet"),
        os.path.join(ft, "*/*.snippet"),
    ]

    ret = set()
    if vim_helper.eval("exists('g:UltiSnipsSnipMateAbsDirectories')") == '1':
        # specify the snipmate snippets by handle with absolute path
        paths = vim_helper.eval('g:UltiSnipsSnipMateAbsDirectories')
    else:
        paths = vim_helper.eval('&runtimepath').split(',')
    for rtp in paths:
        path = normalize_file_path(
            os.path.expanduser(os.path.join(rtp, "snippets")))
        for pattern in patterns:
            for fn in glob.glob(os.path.join(path, pattern)):
                ret.add(fn)
    return ret
Example #20
0
    def could_match(self, before):
        """Return True if this snippet could match the (partial) 'before'."""
        self._matched = ""

        # List all on whitespace.
        if before and before[-1] in (" ", "\t"):
            before = ""
        if before and before.rstrip() is not before:
            return False

        words = _words_for_line(self._trigger, before)

        if "r" in self._opts:
            # Test for full match only
            match = self._re_match(before)
        elif "w" in self._opts:
            # Trim non-empty prefix up to word boundary, if present.
            qwords = escape(words, r"\"")
            words_suffix = vim_helper.eval(
                'substitute("%s", "\\\\v^.+<(.+)", "\\\\1", "")' % qwords
            )
            match = self._trigger.startswith(words_suffix)
            self._matched = words_suffix

            # TODO: list_snippets() function cannot handle partial-trigger
            # matches yet, so for now fail if we trimmed the prefix.
            if words_suffix != words:
                match = False
        elif "i" in self._opts:
            # TODO: It is hard to define when a inword snippet could match,
            # therefore we check only for full-word trigger.
            match = self._trigger.startswith(words)
        else:
            match = self._trigger.startswith(words)

        # By default, we match the words from the trigger
        if match and not self._matched:
            self._matched = words

        # Ensure the match was on a word boundry if needed
        if "b" in self._opts and match:
            text_before = before.rstrip()[: -len(self._matched)]
            if text_before.strip(" \t") != "":
                self._matched = ""
                return False

        return match
Example #21
0
def _snipmate_files_for(ft):
    """Returns all snipMate files we need to look at for 'ft'."""
    if ft == "all":
        ft = "_"
    patterns = [
        "%s.snippets" % ft,
        os.path.join(ft, "*.snippets"),
        os.path.join(ft, "*.snippet"),
        os.path.join(ft, "*/*.snippet"),
    ]
    ret = set()
    for rtp in vim_helper.eval("&runtimepath").split(","):
        path = os.path.expanduser(os.path.join(rtp, "snippets"))
        for pattern in patterns:
            for fn in glob.glob(os.path.join(path, pattern)):
                ret.add(fn)
    return ret
Example #22
0
def _ask_user(a, formatted):
    """Asks the user using inputlist() and returns the selected element or
    None."""
    try:
        rv = vim_helper.eval("inputlist(%s)" % vim_helper.escape(formatted))
        if rv is None or rv == "0":
            return None
        rv = int(rv)
        if rv > len(a):
            rv = len(a)
        return a[rv - 1]
    except vim_helper.error:
        # Likely "invalid expression", but might be translated. We have no way
        # of knowing the exact error, therefore, we ignore all errors silently.
        return None
    except KeyboardInterrupt:
        return None
Example #23
0
 def __init__(self):
     pos = vim_helper.buf.cursor
     self._mode = vim_helper.eval("mode()")
     Position.__init__(self, pos.line, pos.col)
Example #24
0
 def is_blocking():
     return bool(int(vim_helper.eval("g:UltiSnipsPMDebugBlocking")))
Example #25
0
 def is_enable():
     return bool(int(vim_helper.eval("g:UltiSnipsDebugServerEnable")))
Example #26
0
 def get_host_port(host=None, port=None):
     if host is None:
         host = vim_helper.eval("g:UltiSnipsDebugHost")
     if port is None:
         port = int(vim_helper.eval("g:UltiSnipsDebugPort"))
     return host, port
Example #27
0
def guess_edit(initial_line, last_text, current_text, vim_state):
    """Try to guess what the user might have done by heuristically looking at
    cursor movement, number of changed lines and if they got longer or shorter.
    This will detect most simple movements like insertion, deletion of a line
    or carriage return. 'initial_text' is the index of where the comparison
    starts, 'last_text' is the last text of the snippet, 'current_text' is the
    current text of the snippet and 'vim_state' is the cached vim state.

    Returns (True, edit_cmds) when the edit could be guessed, (False,
    None) otherwise.

    """
    if not len(last_text) and not len(current_text):
        return True, ()
    pos = vim_state.pos
    ppos = vim_state.ppos

    # All text deleted?
    if len(last_text) and (not current_text or
                           (len(current_text) == 1 and not current_text[0])):
        es = []
        if not current_text:
            current_text = [""]
        for i in last_text:
            es.append(("D", initial_line, 0, i))
            es.append(("D", initial_line, 0, "\n"))
        es.pop()  # Remove final \n because it is not really removed
        if is_complete_edit(initial_line, last_text, current_text, es):
            return True, es
    if ppos.mode == "v":  # Maybe selectmode?
        sv = list(map(int, vim_helper.eval("""getpos("'<")""")))
        sv = Position(sv[1] - 1, sv[2] - 1)
        ev = list(map(int, vim_helper.eval("""getpos("'>")""")))
        ev = Position(ev[1] - 1, ev[2] - 1)
        if "exclusive" in vim_helper.eval("&selection"):
            ppos.col -= 1  # We want to be inclusive, sorry.
            ev.col -= 1
        es = []
        if sv.line == ev.line:
            es.append((
                "D",
                sv.line,
                sv.col,
                last_text[sv.line - initial_line][sv.col:ev.col + 1],
            ))
            if sv != pos and sv.line == pos.line:
                es.append((
                    "I",
                    sv.line,
                    sv.col,
                    current_text[sv.line - initial_line][sv.col:pos.col + 1],
                ))
        if is_complete_edit(initial_line, last_text, current_text, es):
            return True, es
    if pos.line == ppos.line:
        if len(last_text) == len(current_text):  # Movement only in one line
            llen = len(last_text[ppos.line - initial_line])
            clen = len(current_text[pos.line - initial_line])
            if ppos < pos and clen > llen:  # maybe only chars have been added
                es = ((
                    "I",
                    ppos.line,
                    ppos.col,
                    current_text[ppos.line - initial_line][ppos.col:pos.col],
                ), )
                if is_complete_edit(initial_line, last_text, current_text, es):
                    return True, es
            if clen < llen:
                if ppos == pos:  # 'x' or DEL or dt or something
                    es = ((
                        "D",
                        pos.line,
                        pos.col,
                        last_text[ppos.line - initial_line][ppos.col:ppos.col +
                                                            (llen - clen)],
                    ), )
                    if is_complete_edit(initial_line, last_text, current_text,
                                        es):
                        return True, es
                if pos < ppos:  # Backspacing or dT dF?
                    es = ((
                        "D",
                        pos.line,
                        pos.col,
                        last_text[pos.line - initial_line][pos.col:pos.col +
                                                           llen - clen],
                    ), )
                    if is_complete_edit(initial_line, last_text, current_text,
                                        es):
                        return True, es
        elif len(current_text) < len(last_text):
            # were some lines deleted? (dd or so)
            es = []
            for i in range(len(last_text) - len(current_text)):
                es.append(
                    ("D", pos.line, 0, last_text[pos.line - initial_line + i]))
                es.append(("D", pos.line, 0, "\n"))
            if is_complete_edit(initial_line, last_text, current_text, es):
                return True, es
    else:
        # Movement in more than one line
        if ppos.line + 1 == pos.line and pos.col == 0:  # Carriage return?
            es = (("I", ppos.line, ppos.col, "\n"), )
            if is_complete_edit(initial_line, last_text, current_text, es):
                return True, es
    return False, None
Example #28
0
 def fn(self):  # pylint:disable=no-self-use,invalid-name
     """The filename."""
     return vim_helper.eval('expand("%:t")') or ""
Example #29
0
 def basename(self):  # pylint:disable=no-self-use
     """The filename without extension."""
     return vim_helper.eval('expand("%:t:r")') or ""
Example #30
0
    def _cursor_moved(self):
        """Called whenever the cursor moved."""
        self._should_update_textobjects = False

        self._vstate.remember_position()
        if vim_helper.eval("mode()") not in "in":
            return

        if self._ignore_movements:
            self._ignore_movements = False
            return

        if self._active_snippets:
            cstart = self._active_snippets[0].start.line
            cend = (
                self._active_snippets[0].end.line + self._vstate.diff_in_buffer_length
            )
            ct = vim_helper.buf[cstart : cend + 1]
            lt = self._vstate.remembered_buffer
            pos = vim_helper.buf.cursor

            lt_span = [0, len(lt)]
            ct_span = [0, len(ct)]
            initial_line = cstart

            # Cut down on lines searched for changes. Start from behind and
            # remove all equal lines. Then do the same from the front.
            if lt and ct:
                while (
                    lt[lt_span[1] - 1] == ct[ct_span[1] - 1]
                    and self._vstate.ppos.line < initial_line + lt_span[1] - 1
                    and pos.line < initial_line + ct_span[1] - 1
                    and (lt_span[0] < lt_span[1])
                    and (ct_span[0] < ct_span[1])
                ):
                    ct_span[1] -= 1
                    lt_span[1] -= 1
                while (
                    lt_span[0] < lt_span[1]
                    and ct_span[0] < ct_span[1]
                    and lt[lt_span[0]] == ct[ct_span[0]]
                    and self._vstate.ppos.line >= initial_line
                    and pos.line >= initial_line
                ):
                    ct_span[0] += 1
                    lt_span[0] += 1
                    initial_line += 1
            ct_span[0] = max(0, ct_span[0] - 1)
            lt_span[0] = max(0, lt_span[0] - 1)
            initial_line = max(cstart, initial_line - 1)

            lt = lt[lt_span[0] : lt_span[1]]
            ct = ct[ct_span[0] : ct_span[1]]

            try:
                rv, es = guess_edit(initial_line, lt, ct, self._vstate)
                if not rv:
                    lt = "\n".join(lt)
                    ct = "\n".join(ct)
                    es = diff(lt, ct, initial_line)
                self._active_snippets[0].replay_user_edits(es, self._ctab)
            except IndexError:
                # Rather do nothing than throwing an error. It will be correct
                # most of the time
                pass

        self._check_if_still_inside_snippet()
        if self._active_snippets:
            self._active_snippets[0].update_textobjects(vim_helper.buf)
            self._vstate.remember_buffer(self._active_snippets[0])