Return index of a good place to begin parsing, as close to the end of the string as possible. This will be the start of some popular stmt like "if" or "def". Return None if none found: the caller should pass more prior context then, if possible, or if not (
(self, is_char_in_string)
| 134 | self.study_level = 0 |
| 135 | |
| 136 | def find_good_parse_start(self, is_char_in_string): |
| 137 | """ |
| 138 | Return index of a good place to begin parsing, as close to the |
| 139 | end of the string as possible. This will be the start of some |
| 140 | popular stmt like "if" or "def". Return None if none found: |
| 141 | the caller should pass more prior context then, if possible, or |
| 142 | if not (the entire program text up until the point of interest |
| 143 | has already been tried) pass 0 to set_lo(). |
| 144 | |
| 145 | This will be reliable iff given a reliable is_char_in_string() |
| 146 | function, meaning that when it says "no", it's absolutely |
| 147 | guaranteed that the char is not in a string. |
| 148 | """ |
| 149 | code, pos = self.code, None |
| 150 | |
| 151 | # Peek back from the end for a good place to start, |
| 152 | # but don't try too often; pos will be left None, or |
| 153 | # bumped to a legitimate synch point. |
| 154 | limit = len(code) |
| 155 | for tries in range(5): |
| 156 | i = code.rfind(":\n", 0, limit) |
| 157 | if i < 0: |
| 158 | break |
| 159 | i = code.rfind('\n', 0, i) + 1 # start of colon line (-1+1=0) |
| 160 | m = _synchre(code, i, limit) |
| 161 | if m and not is_char_in_string(m.start()): |
| 162 | pos = m.start() |
| 163 | break |
| 164 | limit = i |
| 165 | if pos is None: |
| 166 | # Nothing looks like a block-opener, or stuff does |
| 167 | # but is_char_in_string keeps returning true; most likely |
| 168 | # we're in or near a giant string, the colorizer hasn't |
| 169 | # caught up enough to be helpful, or there simply *aren't* |
| 170 | # any interesting stmts. In any of these cases we're |
| 171 | # going to have to parse the whole thing to be sure, so |
| 172 | # give it one last try from the start, but stop wasting |
| 173 | # time here regardless of the outcome. |
| 174 | m = _synchre(code) |
| 175 | if m and not is_char_in_string(m.start()): |
| 176 | pos = m.start() |
| 177 | return pos |
| 178 | |
| 179 | # Peeking back worked; look forward until _synchre no longer |
| 180 | # matches. |
| 181 | i = pos + 1 |
| 182 | while m := _synchre(code, i): |
| 183 | s, i = m.span() |
| 184 | if not is_char_in_string(s): |
| 185 | pos = s |
| 186 | return pos |
| 187 | |
| 188 | def set_lo(self, lo): |
| 189 | """ Throw away the start of the string. |
no test coverage detected