Skip to content

Commit 48c6a17

Browse files
committed
Rewrite value parsing from comments
- Consider values wrapped in backticks and parse them as JSON - Smarter type detection for completion hints - Don't suggest non-string values within a string
1 parent 593e84d commit 48c6a17

File tree

1 file changed

+66
-35
lines changed

1 file changed

+66
-35
lines changed

settings.py

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ def sorted_completions(completions):
108108
return list(sorted(completions, key=lambda x: x[0].lower()))
109109

110110

111+
def int_or_float(string):
112+
try:
113+
return int(string)
114+
except ValueError:
115+
return float(string)
116+
117+
111118
def _settings():
112119
return sublime.load_settings("PackageDev.sublime-settings")
113120

@@ -601,9 +608,7 @@ def value_completions(self, view, prefix, locations):
601608
typed_region = sublime.Region(value_region.begin(), point)
602609
typed = view.substr(typed_region).lstrip()
603610
# try to built the list of completions from setting's comment
604-
completions = list(
605-
self._completions_from_comment(view, key, default, typed, prefix)
606-
)
611+
completions = self._completions_from_comment(view, key)
607612

608613
if not completions:
609614
if isinstance(default, bool):
@@ -614,7 +619,7 @@ def value_completions(self, view, prefix, locations):
614619
completions[default][0] += " (default)" # booleans are integers
615620
elif default:
616621
completions = [(
617-
'{0} \tdefault'.format(default),
622+
"{} \t{} (default)".format(default, type(default).__name__),
618623
default
619624
)]
620625

@@ -628,16 +633,31 @@ def value_completions(self, view, prefix, locations):
628633
)
629634
# cursor already within quotes
630635
in_str = view.match_selector(point, 'string')
631-
l.debug("Completing a string (%s) within a string (%s)", is_str, in_str)
636+
l.debug("completing a string (%s) within a string (%s)", is_str, in_str)
632637

633638
if not in_str or not is_str:
634639
# jsonify completion values
635-
completions = [(trigger, sublime.encode_value(value))
636-
for trigger, value in completions]
640+
completions_tmp = []
641+
for trigger, value in completions:
642+
if isinstance(value, float):
643+
# strip already typed text from float completions
644+
# because ST cannot complete past word boundaries
645+
# (e.g. strip `1.` of `1.234`)
646+
value_str = str(value)
647+
if value_str.startswith(typed):
648+
offset = len(typed) - len(prefix)
649+
completions.append((
650+
'{0}\tfloat'.format(value),
651+
value_str[offset:]
652+
))
653+
else:
654+
completions_tmp.append((trigger, sublime.encode_value(value)))
655+
completions = completions_tmp
637656
elif is_str and in_str:
638-
# stringify values, just to be safe. Don't need quotation marks
639-
completions = [(trigger, str(value))
640-
for trigger, value in completions]
657+
# Strip completions of non-strings. Don't need quotation marks.
658+
completions = [(trigger, value)
659+
for trigger, value in completions
660+
if isinstance(value, str)]
641661
else:
642662
# We're within a string but don't have a string value to complete.
643663
# Complain about this in the status bar, I guess.
@@ -649,8 +669,8 @@ def value_completions(self, view, prefix, locations):
649669
# disable word completion to prevent stupid suggestions
650670
return sorted_completions(completions), sublime.INHIBIT_WORD_COMPLETIONS
651671

652-
def _completions_from_comment(self, view, key, default, typed, prefix):
653-
"""Parse settings comments and return all possible values (generator).
672+
def _completions_from_comment(self, view, key):
673+
"""Parse settings comments and return all possible values.
654674
655675
Many settings are commented with a list of quoted words representing
656676
the possible / allowed values. This method generates a list of these
@@ -661,35 +681,46 @@ def _completions_from_comment(self, view, key, default, typed, prefix):
661681
the view to provide completions for
662682
key (string):
663683
the settings key name to read comments from
664-
default (any):
665-
the default value of key
666-
typed (string):
667-
the value entered so far, which may differ from prefix if
668-
user entered floating point numbers
669-
prefix (string):
670-
the completion prefix provided by ST.
671684
672685
Yields:
673686
list: [trigger, contents]
674687
The list representing one auto-completion item.
675688
"""
676-
is_float = isinstance(default, float)
677-
678-
# TODO try backtick "quotes" first (less frequently used but more precise)
679-
for match in re.finditer('"([\.\w]+)"', self.comments.get(key, '')):
680-
word, = match.groups()
681-
if is_float:
682-
# provide completions for numbers which match the already
683-
# entered value
684-
if word.startswith(typed):
685-
# strip already entered '1.' from completions as ST doesn't
686-
offset = len(typed) - len(prefix)
687-
yield ('{0} \tnumber'.format(word), word[offset:])
689+
comment = self.comments.get(key, '')
690+
if not comment:
691+
return
692+
693+
# must use list because "lists" as values are not hashable
694+
values = []
695+
for match in re.finditer('`([^`\n]+)`', comment):
696+
# backticks should wrap the value in JSON representation,
697+
# so we try to decode it
698+
value_str, = match.groups()
699+
try:
700+
value = sublime.decode_value(value_str)
701+
except:
702+
value = value_str
703+
values.append(value)
704+
705+
for match in re.finditer('"([\.\w]+)"', comment):
706+
# quotation marks either wrap a string, a numeric or a boolean
707+
# fall back to a str
708+
value, = match.groups()
709+
if value == 'true':
710+
value = True
711+
elif value == 'false':
712+
value = False
688713
else:
689-
yield (
690-
'{0} \tstring'.format(word),
691-
word
692-
)
714+
try:
715+
value = int_or_float(value)
716+
except ValueError:
717+
pass # just use the string
718+
values.append(value)
719+
720+
completions = [("{} \t{}".format(value, type(value).__name__), value)
721+
for value in values]
722+
l.debug("compl %r", completions)
723+
return sorted_completions(completions)
693724

694725
@staticmethod
695726
def _color_scheme_completions(view):

0 commit comments

Comments
 (0)