| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent cf43820 commit 452878f
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -511,6 +511,24 @@ def is_line_continuation(value: str) -> bool: | |||
| 511 | 511 | return False | |
| 512 | 512 | return escaped | |
| 513 | 513 | ||
| 514 | + def strip_inline_comment(value: str) -> str: | ||
| 515 | + """Cut an unquoted ``#`` or ``;`` comment, as git's ``parse_value`` does. | ||
| 516 | + | ||
| 517 | + Quoting and backslash escapes are honoured, so a ``#`` inside a quoted | ||
| 518 | + value is literal and an unterminated quote swallows the rest of the line. | ||
| 519 | + """ | ||
| 520 | + quoted = escaped = False | ||
| 521 | + for index, char in enumerate(value): | ||
| 522 | + if escaped: | ||
| 523 | + escaped = False | ||
| 524 | + elif char == "\\": | ||
| 525 | + escaped = True | ||
| 526 | + elif char == '"': | ||
| 527 | + quoted = not quoted | ||
| 528 | + elif char in "#;" and not quoted: | ||
| 529 | + return value[:index] | ||
| 530 | + return value | ||
| 531 | + | ||
| 514 | 532 | def parse_value(value: str) -> str: | |
| 515 | 533 | parsed: List[str] = [] | |
| 516 | 534 | whitespace: List[str] = [] | |
@@ -575,11 +593,7 @@ def parse_value(value: str) -> str: | |||
| 575 | 593 | optname, vi, optval = mo.group("option", "vi", "value") | |
| 576 | 594 | optname = self.optionxform(optname.rstrip()) | |
| 577 | 595 | ||
| 578 | - if vi in ("=", ":") and ";" in optval and not optval.strip().startswith('"'): | ||
| 579 | - pos = optval.find(";") | ||
| 580 | - if pos != -1 and optval[pos - 1].isspace(): | ||
| 581 | - optval = optval[:pos] | ||
| 582 | - optval = optval.strip() | ||
| 596 | + optval = strip_inline_comment(optval).strip() | ||
| 583 | 597 | ||
| 584 | 598 | if len(optval) < 2 or optval[0] != '"': | |
| 585 | 599 | # Does not open quoting. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,6 +239,29 @@ def test_multi_line_config(self): | |||
| 239 | 239 | ) | |
| 240 | 240 | self.assertEqual(len(config.sections()), 23) | |
| 241 | 241 | ||
| 242 | + def test_inline_comments_are_stripped_like_git(self): | ||
| 243 | + """A `#` or `;` outside quotes starts a comment, with or without a space | ||
| 244 | + before it, and whether or not the value is quoted. Expectations are what | ||
| 245 | + `git config -f <file> --get a.k` prints on git 2.50.1.""" | ||
| 246 | + cases = [ | ||
| 247 | + (b"[a]\n\tk = value # comment\n", "value"), | ||
| 248 | + (b"[a]\n\tk = value ; comment\n", "value"), | ||
| 249 | + (b"[a]\n\tk = value#nospace\n", "value"), | ||
| 250 | + (b"[a]\n\tk = value;nospace\n", "value"), | ||
| 251 | + (b"[a]\n\tk = a # b ; c\n", "a"), | ||
| 252 | + (b'[a]\n\tk = "quoted" # after\n', "quoted"), | ||
| 253 | + # A comment character inside quotes is literal. | ||
| 254 | + (b'[a]\n\tk = "has # inside"\n', "has # inside"), | ||
| 255 | + (b'[a]\n\tk = "has ; inside"\n', "has ; inside"), | ||
| 256 | + ] | ||
| 257 | + for content, expected in cases: | ||
| 258 | + config_file = io.BytesIO(content) | ||
| 259 | + config_file.name = "inline_comment.config" | ||
| 260 | + config = GitConfigParser(config_file) | ||
| 261 | + config.read() | ||
| 262 | + with self.subTest(content=content): | ||
| 263 | + self.assertEqual(config.get_value("a", "k"), expected) | ||
| 264 | + | ||
| 242 | 265 | def test_backslash_line_continuation(self): | |
| 243 | 266 | """An unquoted value ending in a backslash continues on the next line, | |
| 244 | 267 | exactly as git config parses it: the final backslash and the newline | |
| Back | FazBrowse Home | New Git URL |
0 commit comments