mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Formula autocomplete improvements for references and lookups
Summary: Makes the following improvements to formula autocomplete: - When a user types `$RefCol` (or part of it), also show `$RefCol.VisibleCol` (replace actual column names) in the autocomplete even before the `.` is typed, to help users understand the difference between a raw reference/record and its visible column. - When a user types a table name, show `.lookupOne` and `.lookupRecords` in the autocomplete, again even before the `.` is typed. - For `.lookupRecords(` and `.lookupOne(`, once the `(` is entered, suggest each column name as a keyword argument. - Also suggest lookup arguments involving compatible reference columns, especially 'reverse reference' lookups like `refcol=$id` which are very common and difficult for users. - To support these features, the Ace editor autocomplete needs some patching to fetch fresh autocomplete options after typing `.` or `(`. This also improves unrelated behaviour that wasn't great before when one column name is contained in another. See the first added browser test. Discussions: - https://grist.slack.com/archives/CDHABLZJT/p1659707068383179 - https://grist.quip.com/HoSmAlvFax0j#MbTADAH5kgG - https://grist.quip.com/HoSmAlvFax0j/Formula-Improvements#temp:C:MbT3649fe964a184e8dada9bbebb Test Plan: Added Python and nbrowser tests. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3580
This commit is contained in:
@@ -19,7 +19,7 @@ from sortedcontainers import SortedSet
|
||||
import acl
|
||||
import actions
|
||||
import action_obj
|
||||
from autocomplete_context import AutocompleteContext
|
||||
from autocomplete_context import AutocompleteContext, lookup_autocomplete_options
|
||||
from codebuilder import DOLLAR_REGEX
|
||||
import depend
|
||||
import docactions
|
||||
@@ -1418,12 +1418,33 @@ class Engine(object):
|
||||
"""
|
||||
Return a list of suggested completions of the python fragment supplied.
|
||||
"""
|
||||
table = self.tables[table_id]
|
||||
|
||||
# Table.lookup methods are special to suggest arguments after '('
|
||||
match = re.match(r"(\w+)\.(lookupRecords|lookupOne)\($", txt)
|
||||
if match:
|
||||
# Get the 'Table1' in 'Table1.lookupRecords('
|
||||
lookup_table_id = match.group(1)
|
||||
if lookup_table_id in self.tables:
|
||||
lookup_table = self.tables[lookup_table_id]
|
||||
# Add a keyword argument with no value for each column name in the lookup table.
|
||||
result = [
|
||||
txt + col_id + "="
|
||||
for col_id in lookup_table.all_columns
|
||||
if column.is_user_column(col_id) or col_id == 'id'
|
||||
]
|
||||
# Add specific complete lookups involving reference columns.
|
||||
result += [
|
||||
txt + option
|
||||
for option in lookup_autocomplete_options(lookup_table, table, reverse_only=False)
|
||||
]
|
||||
return sorted(result)
|
||||
|
||||
# replace $ with rec. and add a dummy rec object
|
||||
tweaked_txt = DOLLAR_REGEX.sub(r'rec.', txt)
|
||||
# convert a bare $ with nothing after it also
|
||||
if txt == '$':
|
||||
tweaked_txt = 'rec.'
|
||||
table = self.tables[table_id]
|
||||
|
||||
autocomplete_context = self.autocomplete_context
|
||||
context = autocomplete_context.get_context()
|
||||
@@ -1433,10 +1454,10 @@ class Engine(object):
|
||||
context.pop('value', None)
|
||||
context.pop('user', None)
|
||||
|
||||
column = table.get_column(column_id) if table.has_column(column_id) else None
|
||||
if column and not column.is_formula():
|
||||
col = table.get_column(column_id) if table.has_column(column_id) else None
|
||||
if col and not col.is_formula():
|
||||
# Add trigger formula completions.
|
||||
context['value'] = column.sample_value()
|
||||
context['value'] = col.sample_value()
|
||||
context['user'] = User(user, self.tables, is_sample=True)
|
||||
|
||||
completer = rlcompleter.Completer(context)
|
||||
@@ -1450,7 +1471,19 @@ class Engine(object):
|
||||
break
|
||||
if skipped_completions.search(result):
|
||||
continue
|
||||
results.append(autocomplete_context.process_result(result))
|
||||
result = autocomplete_context.process_result(result)
|
||||
results.append(result)
|
||||
funcname = result[0]
|
||||
# Suggest reverse reference lookups, specifically only for .lookupRecords(),
|
||||
# not for .lookupOne().
|
||||
if isinstance(result, tuple) and funcname.endswith(".lookupRecords"):
|
||||
lookup_table_id = funcname.split(".")[0]
|
||||
if lookup_table_id in self.tables:
|
||||
lookup_table = self.tables[lookup_table_id]
|
||||
results += [
|
||||
funcname + "(" + option
|
||||
for option in lookup_autocomplete_options(lookup_table, table, reverse_only=True)
|
||||
]
|
||||
|
||||
# If we changed the prefix (expanding the $ symbol) we now need to change it back.
|
||||
if tweaked_txt != txt:
|
||||
|
||||
Reference in New Issue
Block a user