File: snipmate.py

package info (click to toggle)
vim-ultisnips 3.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,924 kB
  • sloc: python: 8,353; sh: 64; makefile: 38
file content (133 lines) | stat: -rw-r--r-- 4,148 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
# encoding: utf-8

"""Parses snipMate files."""

import os
import glob

from UltiSnips import vim_helper
from UltiSnips.snippet.definition import SnipMateSnippetDefinition
from UltiSnips.snippet.source.file.base import SnippetFileSource
from UltiSnips.snippet.source.file.common import handle_extends
from UltiSnips.text import LineIterator, head_tail


def _splitall(path):
    """Split 'path' into all its components."""
    # From http://my.safaribooksonline.com/book/programming/
    # python/0596001673/files/pythoncook-chp-4-sect-16
    allparts = []
    while True:
        parts = os.path.split(path)
        if parts[0] == path:  # sentinel for absolute paths
            allparts.insert(0, parts[0])
            break
        elif parts[1] == path:  # sentinel for relative paths
            allparts.insert(0, parts[1])
            break
        else:
            path = parts[0]
            allparts.insert(0, parts[1])
    return allparts


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.realpath(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


def _parse_snippet_file(content, full_filename):
    """Parses 'content' assuming it is a .snippet file and yields events."""
    filename = full_filename[: -len(".snippet")]  # strip extension
    segments = _splitall(filename)
    segments = segments[segments.index("snippets") + 1 :]
    assert len(segments) in (2, 3)

    trigger = segments[1]
    description = segments[2] if 2 < len(segments) else ""

    # Chomp \n if any.
    if content and content.endswith(os.linesep):
        content = content[: -len(os.linesep)]
    yield "snippet", (
        SnipMateSnippetDefinition(trigger, content, description, full_filename),
    )


def _parse_snippet(line, lines, filename):
    """Parse a snippet defintions."""
    start_line_index = lines.line_index
    trigger, description = head_tail(line[len("snippet") :].lstrip())
    content = ""
    while True:
        next_line = lines.peek()
        if next_line is None:
            break
        if next_line.strip() and not next_line.startswith("\t"):
            break
        line = next(lines)
        if line[0] == "\t":
            line = line[1:]
        content += line
    content = content[:-1]  # Chomp the last newline
    return (
        "snippet",
        (
            SnipMateSnippetDefinition(
                trigger, content, description, "%s:%i" % (filename, start_line_index)
            ),
        ),
    )


def _parse_snippets_file(data, filename):
    """Parse 'data' assuming it is a .snippets file.

    Yields events in the file.

    """
    lines = LineIterator(data)
    for line in lines:
        if not line.strip():
            continue

        head, tail = head_tail(line)
        if head == "extends":
            yield handle_extends(tail, lines.line_index)
        elif head in "snippet":
            snippet = _parse_snippet(line, lines, filename)
            if snippet is not None:
                yield snippet
        elif head and not head.startswith("#"):
            yield "error", ("Invalid line %r" % line.rstrip(), lines.line_index)


class SnipMateFileSource(SnippetFileSource):

    """Manages all snipMate snippet definitions found in rtp."""

    def _get_all_snippet_files_for(self, ft):
        return _snipmate_files_for(ft)

    def _parse_snippet_file(self, filedata, filename):
        if filename.lower().endswith("snippet"):
            for event, data in _parse_snippet_file(filedata, filename):
                yield event, data
        else:
            for event, data in _parse_snippets_file(filedata, filename):
                yield event, data