bracex 3.2__tar.gz → 3.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bracex-3.2 → bracex-3.2.2}/PKG-INFO +1 -1
- {bracex-3.2 → bracex-3.2.2}/bracex/__init__.py +177 -19
- {bracex-3.2 → bracex-3.2.2}/bracex/__main__.py +1 -1
- {bracex-3.2 → bracex-3.2.2}/bracex/__meta__.py +1 -1
- bracex-3.2.2/docs/src/dictionary/en-custom.txt +45 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/about/changelog.md +15 -0
- {bracex-3.2 → bracex-3.2.2}/pyproject.toml +2 -3
- {bracex-3.2 → bracex-3.2.2}/tests/brace-cases.txt +73 -0
- {bracex-3.2 → bracex-3.2.2}/tests/brace-results.txt +172 -1
- bracex-3.2.2/tests/generate.sh +22 -0
- {bracex-3.2 → bracex-3.2.2}/tests/test_brace.py +19 -2
- bracex-3.2.2/zensical.yml +164 -0
- bracex-3.2/tests/generate.sh +0 -21
- {bracex-3.2 → bracex-3.2.2}/.gitignore +0 -0
- {bracex-3.2 → bracex-3.2.2}/.pyspelling.yml +0 -0
- {bracex-3.2 → bracex-3.2.2}/LICENSE.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/README.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/bracex/py.typed +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/.snippets/abbr.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/.snippets/links.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/.snippets/refs.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/about/contributing.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/about/development.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/about/license.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/src/markdown/index.md +0 -0
- {bracex-3.2 → bracex-3.2.2}/docs/theme/announce.html +0 -0
- {bracex-3.2 → bracex-3.2.2}/hatch_build.py +0 -0
- {bracex-3.2 → bracex-3.2.2}/tests/__init__.py +0 -0
- {bracex-3.2 → bracex-3.2.2}/tests/test_main.py +0 -0
- {bracex-3.2 → bracex-3.2.2}/tests/test_versions.py +0 -0
- {bracex-3.2 → bracex-3.2.2}/tools/pycon.py +0 -0
|
@@ -33,8 +33,13 @@ __version_info__ = __meta__.__version_info__
|
|
|
33
33
|
_alpha = [chr(x) if x != 0x5c else '' for x in range(ord('A'), ord('z') + 1)]
|
|
34
34
|
_nalpha = list(reversed(_alpha))
|
|
35
35
|
|
|
36
|
-
RE_INT_ITER = re.compile(
|
|
37
|
-
|
|
36
|
+
RE_INT_ITER = re.compile(
|
|
37
|
+
r'([-+]?((?:0(?=\d))*)\d+)\.{2}([-+]?((?:0(?=\d))*)\d+)(?:\.{2}[-+]?(((?:0(?=\d))*)\d+))?(?=\})', re.ASCII
|
|
38
|
+
)
|
|
39
|
+
RE_CHR_ITER = re.compile(r'([A-Za-z])\.{2}([A-Za-z])(?:\.{2}[-+]?(((?:0(?=\d))*)\d+))?(?=\})', re.ASCII)
|
|
40
|
+
RE_SEQ_SEP = re.compile(r'\.(?!\})')
|
|
41
|
+
RE_SEQ_TERM = re.compile(r'(?:[-+]?\d|[A-Za-z]\.)', re.ASCII)
|
|
42
|
+
RE_SEQ_TERM_END = re.compile(r'(?:[-+]?\d|[A-Za-z][.}])', re.ASCII)
|
|
38
43
|
|
|
39
44
|
DEFAULT_LIMIT = 1000
|
|
40
45
|
|
|
@@ -97,6 +102,8 @@ class StringIter:
|
|
|
97
102
|
|
|
98
103
|
self._string = string
|
|
99
104
|
self._index = 0
|
|
105
|
+
self._last_seq = string.rfind('..')
|
|
106
|
+
self.scan_memo = {} # type: dict[int, tuple[int, bool]]
|
|
100
107
|
|
|
101
108
|
def __iter__(self) -> "StringIter": # pragma: no cover
|
|
102
109
|
"""Iterate."""
|
|
@@ -122,6 +129,18 @@ class StringIter:
|
|
|
122
129
|
|
|
123
130
|
return self._index
|
|
124
131
|
|
|
132
|
+
@property
|
|
133
|
+
def last_seq(self) -> int:
|
|
134
|
+
"""Get the index of the last `..`, or -1 if there are none."""
|
|
135
|
+
|
|
136
|
+
return self._last_seq
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def string(self) -> str:
|
|
140
|
+
"""Get the string being iterated."""
|
|
141
|
+
|
|
142
|
+
return self._string
|
|
143
|
+
|
|
125
144
|
def previous(self) -> str: # pragma: no cover
|
|
126
145
|
"""Get previous char."""
|
|
127
146
|
|
|
@@ -196,6 +215,84 @@ class ExpandBrace:
|
|
|
196
215
|
if release:
|
|
197
216
|
self.expanding = False
|
|
198
217
|
|
|
218
|
+
def scan_group(self, i: StringIter, index: int, bounded: bool) -> tuple[int, bool]:
|
|
219
|
+
"""
|
|
220
|
+
Scan ahead, like Bash to find the `}` that ends the group starting at `index`.
|
|
221
|
+
|
|
222
|
+
Returns the index of the closing `}` (or -1 if there is none) and whether Bash would treat the group
|
|
223
|
+
as a sequence candidate: a top level `..` (not directly followed by `}`) and no top level comma.
|
|
224
|
+
|
|
225
|
+
Bash only ever sees the slot a nested group is in, so when `bounded`, a top level `}` that doesn't end the
|
|
226
|
+
group can only be the end of the slot, which means there is no closing `}`.
|
|
227
|
+
|
|
228
|
+
Groups nested in the one being scanned are tracked as they are passed, as their outcome (as a bounded
|
|
229
|
+
group) is known as soon as they close. These are remembered so they don't have to be scanned again.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
string = i.string
|
|
233
|
+
memo = i.scan_memo
|
|
234
|
+
if bounded:
|
|
235
|
+
result = memo.get(index)
|
|
236
|
+
if result is not None:
|
|
237
|
+
return result
|
|
238
|
+
|
|
239
|
+
# Open nested groups as `[start, found a separator, is a sequence]`, and `None` for a `${`.
|
|
240
|
+
stack = [] # type: list[list[Any] | None]
|
|
241
|
+
found = False # A top level comma or `..` has been found, which allows a top level `}` to end the group.
|
|
242
|
+
is_seq = False
|
|
243
|
+
size = len(string)
|
|
244
|
+
while index < size:
|
|
245
|
+
c = string[index]
|
|
246
|
+
if c == '\\':
|
|
247
|
+
index += 1
|
|
248
|
+
elif c == '$' and string.startswith('{', index + 1):
|
|
249
|
+
stack.append(None)
|
|
250
|
+
index += 1
|
|
251
|
+
elif c == '{':
|
|
252
|
+
stack.append([index + 1, False, False])
|
|
253
|
+
elif c == '}':
|
|
254
|
+
if stack:
|
|
255
|
+
nested = stack.pop()
|
|
256
|
+
if nested is not None:
|
|
257
|
+
memo[nested[0]] = (index, nested[2]) if nested[1] else (-1, False)
|
|
258
|
+
elif found:
|
|
259
|
+
return index, is_seq
|
|
260
|
+
elif bounded: # pragma: no cover
|
|
261
|
+
# A nested group is normally already known from the scan of the group around it.
|
|
262
|
+
break
|
|
263
|
+
elif c == ',' or (c == '.' and string.startswith('..', index) and string[index + 2:index + 3] != '}'):
|
|
264
|
+
if not stack:
|
|
265
|
+
if c == ',' or not found:
|
|
266
|
+
found = True
|
|
267
|
+
is_seq = c == '.'
|
|
268
|
+
else:
|
|
269
|
+
top = stack[-1]
|
|
270
|
+
if top is not None and (c == ',' or not top[1]):
|
|
271
|
+
top[1:] = [True, c == '.']
|
|
272
|
+
index += 1
|
|
273
|
+
return -1, False
|
|
274
|
+
|
|
275
|
+
def looks_like_sequence(self, group: str) -> bool:
|
|
276
|
+
"""
|
|
277
|
+
Check whether the group (with its closing `}`) starts like a sequence.
|
|
278
|
+
|
|
279
|
+
This is Bash's loose `valid_seqterm` check: both sides of the first `..` must start like the same kind
|
|
280
|
+
of term (integer or letter). Whether the sequence is really valid is not considered here.
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
index = group.find('..')
|
|
284
|
+
if index < 1 or group[0] == '.':
|
|
285
|
+
return False
|
|
286
|
+
left = RE_SEQ_TERM.match(group)
|
|
287
|
+
right = RE_SEQ_TERM_END.match(group, index + 2)
|
|
288
|
+
return bool(left and right and group[0].isalpha() == group[index + 2].isalpha())
|
|
289
|
+
|
|
290
|
+
def literal_text(self, text: str) -> str:
|
|
291
|
+
"""Resolve escapes in text that is kept literally."""
|
|
292
|
+
|
|
293
|
+
i = StringIter(text)
|
|
294
|
+
return ''.join(self.get_escape(c, i) if c == '\\' else c for c in i)
|
|
295
|
+
|
|
199
296
|
def get_escape(self, c: str, i: StringIter) -> str:
|
|
200
297
|
"""Get an escape."""
|
|
201
298
|
|
|
@@ -241,7 +338,7 @@ class ExpandBrace:
|
|
|
241
338
|
i: StringIter,
|
|
242
339
|
depth: int,
|
|
243
340
|
ignore_end: bool = False
|
|
244
|
-
) -> tuple[list[str | Iterator[str]], int]:
|
|
341
|
+
) -> tuple[list[str | Iterator[str]], int, bool]:
|
|
245
342
|
"""
|
|
246
343
|
Get a string literal.
|
|
247
344
|
|
|
@@ -250,9 +347,12 @@ class ExpandBrace:
|
|
|
250
347
|
"""
|
|
251
348
|
|
|
252
349
|
result = [] # type: list[str | Iterator[str]]
|
|
350
|
+
word_start = 0
|
|
253
351
|
is_dollar = False
|
|
352
|
+
dollar_depth = 0
|
|
254
353
|
count = 1
|
|
255
354
|
literal = ''
|
|
355
|
+
has_seq = False
|
|
256
356
|
|
|
257
357
|
try:
|
|
258
358
|
while c:
|
|
@@ -266,7 +366,11 @@ class ExpandBrace:
|
|
|
266
366
|
elif c == '\\':
|
|
267
367
|
literal += self.get_escape(c, i)
|
|
268
368
|
|
|
269
|
-
elif
|
|
369
|
+
elif (ignore_brace and c == '{') or (dollar_depth and c == '}'):
|
|
370
|
+
literal += c
|
|
371
|
+
dollar_depth += 1 if c == '{' else -1
|
|
372
|
+
|
|
373
|
+
elif c == '{':
|
|
270
374
|
|
|
271
375
|
if literal:
|
|
272
376
|
result.append(literal)
|
|
@@ -274,7 +378,10 @@ class ExpandBrace:
|
|
|
274
378
|
|
|
275
379
|
# Try and get the group
|
|
276
380
|
try:
|
|
277
|
-
seq, scount = self.get_sequence(next(i), i, depth + 1)
|
|
381
|
+
seq, scount, expanded = self.get_sequence(next(i), i, depth + 1, word_start)
|
|
382
|
+
if expanded:
|
|
383
|
+
# Bash expands each postamble as a new word.
|
|
384
|
+
word_start = i.index
|
|
278
385
|
count *= scount
|
|
279
386
|
result.append(seq)
|
|
280
387
|
except StopIteration:
|
|
@@ -283,7 +390,7 @@ class ExpandBrace:
|
|
|
283
390
|
literal += c
|
|
284
391
|
raise
|
|
285
392
|
|
|
286
|
-
elif self.is_expanding() and (c == ',' or (c == '}' and not ignore_end)):
|
|
393
|
+
elif self.is_expanding() and not dollar_depth and (c == ',' or (c == '}' and not ignore_end)):
|
|
287
394
|
# We are Expanding within a group and found a group delimiter
|
|
288
395
|
# Return what we gathered before the group delimiters.
|
|
289
396
|
|
|
@@ -294,6 +401,14 @@ class ExpandBrace:
|
|
|
294
401
|
|
|
295
402
|
i.rewind(1)
|
|
296
403
|
break
|
|
404
|
+
|
|
405
|
+
elif not dollar_depth and c == '.' and i.match(RE_SEQ_SEP):
|
|
406
|
+
# Bash counts `..` like a comma when looking for the `}` that ends a top level group,
|
|
407
|
+
# unless `}` follows it, so the next `}` can end the group.
|
|
408
|
+
ignore_end = False
|
|
409
|
+
has_seq = True
|
|
410
|
+
literal += '..'
|
|
411
|
+
|
|
297
412
|
else:
|
|
298
413
|
literal += c
|
|
299
414
|
|
|
@@ -303,9 +418,9 @@ class ExpandBrace:
|
|
|
303
418
|
if literal:
|
|
304
419
|
result.append(literal)
|
|
305
420
|
|
|
306
|
-
return result, self.account(count)
|
|
421
|
+
return result, self.account(count), has_seq
|
|
307
422
|
|
|
308
|
-
def get_sequence(self, c: str, i: StringIter, depth: int) -> tuple[Iterator[str], int]:
|
|
423
|
+
def get_sequence(self, c: str, i: StringIter, depth: int, word_start: int) -> tuple[Iterator[str], int, bool]:
|
|
309
424
|
"""
|
|
310
425
|
Get the sequence.
|
|
311
426
|
|
|
@@ -314,8 +429,10 @@ class ExpandBrace:
|
|
|
314
429
|
"""
|
|
315
430
|
|
|
316
431
|
result = [] # type: list[str | Iterator[str] | Iterable[str | Iterator[str]]]
|
|
432
|
+
group_start = i.index - 1 # Index of the first character within the group.
|
|
317
433
|
release = self.set_expanding()
|
|
318
434
|
has_comma = False # Used to indicate validity of group (`{1..2}` are an exception).
|
|
435
|
+
has_seq = False # Used to indicate a top level `..` that lets the next `}` end the group.
|
|
319
436
|
is_empty = True # Tracks whether the current slot is empty `{slot,slot,slot}`.
|
|
320
437
|
counts = []
|
|
321
438
|
|
|
@@ -325,15 +442,34 @@ class ExpandBrace:
|
|
|
325
442
|
i.advance(1)
|
|
326
443
|
if item is not None:
|
|
327
444
|
self.release_expanding(release)
|
|
328
|
-
return item, self.account(count)
|
|
445
|
+
return item, self.account(count), True
|
|
446
|
+
|
|
447
|
+
# Bash decides up front whether a group is a sequence candidate and, if so, whether it looks like a sequence.
|
|
448
|
+
# A group that looks like one but isn't valid is kept as text, nested groups and all. A group that doesn't
|
|
449
|
+
# even look like one is abandoned: Bash skips just the `{` and tries again with what follows.
|
|
450
|
+
# Without a `..` ahead, the group can't be a sequence candidate, so skip the scan.
|
|
451
|
+
end, is_seq = self.scan_group(i, group_start, depth > 1) if i.last_seq >= group_start else (-1, False)
|
|
452
|
+
if is_seq and end != -1:
|
|
453
|
+
self.release_expanding(release)
|
|
454
|
+
if self.looks_like_sequence(i.string[group_start:end + 1]):
|
|
455
|
+
i.advance(end + 1 - i.index)
|
|
456
|
+
return iter(['{' + self.literal_text(i.string[group_start:end]) + '}']), 1, False
|
|
457
|
+
if depth == 1:
|
|
458
|
+
# Continue the current word from just after the `{`.
|
|
459
|
+
i.rewind(i.index - group_start)
|
|
460
|
+
return iter(['{']), 1, False
|
|
461
|
+
# Nested groups are confined to their slot, so expand what follows the `{` on its own.
|
|
462
|
+
sub, scount = self.expand_isolated(i.string[group_start:end + 1])
|
|
463
|
+
i.advance(end + 1 - i.index)
|
|
464
|
+
return self.squash(iter(['{']), sub), scount, False
|
|
329
465
|
|
|
330
466
|
try:
|
|
331
467
|
while True:
|
|
332
468
|
# Bash has some special top level logic. if `}` follows `{` but hasn't matched
|
|
333
|
-
# a group yet, keep going except when the first 2 bytes
|
|
334
|
-
# completely ignored.
|
|
335
|
-
keep_looking = depth == 1 and not has_comma
|
|
336
|
-
if (c == '}' and (not keep_looking or i.index == 2)):
|
|
469
|
+
# a group yet, keep going except when the first 2 bytes of the current
|
|
470
|
+
# postamble are `{}` which gets completely ignored.
|
|
471
|
+
keep_looking = depth == 1 and not has_comma and not has_seq
|
|
472
|
+
if (c == '}' and (not keep_looking or i.index == word_start + 2)):
|
|
337
473
|
self.release_expanding(release)
|
|
338
474
|
|
|
339
475
|
# Handle empty slot
|
|
@@ -349,7 +485,7 @@ class ExpandBrace:
|
|
|
349
485
|
for r in self.flatten(result):
|
|
350
486
|
temp = self.squash(temp, [r] if isinstance(r, str) else r)
|
|
351
487
|
temp = self.squash(temp, ['}'])
|
|
352
|
-
return temp, self.account(math.prod(counts, start=1))
|
|
488
|
+
return temp, self.account(math.prod(counts, start=1)), False
|
|
353
489
|
|
|
354
490
|
# Format return for a sequence
|
|
355
491
|
fin = iter([]) # type: Iterator[str]
|
|
@@ -369,7 +505,7 @@ class ExpandBrace:
|
|
|
369
505
|
start = e + 1
|
|
370
506
|
if start < l:
|
|
371
507
|
fin = self.chain(fin, result[start:])
|
|
372
|
-
return fin, self.account(sum(counts))
|
|
508
|
+
return fin, self.account(sum(counts)), True
|
|
373
509
|
|
|
374
510
|
elif c == ',':
|
|
375
511
|
# Must be the first element in the list.
|
|
@@ -382,7 +518,7 @@ class ExpandBrace:
|
|
|
382
518
|
|
|
383
519
|
else:
|
|
384
520
|
# Lower level: Try to find group, but give up if cannot acquire.
|
|
385
|
-
value, lcount = self.get_literals(c, i, depth, keep_looking)
|
|
521
|
+
value, lcount, has_seq = self.get_literals(c, i, depth, keep_looking)
|
|
386
522
|
counts.append(lcount)
|
|
387
523
|
if value is not None:
|
|
388
524
|
if len(value) > 1:
|
|
@@ -408,7 +544,7 @@ class ExpandBrace:
|
|
|
408
544
|
for r in self.flatten([slot]):
|
|
409
545
|
member = self.squash(member, [r] if isinstance(r, str) else r)
|
|
410
546
|
temp2 = self.squash(temp2, member)
|
|
411
|
-
return temp2, self.account(math.prod(counts, start=1))
|
|
547
|
+
return temp2, self.account(math.prod(counts, start=1)), False
|
|
412
548
|
|
|
413
549
|
def get_range(self, i: StringIter) -> tuple[Iterator[str] | None, int]:
|
|
414
550
|
"""
|
|
@@ -461,9 +597,15 @@ class ExpandBrace:
|
|
|
461
597
|
last = int64(end)
|
|
462
598
|
inc = max(1, int64(increment))
|
|
463
599
|
|
|
600
|
+
# Bash's zero-padding rule: padding is only enabled when an operand, as written,
|
|
601
|
+
# starts with `0` (or `-0`). A unary `+` sign never enables padding, but once
|
|
602
|
+
# padding is enabled by either operand, the full written width of both operands
|
|
603
|
+
# (signs included) is honored.
|
|
604
|
+
arm = bool((spad[1] - spad[0]) and not start.startswith('+'))
|
|
605
|
+
arm = arm or bool((epad[1] - epad[0]) and not end.startswith('+'))
|
|
464
606
|
spad_len = spad[1] - spad[0]
|
|
465
607
|
epad_len = epad[1] - epad[0]
|
|
466
|
-
padding = max(spad_len + len(start), epad_len + len(end)) if
|
|
608
|
+
padding = max(spad_len + len(start), epad_len + len(end)) if arm else 0
|
|
467
609
|
|
|
468
610
|
if first < last:
|
|
469
611
|
span = abs(last - first + 1)
|
|
@@ -509,11 +651,27 @@ class ExpandBrace:
|
|
|
509
651
|
r = range(first, last - 1, -inc)
|
|
510
652
|
return (alpha[i] for i in r), count
|
|
511
653
|
|
|
654
|
+
def expand_isolated(self, string: str) -> tuple[Iterator[str], int]:
|
|
655
|
+
"""Expand a piece of text on its own, as though it were not inside a group."""
|
|
656
|
+
|
|
657
|
+
expanding = self.expanding
|
|
658
|
+
self.expanding = False
|
|
659
|
+
try:
|
|
660
|
+
i = StringIter(string)
|
|
661
|
+
values, count, _ = self.get_literals(next(i), i, 0)
|
|
662
|
+
finally:
|
|
663
|
+
self.expanding = expanding
|
|
664
|
+
|
|
665
|
+
results = iter([EMPTY]) # type: Iterator[str]
|
|
666
|
+
for v in values:
|
|
667
|
+
results = self.squash(results, [v] if isinstance(v, str) else v)
|
|
668
|
+
return results, count
|
|
669
|
+
|
|
512
670
|
def expand_str(self, string: str) -> Iterator[str]:
|
|
513
671
|
"""Expand the string."""
|
|
514
672
|
|
|
515
673
|
i = StringIter(string)
|
|
516
|
-
values, _ = self.get_literals(next(i), i, 0)
|
|
674
|
+
values, _, _ = self.get_literals(next(i), i, 0)
|
|
517
675
|
|
|
518
676
|
# Squash the nested list by calculating the combinations
|
|
519
677
|
results = iter([EMPTY]) # type: Iterator[str]
|
|
@@ -24,7 +24,7 @@ import argparse
|
|
|
24
24
|
import bracex
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def main(argv: str | None = None) -> None:
|
|
27
|
+
def main(argv: list[str] | None = None) -> None:
|
|
28
28
|
"""Accept command line arguments and output brace expansion to stdout."""
|
|
29
29
|
parser = argparse.ArgumentParser(
|
|
30
30
|
prog='python -m bracex',
|
|
@@ -193,5 +193,5 @@ def parse_version(ver: str) -> Version:
|
|
|
193
193
|
return Version(major, minor, micro, release, pre, post, dev)
|
|
194
194
|
|
|
195
195
|
|
|
196
|
-
__version_info__ = Version(3, 2,
|
|
196
|
+
__version_info__ = Version(3, 2, 2, "final")
|
|
197
197
|
__version__ = __version_info__._get_canonical()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
API
|
|
2
|
+
Accessors
|
|
3
|
+
Backport
|
|
4
|
+
Bracex
|
|
5
|
+
Changelog
|
|
6
|
+
Formatter
|
|
7
|
+
GitHub
|
|
8
|
+
Gitter
|
|
9
|
+
KiB
|
|
10
|
+
MERCHANTABILITY
|
|
11
|
+
MkDocs
|
|
12
|
+
NONINFRINGEMENT
|
|
13
|
+
NUL
|
|
14
|
+
Preprocess
|
|
15
|
+
PyPI
|
|
16
|
+
Setuptools
|
|
17
|
+
TODO
|
|
18
|
+
Tox
|
|
19
|
+
Twemoji
|
|
20
|
+
Virtualenv
|
|
21
|
+
Willmer
|
|
22
|
+
Zensical
|
|
23
|
+
accessor
|
|
24
|
+
backend
|
|
25
|
+
deprecations
|
|
26
|
+
expander
|
|
27
|
+
formatter
|
|
28
|
+
globbing
|
|
29
|
+
incrementer
|
|
30
|
+
iterables
|
|
31
|
+
linter
|
|
32
|
+
postamble
|
|
33
|
+
pre
|
|
34
|
+
prerelease
|
|
35
|
+
prereleases
|
|
36
|
+
pytest
|
|
37
|
+
regex
|
|
38
|
+
santhreal
|
|
39
|
+
stdout
|
|
40
|
+
sublicense
|
|
41
|
+
tuple
|
|
42
|
+
uncatchable
|
|
43
|
+
validator
|
|
44
|
+
wordlist
|
|
45
|
+
unary
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
+
## 3.2.2
|
|
4
|
+
|
|
5
|
+
- **FIX**: Match Bash 5.3 for groups that contain a top level `..` but are not valid sequences. If the group starts
|
|
6
|
+
like a sequence, such as `{1..3{a,b}}`, it is kept as text without expanding nested groups. If it doesn't, such as
|
|
7
|
+
`{a..x{b}},}`, only the opening `{` is skipped and what follows is parsed again, as in Bash.
|
|
8
|
+
|
|
9
|
+
## 3.2.1
|
|
10
|
+
|
|
11
|
+
- **FIX**: Keep numeric sequences with non-ASCII digits literal, matching Bash.
|
|
12
|
+
- **FIX**: Preserve an initial empty brace group after a valid expansion.
|
|
13
|
+
- **FIX**: Fix `${...}` inside a brace group ending the group early.
|
|
14
|
+
- **FIX**: Fix an invalid sequence such as `{1..a}` being split at a later comma instead of being kept as text.
|
|
15
|
+
- **FIX**: Fix numeric and character sequences with unary `+` signs (`{+1..3}`, `{1..+3..2}`, `{a..z..+2}`)
|
|
16
|
+
being left as literal text instead of expanded like Bash, including Bash's zero-padding rule for `+` operands.
|
|
17
|
+
|
|
3
18
|
## 3.2
|
|
4
19
|
|
|
5
20
|
- **NEW**: Drop Python 3.10 support.
|
|
@@ -40,11 +40,10 @@ include = [
|
|
|
40
40
|
"/docs/src/markdown/**/*.md",
|
|
41
41
|
"/docs/src/markdown/**/*.gif",
|
|
42
42
|
"/docs/src/markdown/**/*.png",
|
|
43
|
-
"/docs/src/
|
|
43
|
+
"/docs/src/dictionary/*.txt",
|
|
44
44
|
"/docs/theme/**/*.css",
|
|
45
45
|
"/docs/theme/**/*.js",
|
|
46
46
|
"/docs/theme/**/*.html",
|
|
47
|
-
"/requirements/*.txt",
|
|
48
47
|
"/bracex/**/*.py",
|
|
49
48
|
"/bracex/py.typed",
|
|
50
49
|
"/tests/**/*.py",
|
|
@@ -53,7 +52,7 @@ include = [
|
|
|
53
52
|
"/tools/**/*.py",
|
|
54
53
|
"/.pyspelling.yml",
|
|
55
54
|
"/.coveragerc",
|
|
56
|
-
"/
|
|
55
|
+
"/zensical.yml"
|
|
57
56
|
]
|
|
58
57
|
|
|
59
58
|
[tool.mypy]
|
|
@@ -289,3 +289,76 @@ a{b},
|
|
|
289
289
|
{a,b{c,d}
|
|
290
290
|
{a,b{
|
|
291
291
|
{2{
|
|
292
|
+
# A top level `..` that is not followed by `}` lets the next `}` end the group
|
|
293
|
+
{1..a},b}
|
|
294
|
+
{a...},c}
|
|
295
|
+
a{1..a},b}c
|
|
296
|
+
{1..a},{b,c}}
|
|
297
|
+
{1..},b}
|
|
298
|
+
# An initial empty group is literal in the postamble after a valid expansion
|
|
299
|
+
{a,b}{},c}
|
|
300
|
+
{1..2}{},c}
|
|
301
|
+
prefix{a,b}{},tail}
|
|
302
|
+
{a,b}x{},c}
|
|
303
|
+
{a,b}{}{},c}
|
|
304
|
+
{word}{},c}
|
|
305
|
+
{a{b,c}}{},d}
|
|
306
|
+
{+1..3}
|
|
307
|
+
{+1..+3}
|
|
308
|
+
{3..+1}
|
|
309
|
+
{+1..+3..2}
|
|
310
|
+
{1..+3..2}
|
|
311
|
+
{+1..+3..+2}
|
|
312
|
+
{+3..1..+2}
|
|
313
|
+
{+05..8}
|
|
314
|
+
{+005..8}
|
|
315
|
+
{05..+8}
|
|
316
|
+
{+5..+08}
|
|
317
|
+
{+05..+05}
|
|
318
|
+
{+05..08}
|
|
319
|
+
{+10..08}
|
|
320
|
+
{-05..+2}
|
|
321
|
+
{+5..05}
|
|
322
|
+
{+5..08}
|
|
323
|
+
{08..+5}
|
|
324
|
+
{+003..1}
|
|
325
|
+
{a..z..+2}
|
|
326
|
+
a{+1..2}b
|
|
327
|
+
{a,{+1..2},b}
|
|
328
|
+
{+9223372036854775806..+9223372036854775807}
|
|
329
|
+
{١..٣}
|
|
330
|
+
{1..3}
|
|
331
|
+
{1..٣}
|
|
332
|
+
{١..3}
|
|
333
|
+
{1..3..٢}
|
|
334
|
+
{a..e..٢}
|
|
335
|
+
{0١..03}
|
|
336
|
+
x{١..٣}y
|
|
337
|
+
{a,{١..٣},b}
|
|
338
|
+
{+١..+٣}
|
|
339
|
+
{-١..٣}
|
|
340
|
+
{1..3{a,b}}
|
|
341
|
+
{1..3{a,b}}x
|
|
342
|
+
x{1..3{a,b}}y{c,d}
|
|
343
|
+
{1..3{a,b}c}
|
|
344
|
+
{1..3{1..3}}
|
|
345
|
+
{a..c{1,2}}
|
|
346
|
+
{1{a,b}..3}
|
|
347
|
+
{a{b,c}..d}
|
|
348
|
+
{1..{a,b}}
|
|
349
|
+
{1..3{a,b},z}
|
|
350
|
+
{{a,b}..c}
|
|
351
|
+
{{1..3}..b}
|
|
352
|
+
x{{1..3}..b}y
|
|
353
|
+
{x{1..3}..y}
|
|
354
|
+
{{1..3}...}
|
|
355
|
+
{{11}..3{1..3}b}
|
|
356
|
+
{{11}..3{1..3}b}z
|
|
357
|
+
{x,{{11}..3{1..3}b}}
|
|
358
|
+
{a..b{c}}x,y}
|
|
359
|
+
{a..x{b}},}
|
|
360
|
+
{..x{b}}1x,}
|
|
361
|
+
{x,{a..x{b}},y}
|
|
362
|
+
{1..3{a,b}}{c,d}
|
|
363
|
+
{a,{b}..c}
|
|
364
|
+
{x,{b}..c,y}
|
|
@@ -1262,4 +1262,175 @@ A{b,{d,e},{f,g}}Z
|
|
|
1262
1262
|
[{a,bc]
|
|
1263
1263
|
[{a,bd]><><><><{a,b{
|
|
1264
1264
|
[{a,b{]><><><><{2{
|
|
1265
|
-
[{2{]><><><><
|
|
1265
|
+
[{2{]><><><><{1..a},b}
|
|
1266
|
+
[{1..a},b}]><><><><{a...},c}
|
|
1267
|
+
[{a...},c}]><><><><a{1..a},b}c
|
|
1268
|
+
[a{1..a},b}c]><><><><{1..a},{b,c}}
|
|
1269
|
+
[{1..a},b}]
|
|
1270
|
+
[{1..a},c}]><><><><{1..},b}
|
|
1271
|
+
[1..}]
|
|
1272
|
+
[b]><><><><{a,b}{},c}
|
|
1273
|
+
[a{},c}]
|
|
1274
|
+
[b{},c}]><><><><{1..2}{},c}
|
|
1275
|
+
[1{},c}]
|
|
1276
|
+
[2{},c}]><><><><prefix{a,b}{},tail}
|
|
1277
|
+
[prefixa{},tail}]
|
|
1278
|
+
[prefixb{},tail}]><><><><{a,b}x{},c}
|
|
1279
|
+
[ax}]
|
|
1280
|
+
[axc]
|
|
1281
|
+
[bx}]
|
|
1282
|
+
[bxc]><><><><{a,b}{}{},c}
|
|
1283
|
+
[a{}}]
|
|
1284
|
+
[a{}c]
|
|
1285
|
+
[b{}}]
|
|
1286
|
+
[b{}c]><><><><{word}{},c}
|
|
1287
|
+
[word}{}]
|
|
1288
|
+
[c]><><><><{a{b,c}}{},d}
|
|
1289
|
+
[ab}{}]
|
|
1290
|
+
[ac}{}]
|
|
1291
|
+
[d]><><><><{+1..3}
|
|
1292
|
+
[1]
|
|
1293
|
+
[2]
|
|
1294
|
+
[3]><><><><{+1..+3}
|
|
1295
|
+
[1]
|
|
1296
|
+
[2]
|
|
1297
|
+
[3]><><><><{3..+1}
|
|
1298
|
+
[3]
|
|
1299
|
+
[2]
|
|
1300
|
+
[1]><><><><{+1..+3..2}
|
|
1301
|
+
[1]
|
|
1302
|
+
[3]><><><><{1..+3..2}
|
|
1303
|
+
[1]
|
|
1304
|
+
[3]><><><><{+1..+3..+2}
|
|
1305
|
+
[1]
|
|
1306
|
+
[3]><><><><{+3..1..+2}
|
|
1307
|
+
[3]
|
|
1308
|
+
[1]><><><><{+05..8}
|
|
1309
|
+
[5]
|
|
1310
|
+
[6]
|
|
1311
|
+
[7]
|
|
1312
|
+
[8]><><><><{+005..8}
|
|
1313
|
+
[5]
|
|
1314
|
+
[6]
|
|
1315
|
+
[7]
|
|
1316
|
+
[8]><><><><{05..+8}
|
|
1317
|
+
[05]
|
|
1318
|
+
[06]
|
|
1319
|
+
[07]
|
|
1320
|
+
[08]><><><><{+5..+08}
|
|
1321
|
+
[5]
|
|
1322
|
+
[6]
|
|
1323
|
+
[7]
|
|
1324
|
+
[8]><><><><{+05..+05}
|
|
1325
|
+
[5]><><><><{+05..08}
|
|
1326
|
+
[005]
|
|
1327
|
+
[006]
|
|
1328
|
+
[007]
|
|
1329
|
+
[008]><><><><{+10..08}
|
|
1330
|
+
[010]
|
|
1331
|
+
[009]
|
|
1332
|
+
[008]><><><><{-05..+2}
|
|
1333
|
+
[-05]
|
|
1334
|
+
[-04]
|
|
1335
|
+
[-03]
|
|
1336
|
+
[-02]
|
|
1337
|
+
[-01]
|
|
1338
|
+
[000]
|
|
1339
|
+
[001]
|
|
1340
|
+
[002]><><><><{+5..05}
|
|
1341
|
+
[05]><><><><{+5..08}
|
|
1342
|
+
[05]
|
|
1343
|
+
[06]
|
|
1344
|
+
[07]
|
|
1345
|
+
[08]><><><><{08..+5}
|
|
1346
|
+
[08]
|
|
1347
|
+
[07]
|
|
1348
|
+
[06]
|
|
1349
|
+
[05]><><><><{+003..1}
|
|
1350
|
+
[3]
|
|
1351
|
+
[2]
|
|
1352
|
+
[1]><><><><{a..z..+2}
|
|
1353
|
+
[a]
|
|
1354
|
+
[c]
|
|
1355
|
+
[e]
|
|
1356
|
+
[g]
|
|
1357
|
+
[i]
|
|
1358
|
+
[k]
|
|
1359
|
+
[m]
|
|
1360
|
+
[o]
|
|
1361
|
+
[q]
|
|
1362
|
+
[s]
|
|
1363
|
+
[u]
|
|
1364
|
+
[w]
|
|
1365
|
+
[y]><><><><a{+1..2}b
|
|
1366
|
+
[a1b]
|
|
1367
|
+
[a2b]><><><><{a,{+1..2},b}
|
|
1368
|
+
[a]
|
|
1369
|
+
[1]
|
|
1370
|
+
[2]
|
|
1371
|
+
[b]><><><><{+9223372036854775806..+9223372036854775807}
|
|
1372
|
+
[9223372036854775806]
|
|
1373
|
+
[9223372036854775807]><><><><{١..٣}
|
|
1374
|
+
[{١..٣}]><><><><{1..3}
|
|
1375
|
+
[{1..3}]><><><><{1..٣}
|
|
1376
|
+
[{1..٣}]><><><><{١..3}
|
|
1377
|
+
[{١..3}]><><><><{1..3..٢}
|
|
1378
|
+
[{1..3..٢}]><><><><{a..e..٢}
|
|
1379
|
+
[{a..e..٢}]><><><><{0١..03}
|
|
1380
|
+
[{0١..03}]><><><><x{١..٣}y
|
|
1381
|
+
[x{١..٣}y]><><><><{a,{١..٣},b}
|
|
1382
|
+
[a]
|
|
1383
|
+
[{١..٣}]
|
|
1384
|
+
[b]><><><><{+١..+٣}
|
|
1385
|
+
[{+١..+٣}]><><><><{-١..٣}
|
|
1386
|
+
[{-١..٣}]><><><><{1..3{a,b}}
|
|
1387
|
+
[{1..3{a,b}}]><><><><{1..3{a,b}}x
|
|
1388
|
+
[{1..3{a,b}}x]><><><><x{1..3{a,b}}y{c,d}
|
|
1389
|
+
[x{1..3{a,b}}yc]
|
|
1390
|
+
[x{1..3{a,b}}yd]><><><><{1..3{a,b}c}
|
|
1391
|
+
[{1..3{a,b}c}]><><><><{1..3{1..3}}
|
|
1392
|
+
[{1..3{1..3}}]><><><><{a..c{1,2}}
|
|
1393
|
+
[{a..c1}]
|
|
1394
|
+
[{a..c2}]><><><><{1{a,b}..3}
|
|
1395
|
+
[{1{a,b}..3}]><><><><{a{b,c}..d}
|
|
1396
|
+
[{ab..d}]
|
|
1397
|
+
[{ac..d}]><><><><{1..{a,b}}
|
|
1398
|
+
[{1..a}]
|
|
1399
|
+
[{1..b}]><><><><{1..3{a,b},z}
|
|
1400
|
+
[1..3a]
|
|
1401
|
+
[1..3b]
|
|
1402
|
+
[z]><><><><{{a,b}..c}
|
|
1403
|
+
[{a..c}]
|
|
1404
|
+
[{b..c}]><><><><{{1..3}..b}
|
|
1405
|
+
[{1..b}]
|
|
1406
|
+
[{2..b}]
|
|
1407
|
+
[{3..b}]><><><><x{{1..3}..b}y
|
|
1408
|
+
[x{1..b}y]
|
|
1409
|
+
[x{2..b}y]
|
|
1410
|
+
[x{3..b}y]><><><><{x{1..3}..y}
|
|
1411
|
+
[{x1..y}]
|
|
1412
|
+
[{x2..y}]
|
|
1413
|
+
[{x3..y}]><><><><{{1..3}...}
|
|
1414
|
+
[{1...}]
|
|
1415
|
+
[{2...}]
|
|
1416
|
+
[{3...}]><><><><{{11}..3{1..3}b}
|
|
1417
|
+
[{{11}..3{1..3}b}]><><><><{{11}..3{1..3}b}z
|
|
1418
|
+
[{{11}..3{1..3}b}z]><><><><{x,{{11}..3{1..3}b}}
|
|
1419
|
+
[x]
|
|
1420
|
+
[{{11}..3{1..3}b}]><><><><{a..b{c}}x,y}
|
|
1421
|
+
[{a..bc}}x]
|
|
1422
|
+
[{a..by]><><><><{a..x{b}},}
|
|
1423
|
+
[{a..xb}}]
|
|
1424
|
+
[{a..x]><><><><{..x{b}}1x,}
|
|
1425
|
+
[{..xb}}1x]
|
|
1426
|
+
[{..x]><><><><{x,{a..x{b}},y}
|
|
1427
|
+
[x]
|
|
1428
|
+
[{a..x{b}}]
|
|
1429
|
+
[y]><><><><{1..3{a,b}}{c,d}
|
|
1430
|
+
[{1..3{a,b}}c]
|
|
1431
|
+
[{1..3{a,b}}d]><><><><{a,{b}..c}
|
|
1432
|
+
[a]
|
|
1433
|
+
[{b}..c]><><><><{x,{b}..c,y}
|
|
1434
|
+
[x]
|
|
1435
|
+
[{b}..c]
|
|
1436
|
+
[y]><><><><
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Bash 5.3 changed how brace groups that look like sequences are validated (invalid candidates are skipped
|
|
6
|
+
# and later braces are still expanded), so results differ from 5.2 and earlier. Generate against 5.3 only.
|
|
7
|
+
if [[ "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}" != "5.3" ]]; then
|
|
8
|
+
echo "this script requires bash 5.3" >&2
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
CDPATH= cd "$(dirname "$0")"
|
|
13
|
+
|
|
14
|
+
cat brace-cases.txt | \
|
|
15
|
+
while read case; do
|
|
16
|
+
if [ "${case:0:1}" = "#" ]; then
|
|
17
|
+
continue;
|
|
18
|
+
fi;
|
|
19
|
+
b="$($BASH -c 'for c in '"$case"'; do echo "[$c]"; done')"
|
|
20
|
+
echo "$case"
|
|
21
|
+
echo -n "$b><><><><";
|
|
22
|
+
done > brace-results.txt
|
|
@@ -50,7 +50,18 @@ class TestBraces:
|
|
|
50
50
|
dollar_cases = [
|
|
51
51
|
['${1..3}', ['${1..3}']],
|
|
52
52
|
['${a,b}${c,d}', ['${a,b}${c,d}']],
|
|
53
|
-
['x${a,b}x${c,d}x', ['x${a,b}x${c,d}x']]
|
|
53
|
+
['x${a,b}x${c,d}x', ['x${a,b}x${c,d}x']],
|
|
54
|
+
['{a,${b}}', ['a', '${b}']],
|
|
55
|
+
['{${a,b},c}', ['${a,b}', 'c']],
|
|
56
|
+
['{a,${b{c}d}e}', ['a', '${b{c}d}e']],
|
|
57
|
+
[r'{a,${b\}c}}', ['a', '${b}c}']],
|
|
58
|
+
['${x{1..2}}', ['${x1}', '${x2}']],
|
|
59
|
+
['${x{a,b}}', ['${xa}', '${xb}']],
|
|
60
|
+
['{a,${x{1..2}}}', ['a', '${x1}', '${x2}']],
|
|
61
|
+
['{a,${x{c,d}}}', ['a', '${xc}', '${xd}']],
|
|
62
|
+
['x${y{a,b}}z', ['x${ya}z', 'x${yb}z']],
|
|
63
|
+
['q{b}${b,c}z', ['q{b}${b,c}z']],
|
|
64
|
+
['{a${x:-..b}},c}', ['a${x:-..b}}', 'c']]
|
|
54
65
|
]
|
|
55
66
|
|
|
56
67
|
empty_cases = [
|
|
@@ -72,7 +83,13 @@ class TestBraces:
|
|
|
72
83
|
nested_cases = [
|
|
73
84
|
['{a,b{1..3},c}', ['a', 'b1', 'b2', 'b3', 'c']],
|
|
74
85
|
['{{A..Z},{a..z}}', list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')],
|
|
75
|
-
['ppp{,config,oe{,conf}}', ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']]
|
|
86
|
+
['ppp{,config,oe{,conf}}', ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']],
|
|
87
|
+
# Bash keeps a group that starts like a sequence as text, nested groups included
|
|
88
|
+
['{1..3{a,b}}', ['{1..3{a,b}}']],
|
|
89
|
+
['x{1..3{a,b}}y{c,d}', ['x{1..3{a,b}}yc', 'x{1..3{a,b}}yd']],
|
|
90
|
+
['{1..3{a,b\\}}}', ['{1..3{a,b}}}']],
|
|
91
|
+
# But if it doesn't even start like a sequence, nested groups still expand
|
|
92
|
+
['{1..{a,b}}', ['{1..a}', '{1..b}']]
|
|
76
93
|
]
|
|
77
94
|
|
|
78
95
|
order_cases = [
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
site_name: Bracex
|
|
2
|
+
site_url: https://facelessuser.github.io/bracex
|
|
3
|
+
repo_url: https://github.com/facelessuser/bracex
|
|
4
|
+
edit_uri: tree/master/docs/src/markdown
|
|
5
|
+
site_description: Python spell checker.
|
|
6
|
+
copyright: |
|
|
7
|
+
Copyright © 2018 - 2026 <a href="https://github.com/facelessuser" target="_blank" rel="noopener">Isaac Muse</a>
|
|
8
|
+
|
|
9
|
+
docs_dir: docs/src/markdown
|
|
10
|
+
theme:
|
|
11
|
+
name: zensical_pymdownx
|
|
12
|
+
custom_dir: docs/theme
|
|
13
|
+
features:
|
|
14
|
+
- announce.dismiss
|
|
15
|
+
- navigation.tabs
|
|
16
|
+
- navigation.top
|
|
17
|
+
- navigation.instant
|
|
18
|
+
- navigation.indexes
|
|
19
|
+
- navigation.path
|
|
20
|
+
- navigation.footer
|
|
21
|
+
- toc.follow
|
|
22
|
+
- content.tabs.link
|
|
23
|
+
- search.share
|
|
24
|
+
- search.highlight
|
|
25
|
+
- search.suggest
|
|
26
|
+
- content.code.copy
|
|
27
|
+
- content.tabs.link
|
|
28
|
+
- content.code.annotations
|
|
29
|
+
|
|
30
|
+
nav:
|
|
31
|
+
- Home:
|
|
32
|
+
- Usage: index.md
|
|
33
|
+
- About:
|
|
34
|
+
- Contributing & Support: about/contributing.md
|
|
35
|
+
- Development: about/development.md
|
|
36
|
+
- Changelog: about/changelog.md
|
|
37
|
+
- License: about/license.md
|
|
38
|
+
|
|
39
|
+
markdown_extensions:
|
|
40
|
+
- toc:
|
|
41
|
+
slugify: !!python/object/apply:pymdownx.slugs.slugify {kwds: {case: lower}}
|
|
42
|
+
permalink: ""
|
|
43
|
+
- smarty:
|
|
44
|
+
smart_quotes: false
|
|
45
|
+
- pymdownx.betterem:
|
|
46
|
+
- attr_list:
|
|
47
|
+
- tables:
|
|
48
|
+
- abbr:
|
|
49
|
+
- footnotes:
|
|
50
|
+
- md_in_html:
|
|
51
|
+
- pymdownx.superfences:
|
|
52
|
+
preserve_tabs: true
|
|
53
|
+
relaxed_headers: true
|
|
54
|
+
custom_fences:
|
|
55
|
+
- name: py
|
|
56
|
+
class: 'highlight'
|
|
57
|
+
format: !!python/object/apply:tools.pycon.py_command_formatter
|
|
58
|
+
kwds:
|
|
59
|
+
init: |
|
|
60
|
+
import bracex
|
|
61
|
+
validator: !!python/name:tools.pycon.py_command_validator
|
|
62
|
+
reset: !!python/name:tools.pycon.py_command_reset
|
|
63
|
+
- name: python
|
|
64
|
+
class: 'highlight'
|
|
65
|
+
format: !!python/object/apply:tools.pycon.py_command_formatter
|
|
66
|
+
kwds:
|
|
67
|
+
init: |
|
|
68
|
+
import bracex
|
|
69
|
+
validator: !!python/name:tools.pycon.py_command_validator
|
|
70
|
+
reset: !!python/name:tools.pycon.py_command_reset
|
|
71
|
+
- pymdownx.highlight:
|
|
72
|
+
line_spans: __codeline
|
|
73
|
+
line_anchors: __codelineno
|
|
74
|
+
anchor_linenums: True
|
|
75
|
+
- pymdownx.inlinehilite:
|
|
76
|
+
- pymdownx.magiclink:
|
|
77
|
+
repo_url_shortener: true
|
|
78
|
+
repo_url_shorthand: true
|
|
79
|
+
social_url_shorthand: true
|
|
80
|
+
user: facelessuser
|
|
81
|
+
repo: bracex
|
|
82
|
+
- pymdownx.tilde:
|
|
83
|
+
- pymdownx.caret:
|
|
84
|
+
- pymdownx.smartsymbols:
|
|
85
|
+
- pymdownx.emoji:
|
|
86
|
+
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
|
87
|
+
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
|
88
|
+
- pymdownx.escapeall:
|
|
89
|
+
hardbreak: True
|
|
90
|
+
nbsp: True
|
|
91
|
+
- pymdownx.tasklist:
|
|
92
|
+
custom_checkbox: true
|
|
93
|
+
- pymdownx.progressbar:
|
|
94
|
+
- pymdownx.striphtml:
|
|
95
|
+
- pymdownx.snippets:
|
|
96
|
+
base_path:
|
|
97
|
+
- docs/src/markdown/.snippets
|
|
98
|
+
- LICENSE.md
|
|
99
|
+
auto_append:
|
|
100
|
+
- refs.md
|
|
101
|
+
- pymdownx.keys:
|
|
102
|
+
separator: "\uff0b"
|
|
103
|
+
- pymdownx.saneheaders:
|
|
104
|
+
- pymdownx.blocks.admonition:
|
|
105
|
+
types:
|
|
106
|
+
- new
|
|
107
|
+
- settings
|
|
108
|
+
- note
|
|
109
|
+
- abstract
|
|
110
|
+
- info
|
|
111
|
+
- tip
|
|
112
|
+
- success
|
|
113
|
+
- question
|
|
114
|
+
- warning
|
|
115
|
+
- failure
|
|
116
|
+
- danger
|
|
117
|
+
- bug
|
|
118
|
+
- example
|
|
119
|
+
- quote
|
|
120
|
+
- pymdownx.blocks.details:
|
|
121
|
+
types:
|
|
122
|
+
- name: details-new
|
|
123
|
+
class: new
|
|
124
|
+
- name: details-settings
|
|
125
|
+
class: settings
|
|
126
|
+
- name: details-note
|
|
127
|
+
class: note
|
|
128
|
+
- name: details-abstract
|
|
129
|
+
class: abstract
|
|
130
|
+
- name: details-info
|
|
131
|
+
class: info
|
|
132
|
+
- name: details-tip
|
|
133
|
+
class: tip
|
|
134
|
+
- name: details-success
|
|
135
|
+
class: success
|
|
136
|
+
- name: details-question
|
|
137
|
+
class: question
|
|
138
|
+
- name: details-warning
|
|
139
|
+
class: warning
|
|
140
|
+
- name: details-failure
|
|
141
|
+
class: failure
|
|
142
|
+
- name: details-danger
|
|
143
|
+
class: danger
|
|
144
|
+
- name: details-bug
|
|
145
|
+
class: bug
|
|
146
|
+
- name: details-example
|
|
147
|
+
class: example
|
|
148
|
+
- name: details-quote
|
|
149
|
+
class: quote
|
|
150
|
+
- pymdownx.blocks.html:
|
|
151
|
+
- pymdownx.blocks.definition:
|
|
152
|
+
- pymdownx.blocks.tab:
|
|
153
|
+
alternate_style: True
|
|
154
|
+
combine_header_slug: True
|
|
155
|
+
slugify: !!python/object/apply:pymdownx.slugs.slugify {kwds: {case: lower}}
|
|
156
|
+
- pymdownx.quotes:
|
|
157
|
+
callouts: true
|
|
158
|
+
|
|
159
|
+
extra:
|
|
160
|
+
social:
|
|
161
|
+
- icon: fontawesome/brands/github
|
|
162
|
+
link: https://github.com/facelessuser
|
|
163
|
+
zensical_pymdownx:
|
|
164
|
+
sponsor: https://github.com/sponsors/facelessuser
|
bracex-3.2/tests/generate.sh
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
# Bash 4.3 - 5.0 because of arbitrary need to pick a single standard.
|
|
6
|
-
if ! [[ "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}" =~ (4\.[^1-2]|5\.[0-3])(\.\d+)? ]]; then
|
|
7
|
-
echo "this script requires bash 4.3, 4.4, or 5.0" >&2
|
|
8
|
-
exit 1
|
|
9
|
-
fi
|
|
10
|
-
|
|
11
|
-
CDPATH= cd "$(dirname "$0")"
|
|
12
|
-
|
|
13
|
-
cat brace-cases.txt | \
|
|
14
|
-
while read case; do
|
|
15
|
-
if [ "${case:0:1}" = "#" ]; then
|
|
16
|
-
continue;
|
|
17
|
-
fi;
|
|
18
|
-
b="$($BASH -c 'for c in '"$case"'; do echo "[$c]"; done')"
|
|
19
|
-
echo "$case"
|
|
20
|
-
echo -n "$b><><><><";
|
|
21
|
-
done > brace-results.txt
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|