parse a command line and return a list of `MatchResult`s describing each token.
| 68 | |
| 69 | |
| 70 | class Matcher(bashlex.ast.nodevisitor): |
| 71 | """parse a command line and return a list of `MatchResult`s describing |
| 72 | each token. |
| 73 | """ |
| 74 | |
| 75 | def __init__( |
| 76 | self, |
| 77 | s, |
| 78 | store, |
| 79 | distro: str | None = None, |
| 80 | release: str | None = None, |
| 81 | distro_preference: list[tuple[str, str]] | None = None, |
| 82 | ): |
| 83 | self.s = s |
| 84 | self.store = store |
| 85 | self.distro = distro |
| 86 | self.release = release |
| 87 | self._distro_preference = distro_preference or [] |
| 88 | self._anchored = False |
| 89 | self._prev_option = self._current_option = None |
| 90 | self.groups = [MatchGroup("shell")] |
| 91 | |
| 92 | # a list of `match_word_exp` where expansions happened during word |
| 93 | # expansion |
| 94 | self.expansions = [] |
| 95 | |
| 96 | # a stack to manage nested command groups: whenever a new simple |
| 97 | # command is started, we push a tuple with: |
| 98 | # - the node that started this group. this is used to find it when |
| 99 | # a command ends (see visitnodeend) |
| 100 | # - its `MatchGroup`. new `MatchResult`s will be added to it. |
| 101 | # - a word used to end the top-most command. this is used when a flag |
| 102 | # starts a new command, e.g. find -exec. |
| 103 | self.group_stack = [(None, self.groups[-1], None)] |
| 104 | |
| 105 | # keep a stack of the currently visited compound command (if/for..) |
| 106 | # to provide context when matching reserved words, since for example |
| 107 | # the keyword 'done' can appear in a for, while.. |
| 108 | self.compound_stack = [] |
| 109 | |
| 110 | # a set of functions defined in the current input, we will try to match |
| 111 | # commands against them so if one refers to defined function, it won't |
| 112 | # show up as unknown or be taken from the db |
| 113 | self.functions = set() |
| 114 | |
| 115 | def _generate_cmd_group_name(self): |
| 116 | existing = len([g for g in self.groups if g.name.startswith("command")]) |
| 117 | return f"command{existing}" |
| 118 | |
| 119 | @property |
| 120 | def matches(self): |
| 121 | """return the list of results from the most recently created group""" |
| 122 | return self.group_stack[-1][1].results |
| 123 | |
| 124 | @property |
| 125 | def all_matches(self): |
| 126 | return list(itertools.chain.from_iterable(g.results for g in self.groups)) |
| 127 |
nothing calls this directly
no outgoing calls
no test coverage detected