File: completer.py

package info (click to toggle)
cadabra2 2.4.3.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 78,796 kB
  • sloc: ansic: 133,450; cpp: 92,064; python: 1,530; javascript: 203; sh: 184; xml: 182; objc: 53; makefile: 51
file content (98 lines) | stat: -rw-r--r-- 2,617 bytes parent folder | download | duplicates (3)
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
""" keywords scraped from cadabra.science/man.html """

properties = [
    "Accent",
    "AntiCommuting",
    "AntiSymmetric",
    "Commuting",
    "CommutingAsProduct",
    "CommutingAsSum",
    "Coordinate",
    "DAntiSymmetric",
    "Depends",
    "Derivative",
    "Determinant",
    "Diagonal",
    "DiracBar",
    "EpsilonTensor",
    "FilledTableau",
    "GammaMatrix",
    "ImplicitIndex",
    "IndexInherit",
    "Indices",
    "Integer",
    "InverseMetric",
    "KroneckerDelta",
    "LaTeXForm",
    "Metric",
    "NonCommuting",
    "PartialDerivative",
    "RiemannTensor",
    "SatisfiesBianchi",
    "SelfAntiCommuting",
    "SelfCommuting",
    "SelfNonCommuting",
    "SortOrder",
    "Spinor",
    "Symbol",
    "Symmetric",
    "Tableau",
    "TableauSymmetry",
    "WeightInherit",
]


import re
import string


class CodeCompleter:
    def __init__(self, kernel):
        self._kernel = kernel
        self.code = ""

    @property
    def triggers(self):
        return string.ascii_letters + ":;."

    def get_last_word(self):
        return re.compile(r"[\W\s]").split(self.code)[-1]

    def cursor_on_property(self, last):
        search_query = re.compile(".*::{}$".format(last), re.MULTILINE)
        return re.search(search_query, self.code)

    def match(self, last, options):
        opts = list(filter(lambda i: re.match("^{}.*".format(last), i), options))
        # return options and length of the last matched word
        return opts, len(last)

    def match_member(self, last, klass):
        """ matches last word in the namespace of the currently selected class """
        instance = self._kernel._sandbox_context._sandbox[klass]
        #  filter out hidden namespace, unless typing hidden namespace
        return self.match(last, (i for i in dir(instance) if "__" not in i))

    def get_class(self):
        """ get class currently behind cursor  """
        return re.findall(r"(\w+)\.\w*$", self.code)

    def __call__(self, code, cursor_pos, namespace):
        # only choose up until current cursor position
        self.code = code[:cursor_pos]

        last = self.get_last_word()
        matched_klass = self.get_class()

        if self.cursor_on_property(last):
            # cursor on cadabra property
            if last:
                return self.match(last, properties)
            else:
                return properties, 0

        elif matched_klass and matched_klass[-1] in namespace:
            # cursor on member function
            return self.match_member(last, matched_klass[-1])
        else:
            return self.match(last, namespace)