Esempio n. 1
0
class SnippetUtil(object):
    """ Provides easy access to indentation, etc.
    """

    def __init__(self, initial_indent, cur=""):
        self._ind = IndentUtil()

        self._initial_indent = self._ind.indent_to_spaces(initial_indent)

        self._reset(cur)

    def _reset(self, cur):
        """ Gets the snippet ready for another update.

        :cur: the new value for c.
        """
        self._ind.reset()
        self._c = cur
        self._rv = ""
        self._changed = False
        self.reset_indent()

    def shift(self, amount=1):
        """ Shifts the indentation level.
        Note that this uses the shiftwidth because thats what code
        formatters use.

        :amount: the amount by which to shift.
        """
        self.indent += " " * self._ind.sw * amount

    def unshift(self, amount=1):
        """ Unshift the indentation level.
        Note that this uses the shiftwidth because thats what code
        formatters use.

        :amount: the amount by which to unshift.
        """
        by = -self._ind.sw * amount
        try:
            self.indent = self.indent[:by]
        except IndexError:
            indent = ""

    def mkline(self, line="", indent=None):
        """ Creates a properly set up line.

        :line: the text to add
        :indent: the indentation to have at the beginning
                 if None, it uses the default amount
        """
        if indent == None:
            indent = self.indent
            # this deals with the fact that the first line is
            # already properly indented
            if '\n' not in self._rv:
                try:
                    indent = indent[len(self._initial_indent):]
                except IndexError:
                    indent = ""
            indent = self._ind.spaces_to_indent(indent)

        return indent + line

    def reset_indent(self):
        """ Clears the indentation. """
        self.indent = self._initial_indent

    # Utility methods
    @property
    def fn(self):
        """ The filename. """
        return vim.eval('expand("%:t")') or ""

    @property
    def basename(self):
        """ The filename without extension. """
        return vim.eval('expand("%:t:r")') or ""

    @property
    def ft(self):
        """ The filetype. """
        return self.opt("&filetype", "")

    # Necessary stuff
    def rv():
        """ The return value.
        This is a list of lines to insert at the
        location of the placeholder.

        Deprecates res.
        """
        def fget(self):
            return self._rv
        def fset(self, value):
            self._changed = True
            self._rv = value
        return locals()
    rv = property(**rv())

    @property
    def _rv_changed(self):
        """ True if rv has changed. """
        return self._changed

    @property
    def c(self):
        """ The current text of the placeholder.

        Deprecates cur.
        """
        return self._c

    def opt(self, option, default=None):
        """ Gets a vim variable. """
        if vim.eval("exists('%s')" % option) == "1":
            try:
                return vim.eval(option)
            except vim.error:
                pass
        return default

    # Syntatic sugar
    def __add__(self, value):
        """ Appends the given line to rv using mkline. """
        self.rv += '\n' # handles the first line properly
        self.rv += self.mkline(value)
        return self

    def __lshift__(self, other):
        """ Same as unshift. """
        self.unshift(other)

    def __rshift__(self, other):
        """ Same as shift. """
        self.shift(other)
Esempio n. 2
0
class Snippet(object):
    _INDENT = re.compile(r"^[ \t]*")
    _TABS = re.compile(r"^\t*")

    def __init__(self, trigger, value, descr, options, globals):
        self._t = as_unicode(trigger)
        self._v = as_unicode(value)
        self._d = as_unicode(descr)
        self._opts = options
        self._matched = ""
        self._last_re = None
        self._globals = globals
        self._util = IndentUtil()

    def __repr__(self):
        return "Snippet(%s,%s,%s)" % (self._t,self._d,self._opts)

    def _words_for_line(self, before, num_words=None):
        """ Gets the final num_words words from before.
        If num_words is None, then use the number of words in
        the trigger.
        """
        words = ''
        if not len(before):
            return ''

        if num_words is None:
            num_words = len(self._t.split())

        word_list = before.split()
        if len(word_list) <= num_words:
            return before.strip()
        else:
            before_words = before
            for i in range(-1, -(num_words + 1), -1):
                left = before_words.rfind(word_list[i])
                before_words = before_words[:left]
            return before[len(before_words):].strip()

    def _re_match(self, trigger):
        """ Test if a the current regex trigger matches
        `trigger`. If so, set _last_re and _matched.
        """
        for match in re.finditer(self._t, trigger):
            if match.end() != len(trigger):
                continue
            else:
                self._matched = trigger[match.start():match.end()]

            self._last_re = match
            return match
        return False

    def matches(self, trigger):
        # 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 = ""

        # Don't expand on whitespace
        if trigger and trigger.rstrip() is not trigger:
            return False

        words = self._words_for_line(trigger)

        if "r" in self._opts:
            match = self._re_match(trigger)
        elif "w" in self._opts:
            words_len = len(self._t)
            words_prefix = words[:-words_len]
            words_suffix = words[-words_len:]
            match = (words_suffix == self._t)
            if match and words_prefix:
                # Require a word boundary between prefix and suffix.
                boundaryChars = words_prefix[-1:] + words_suffix[:1]
                match = re.match(r'.\b.', boundaryChars)
        elif "i" in self._opts:
            match = words.endswith(self._t)
        else:
            match = (words == self._t)

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

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

        return match

    def could_match(self, trigger):
        self._matched = ""

        # Don't expand on whitespace
        if trigger and trigger.rstrip() is not trigger:
            return False

        words = self._words_for_line(trigger)

        if "r" in self._opts:
            # Test for full match only
            match = self._re_match(trigger)
        elif "w" in self._opts:
            # Trim non-empty prefix up to word boundary, if present.
            words_suffix = re.sub(r'^.+\b(.+)$', r'\1', words)
            match = self._t.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._t.startswith(words)
        else:
            match = self._t.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 = trigger.rstrip()[:-len(self._matched)]
            if text_before.strip(" \t") != '':
                self._matched = ""
                return False

        return match

    def keep_formatoptions_unchanged(self):
        return "f" in self._opts
    keep_formatoptions_unchanged = property(keep_formatoptions_unchanged)

    def overwrites_previous(self):
        return "!" in self._opts
    overwrites_previous = property(overwrites_previous)

    def description(self):
        return ("(%s) %s" % (self._t, self._d)).strip()
    description = property(description)

    def trigger(self):
        return self._t
    trigger = property(trigger)

    def matched(self):
        """ The last text that was matched. """
        return self._matched
    matched = property(matched)

    def launch(self, text_before, parent, start, end = None):
        indent = self._INDENT.match(text_before).group(0)
        lines = (self._v + "\n").splitlines()
        self._util.reset()

        v = []
        for line_num, line in enumerate(lines):
            if "t" in self._opts:
                tabs = 0
            else:
                tabs = len(self._TABS.match(line).group(0))


            line_ind = tabs * self._util.sw * " "
            line_ind = self._util.indent_to_spaces(line_ind)
            line_ind = self._util.spaces_to_indent(line_ind)
            if line_num != 0:
                line_ind = indent + line_ind

            v.append(line_ind + line[tabs:])
        v = os.linesep.join(v)

        if parent is None:
            return SnippetInstance(StartMarker(start), indent,
                    v, last_re = self._last_re, globals = self._globals)
        else:
            return SnippetInstance(parent, indent, v, start,
                    end, last_re = self._last_re, globals = self._globals)
Esempio n. 3
0
class SnippetUtil(object):
    """ Provides easy access to indentation, etc.
    """
    def __init__(self, initial_indent, cur=""):
        self._ind = IndentUtil()

        self._initial_indent = self._ind.indent_to_spaces(initial_indent)

        self._reset(cur)

    def _reset(self, cur):
        """ Gets the snippet ready for another update.

        :cur: the new value for c.
        """
        self._ind.reset()
        self._c = cur
        self._rv = ""
        self._changed = False
        self.reset_indent()

    def shift(self, amount=1):
        """ Shifts the indentation level.
        Note that this uses the shiftwidth because thats what code
        formatters use.

        :amount: the amount by which to shift.
        """
        self.indent += " " * self._ind.sw * amount

    def unshift(self, amount=1):
        """ Unshift the indentation level.
        Note that this uses the shiftwidth because thats what code
        formatters use.

        :amount: the amount by which to unshift.
        """
        by = -self._ind.sw * amount
        try:
            self.indent = self.indent[:by]
        except IndexError:
            indent = ""

    def mkline(self, line="", indent=None):
        """ Creates a properly set up line.

        :line: the text to add
        :indent: the indentation to have at the beginning
                 if None, it uses the default amount
        """
        if indent == None:
            indent = self.indent
            # this deals with the fact that the first line is
            # already properly indented
            if '\n' not in self._rv:
                try:
                    indent = indent[len(self._initial_indent):]
                except IndexError:
                    indent = ""
            indent = self._ind.spaces_to_indent(indent)

        return indent + line

    def reset_indent(self):
        """ Clears the indentation. """
        self.indent = self._initial_indent

    # Utility methods
    @property
    def fn(self):
        """ The filename. """
        return vim.eval('expand("%:t")') or ""

    @property
    def basename(self):
        """ The filename without extension. """
        return vim.eval('expand("%:t:r")') or ""

    @property
    def ft(self):
        """ The filetype. """
        return self.opt("&filetype", "")

    # Necessary stuff
    def rv():
        """ The return value.
        This is a list of lines to insert at the
        location of the placeholder.

        Deprecates res.
        """
        def fget(self):
            return self._rv

        def fset(self, value):
            self._changed = True
            self._rv = value

        return locals()

    rv = property(**rv())

    @property
    def _rv_changed(self):
        """ True if rv has changed. """
        return self._changed

    @property
    def c(self):
        """ The current text of the placeholder.

        Deprecates cur.
        """
        return self._c

    def opt(self, option, default=None):
        """ Gets a vim variable. """
        if vim.eval("exists('%s')" % option) == "1":
            try:
                return vim.eval(option)
            except vim.error:
                pass
        return default

    # Syntatic sugar
    def __add__(self, value):
        """ Appends the given line to rv using mkline. """
        self.rv += '\n'  # handles the first line properly
        self.rv += self.mkline(value)
        return self

    def __lshift__(self, other):
        """ Same as unshift. """
        self.unshift(other)

    def __rshift__(self, other):
        """ Same as shift. """
        self.shift(other)
Esempio n. 4
0
class Snippet(object):
    _INDENT = re.compile(r"^[ \t]*")
    _TABS = re.compile(r"^\t*")

    def __init__(self, trigger, value, descr, options, globals):
        self._t = as_unicode(trigger)
        self._v = as_unicode(value)
        self._d = as_unicode(descr)
        self._opts = options
        self._matched = ""
        self._last_re = None
        self._globals = globals
        self._util = IndentUtil()

    def __repr__(self):
        return "Snippet(%s,%s,%s)" % (self._t, self._d, self._opts)

    def _words_for_line(self, before, num_words=None):
        """ Gets the final num_words words from before.
        If num_words is None, then use the number of words in
        the trigger.
        """
        words = ''
        if not len(before):
            return ''

        if num_words is None:
            num_words = len(self._t.split())

        word_list = before.split()
        if len(word_list) <= num_words:
            return before.strip()
        else:
            before_words = before
            for i in range(-1, -(num_words + 1), -1):
                left = before_words.rfind(word_list[i])
                before_words = before_words[:left]
            return before[len(before_words):].strip()

    def _re_match(self, trigger):
        """ Test if a the current regex trigger matches
        `trigger`. If so, set _last_re and _matched.
        """
        for match in re.finditer(self._t, trigger):
            if match.end() != len(trigger):
                continue
            else:
                self._matched = trigger[match.start():match.end()]

            self._last_re = match
            return match
        return False

    def matches(self, trigger):
        # 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 = ""

        # Don't expand on whitespace
        if trigger and trigger.rstrip() is not trigger:
            return False

        words = self._words_for_line(trigger)

        if "r" in self._opts:
            match = self._re_match(trigger)
        elif "w" in self._opts:
            words_len = len(self._t)
            words_prefix = words[:-words_len]
            words_suffix = words[-words_len:]
            match = (words_suffix == self._t)
            if match and words_prefix:
                # Require a word boundary between prefix and suffix.
                boundaryChars = words_prefix[-1:] + words_suffix[:1]
                match = re.match(r'.\b.', boundaryChars)
        elif "i" in self._opts:
            match = words.endswith(self._t)
        else:
            match = (words == self._t)

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

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

        return match

    def could_match(self, trigger):
        self._matched = ""

        # Don't expand on whitespace
        if trigger and trigger.rstrip() is not trigger:
            return False

        words = self._words_for_line(trigger)

        if "r" in self._opts:
            # Test for full match only
            match = self._re_match(trigger)
        elif "w" in self._opts:
            # Trim non-empty prefix up to word boundary, if present.
            words_suffix = re.sub(r'^.+\b(.+)$', r'\1', words)
            match = self._t.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._t.startswith(words)
        else:
            match = self._t.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 = trigger.rstrip()[:-len(self._matched)]
            if text_before.strip(" \t") != '':
                self._matched = ""
                return False

        return match

    def keep_formatoptions_unchanged(self):
        return "f" in self._opts

    keep_formatoptions_unchanged = property(keep_formatoptions_unchanged)

    def overwrites_previous(self):
        return "!" in self._opts

    overwrites_previous = property(overwrites_previous)

    def description(self):
        return ("(%s) %s" % (self._t, self._d)).strip()

    description = property(description)

    def trigger(self):
        return self._t

    trigger = property(trigger)

    def matched(self):
        """ The last text that was matched. """
        return self._matched

    matched = property(matched)

    def launch(self, text_before, parent, start, end=None):
        indent = self._INDENT.match(text_before).group(0)
        lines = (self._v + "\n").splitlines()
        self._util.reset()

        v = []
        for line_num, line in enumerate(lines):
            if "t" in self._opts:
                tabs = 0
            else:
                tabs = len(self._TABS.match(line).group(0))

            line_ind = tabs * self._util.sw * " "
            line_ind = self._util.indent_to_spaces(line_ind)
            line_ind = self._util.spaces_to_indent(line_ind)
            if line_num != 0:
                line_ind = indent + line_ind

            v.append(line_ind + line[tabs:])
        v = os.linesep.join(v)

        if parent is None:
            return SnippetInstance(StartMarker(start),
                                   indent,
                                   v,
                                   last_re=self._last_re,
                                   globals=self._globals)
        else:
            return SnippetInstance(parent,
                                   indent,
                                   v,
                                   start,
                                   end,
                                   last_re=self._last_re,
                                   globals=self._globals)