##// END OF EJS Templates
parselist: move the function from config to stringutil...
marmoute -
r47960:b0e92313 default
parent child Browse files
Show More
@@ -258,93 +258,3 b' class config(object):'
258 self.parse(
258 self.parse(
259 path, fp.read(), sections=sections, remap=remap, include=include
259 path, fp.read(), sections=sections, remap=remap, include=include
260 )
260 )
261
262
263 def parselist(value):
264 """parse a configuration value as a list of comma/space separated strings
265
266 >>> parselist(b'this,is "a small" ,test')
267 ['this', 'is', 'a small', 'test']
268 """
269
270 def _parse_plain(parts, s, offset):
271 whitespace = False
272 while offset < len(s) and (
273 s[offset : offset + 1].isspace() or s[offset : offset + 1] == b','
274 ):
275 whitespace = True
276 offset += 1
277 if offset >= len(s):
278 return None, parts, offset
279 if whitespace:
280 parts.append(b'')
281 if s[offset : offset + 1] == b'"' and not parts[-1]:
282 return _parse_quote, parts, offset + 1
283 elif s[offset : offset + 1] == b'"' and parts[-1][-1:] == b'\\':
284 parts[-1] = parts[-1][:-1] + s[offset : offset + 1]
285 return _parse_plain, parts, offset + 1
286 parts[-1] += s[offset : offset + 1]
287 return _parse_plain, parts, offset + 1
288
289 def _parse_quote(parts, s, offset):
290 if offset < len(s) and s[offset : offset + 1] == b'"': # ""
291 parts.append(b'')
292 offset += 1
293 while offset < len(s) and (
294 s[offset : offset + 1].isspace()
295 or s[offset : offset + 1] == b','
296 ):
297 offset += 1
298 return _parse_plain, parts, offset
299
300 while offset < len(s) and s[offset : offset + 1] != b'"':
301 if (
302 s[offset : offset + 1] == b'\\'
303 and offset + 1 < len(s)
304 and s[offset + 1 : offset + 2] == b'"'
305 ):
306 offset += 1
307 parts[-1] += b'"'
308 else:
309 parts[-1] += s[offset : offset + 1]
310 offset += 1
311
312 if offset >= len(s):
313 real_parts = _configlist(parts[-1])
314 if not real_parts:
315 parts[-1] = b'"'
316 else:
317 real_parts[0] = b'"' + real_parts[0]
318 parts = parts[:-1]
319 parts.extend(real_parts)
320 return None, parts, offset
321
322 offset += 1
323 while offset < len(s) and s[offset : offset + 1] in [b' ', b',']:
324 offset += 1
325
326 if offset < len(s):
327 if offset + 1 == len(s) and s[offset : offset + 1] == b'"':
328 parts[-1] += b'"'
329 offset += 1
330 else:
331 parts.append(b'')
332 else:
333 return None, parts, offset
334
335 return _parse_plain, parts, offset
336
337 def _configlist(s):
338 s = s.rstrip(b' ,')
339 if not s:
340 return []
341 parser, parts, offset = _parse_plain, [b''], 0
342 while parser:
343 parser, parts, offset = parser(parts, s, offset)
344 return parts
345
346 if value is not None and isinstance(value, bytes):
347 result = _configlist(value.lstrip(b' ,\n'))
348 else:
349 result = value
350 return result or []
@@ -887,10 +887,10 b' class ui(object):'
887 """
887 """
888 # default is not always a list
888 # default is not always a list
889 v = self.configwith(
889 v = self.configwith(
890 config.parselist, section, name, default, b'list', untrusted
890 stringutil.parselist, section, name, default, b'list', untrusted
891 )
891 )
892 if isinstance(v, bytes):
892 if isinstance(v, bytes):
893 return config.parselist(v)
893 return stringutil.parselist(v)
894 elif v is None:
894 elif v is None:
895 return []
895 return []
896 return v
896 return v
@@ -868,6 +868,96 b' def parsebool(s):'
868 return _booleans.get(s.lower(), None)
868 return _booleans.get(s.lower(), None)
869
869
870
870
871 def parselist(value):
872 """parse a configuration value as a list of comma/space separated strings
873
874 >>> parselist(b'this,is "a small" ,test')
875 ['this', 'is', 'a small', 'test']
876 """
877
878 def _parse_plain(parts, s, offset):
879 whitespace = False
880 while offset < len(s) and (
881 s[offset : offset + 1].isspace() or s[offset : offset + 1] == b','
882 ):
883 whitespace = True
884 offset += 1
885 if offset >= len(s):
886 return None, parts, offset
887 if whitespace:
888 parts.append(b'')
889 if s[offset : offset + 1] == b'"' and not parts[-1]:
890 return _parse_quote, parts, offset + 1
891 elif s[offset : offset + 1] == b'"' and parts[-1][-1:] == b'\\':
892 parts[-1] = parts[-1][:-1] + s[offset : offset + 1]
893 return _parse_plain, parts, offset + 1
894 parts[-1] += s[offset : offset + 1]
895 return _parse_plain, parts, offset + 1
896
897 def _parse_quote(parts, s, offset):
898 if offset < len(s) and s[offset : offset + 1] == b'"': # ""
899 parts.append(b'')
900 offset += 1
901 while offset < len(s) and (
902 s[offset : offset + 1].isspace()
903 or s[offset : offset + 1] == b','
904 ):
905 offset += 1
906 return _parse_plain, parts, offset
907
908 while offset < len(s) and s[offset : offset + 1] != b'"':
909 if (
910 s[offset : offset + 1] == b'\\'
911 and offset + 1 < len(s)
912 and s[offset + 1 : offset + 2] == b'"'
913 ):
914 offset += 1
915 parts[-1] += b'"'
916 else:
917 parts[-1] += s[offset : offset + 1]
918 offset += 1
919
920 if offset >= len(s):
921 real_parts = _configlist(parts[-1])
922 if not real_parts:
923 parts[-1] = b'"'
924 else:
925 real_parts[0] = b'"' + real_parts[0]
926 parts = parts[:-1]
927 parts.extend(real_parts)
928 return None, parts, offset
929
930 offset += 1
931 while offset < len(s) and s[offset : offset + 1] in [b' ', b',']:
932 offset += 1
933
934 if offset < len(s):
935 if offset + 1 == len(s) and s[offset : offset + 1] == b'"':
936 parts[-1] += b'"'
937 offset += 1
938 else:
939 parts.append(b'')
940 else:
941 return None, parts, offset
942
943 return _parse_plain, parts, offset
944
945 def _configlist(s):
946 s = s.rstrip(b' ,')
947 if not s:
948 return []
949 parser, parts, offset = _parse_plain, [b''], 0
950 while parser:
951 parser, parts, offset = parser(parts, s, offset)
952 return parts
953
954 if value is not None and isinstance(value, bytes):
955 result = _configlist(value.lstrip(b' ,\n'))
956 else:
957 result = value
958 return result or []
959
960
871 def evalpythonliteral(s):
961 def evalpythonliteral(s):
872 """Evaluate a string containing a Python literal expression"""
962 """Evaluate a string containing a Python literal expression"""
873 # We could backport our tokenizer hack to rewrite '' to u'' if we want
963 # We could backport our tokenizer hack to rewrite '' to u'' if we want
@@ -361,10 +361,11 b' impl Config {'
361 ///
361 ///
362 /// This is appropriate for new configuration keys. The value syntax is
362 /// This is appropriate for new configuration keys. The value syntax is
363 /// **not** the same as most existing list-valued config, which has Python
363 /// **not** the same as most existing list-valued config, which has Python
364 /// parsing implemented in `parselist()` in `mercurial/config.py`.
364 /// parsing implemented in `parselist()` in
365 /// Faithfully porting that parsing algorithm to Rust (including behavior
365 /// `mercurial/utils/stringutil.py`. Faithfully porting that parsing
366 /// that are arguably bugs) turned out to be non-trivial and hasn’t been
366 /// algorithm to Rust (including behavior that are arguably bugs)
367 /// completed as of this writing.
367 /// turned out to be non-trivial and hasn’t been completed as of this
368 /// writing.
368 ///
369 ///
369 /// Instead, the "simple" syntax is: split on comma, then trim leading and
370 /// Instead, the "simple" syntax is: split on comma, then trim leading and
370 /// trailing whitespace of each component. Quotes or backslashes are not
371 /// trailing whitespace of each component. Quotes or backslashes are not
@@ -131,7 +131,6 b' expected_mods_tested = set('
131 ('mercurial.changelog', '{}'),
131 ('mercurial.changelog', '{}'),
132 ('mercurial.cmdutil', '{}'),
132 ('mercurial.cmdutil', '{}'),
133 ('mercurial.color', '{}'),
133 ('mercurial.color', '{}'),
134 ('mercurial.config', '{}'),
135 ('mercurial.dagparser', "{'optionflags': 4}"),
134 ('mercurial.dagparser', "{'optionflags': 4}"),
136 ('mercurial.encoding', '{}'),
135 ('mercurial.encoding', '{}'),
137 ('mercurial.fancyopts', '{}'),
136 ('mercurial.fancyopts', '{}'),
General Comments 0
You need to be logged in to leave comments. Login now