mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
completions: Add completions for response IDs
This commit is contained in:
parent
866092ccf7
commit
b26433d865
16 changed files with 123 additions and 42 deletions
|
@ -76,7 +76,11 @@ def complete(
|
||||||
next_token = tokens[next_token_idx]
|
next_token = tokens[next_token_idx]
|
||||||
|
|
||||||
# if the current token is an identifier or whitespace, move to the token before it
|
# if the current token is an identifier or whitespace, move to the token before it
|
||||||
while tokens[token_idx].type in [TokenType.IDENT, TokenType.WHITESPACE]:
|
if tokens[token_idx].type == TokenType.IDENT:
|
||||||
|
idx = tokens[token_idx].start
|
||||||
|
token_idx -= 1
|
||||||
|
else:
|
||||||
|
while tokens[token_idx].type == TokenType.WHITESPACE:
|
||||||
idx = tokens[token_idx].start
|
idx = tokens[token_idx].start
|
||||||
token_idx -= 1
|
token_idx -= 1
|
||||||
|
|
||||||
|
@ -236,7 +240,7 @@ def property_completer(ctx: CompletionContext):
|
||||||
for prop_name, prop in ctx.ast_node.gir_class.properties.items():
|
for prop_name, prop in ctx.ast_node.gir_class.properties.items():
|
||||||
yield get_property_completion(
|
yield get_property_completion(
|
||||||
prop_name,
|
prop_name,
|
||||||
prop,
|
prop.type,
|
||||||
ctx,
|
ctx,
|
||||||
annotations.is_property_translated(prop),
|
annotations.is_property_translated(prop),
|
||||||
prop.doc,
|
prop.doc,
|
||||||
|
@ -245,7 +249,11 @@ def property_completer(ctx: CompletionContext):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[language.Property, language.A11yProperty],
|
applies_in=[language.Property, language.A11yProperty],
|
||||||
matches=[[(TokenType.IDENT, None), (TokenType.OP, ":")]],
|
matches=[
|
||||||
|
[(TokenType.IDENT, None), (TokenType.OP, ":")],
|
||||||
|
[(TokenType.PUNCTUATION, ",")],
|
||||||
|
[(TokenType.PUNCTUATION, "[")],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def prop_value_completer(ctx: CompletionContext):
|
def prop_value_completer(ctx: CompletionContext):
|
||||||
if isinstance(ctx.ast_node, language.Property):
|
if isinstance(ctx.ast_node, language.Property):
|
||||||
|
@ -367,3 +375,58 @@ def template_completer(_ctx: CompletionContext):
|
||||||
CompletionItemKind.Snippet,
|
CompletionItemKind.Snippet,
|
||||||
snippet="template ${1:ClassName} : ${2:ParentClass} {\n $0\n}",
|
snippet="template ${1:ClassName} : ${2:ParentClass} {\n $0\n}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@completer(
|
||||||
|
applies_in=[language.ObjectContent, language.ChildType],
|
||||||
|
matches=[[(TokenType.PUNCTUATION, "[")]],
|
||||||
|
applies_in_subclass=[("Gtk", "Dialog"), ("Gtk", "InfoBar")],
|
||||||
|
)
|
||||||
|
def response_id_completer(ctx: CompletionContext):
|
||||||
|
yield Completion(
|
||||||
|
"action",
|
||||||
|
CompletionItemKind.Snippet,
|
||||||
|
sort_text=get_sort_key(CompletionPriority.KEYWORD, "action"),
|
||||||
|
snippet="action response=$0",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@completer(
|
||||||
|
[language.ChildAnnotation, language.ExtResponse],
|
||||||
|
[[(TokenType.IDENT, "action"), (TokenType.IDENT, "response"), (TokenType.OP, "=")]],
|
||||||
|
)
|
||||||
|
def complete_response_id(ctx: CompletionContext):
|
||||||
|
gir = ctx.ast_node.root.gir
|
||||||
|
response_type = gir.get_type("ResponseType", "Gtk")
|
||||||
|
yield from [
|
||||||
|
Completion(
|
||||||
|
name,
|
||||||
|
kind=CompletionItemKind.EnumMember,
|
||||||
|
docs=member.doc,
|
||||||
|
)
|
||||||
|
for name, member in response_type.members.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@completer(
|
||||||
|
[language.ChildAnnotation, language.ExtResponse],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
(TokenType.IDENT, "action"),
|
||||||
|
(TokenType.IDENT, "response"),
|
||||||
|
(TokenType.OP, "="),
|
||||||
|
(TokenType.IDENT, None),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
(TokenType.IDENT, "action"),
|
||||||
|
(TokenType.IDENT, "response"),
|
||||||
|
(TokenType.OP, "="),
|
||||||
|
(TokenType.NUMBER, None),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def complete_response_default(ctx: CompletionContext):
|
||||||
|
yield Completion(
|
||||||
|
"default",
|
||||||
|
kind=CompletionItemKind.Keyword,
|
||||||
|
)
|
||||||
|
|
|
@ -68,10 +68,22 @@ def completer(applies_in: T.List, matches: T.List = [], applies_in_subclass=None
|
||||||
# For completers that apply in ObjectContent nodes, we can further
|
# For completers that apply in ObjectContent nodes, we can further
|
||||||
# check that the object is the right class
|
# check that the object is the right class
|
||||||
if applies_in_subclass is not None:
|
if applies_in_subclass is not None:
|
||||||
type = ast_node.root.gir.get_type(
|
parent_obj = ast_node
|
||||||
applies_in_subclass[1], applies_in_subclass[0]
|
while parent_obj is not None and not hasattr(parent_obj, "gir_class"):
|
||||||
|
parent_obj = parent_obj.parent
|
||||||
|
|
||||||
|
if (
|
||||||
|
parent_obj is None
|
||||||
|
or not parent_obj.gir_class
|
||||||
|
or not any(
|
||||||
|
[
|
||||||
|
parent_obj.gir_class.assignable_to(
|
||||||
|
parent_obj.root.gir.get_type(c[1], c[0])
|
||||||
)
|
)
|
||||||
if not ast_node.gir_class or not ast_node.gir_class.assignable_to(type):
|
for c in applies_in_subclass
|
||||||
|
]
|
||||||
|
)
|
||||||
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
any_match = len(matches) == 0
|
any_match = len(matches) == 0
|
||||||
|
|
|
@ -34,9 +34,16 @@ from .gtk_scale import ExtScaleMarks
|
||||||
from .gtk_size_group import ExtSizeGroupWidgets
|
from .gtk_size_group import ExtSizeGroupWidgets
|
||||||
from .gtk_string_list import ExtStringListStrings
|
from .gtk_string_list import ExtStringListStrings
|
||||||
from .gtk_styles import ExtStyles
|
from .gtk_styles import ExtStyles
|
||||||
from .gtkbuilder_child import Child, ChildExtension, ChildInternal, ChildType
|
from .gtkbuilder_child import (
|
||||||
|
Child,
|
||||||
|
ChildAnnotation,
|
||||||
|
ChildExtension,
|
||||||
|
ChildInternal,
|
||||||
|
ChildType,
|
||||||
|
)
|
||||||
from .gtkbuilder_template import Template
|
from .gtkbuilder_template import Template
|
||||||
from .imports import GtkDirective, Import
|
from .imports import GtkDirective, Import
|
||||||
|
from .response_id import ExtResponse
|
||||||
from .types import ClassName
|
from .types import ClassName
|
||||||
from .ui import UI
|
from .ui import UI
|
||||||
from .values import (
|
from .values import (
|
||||||
|
|
|
@ -140,7 +140,7 @@ class ExtAdwResponseDialog(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Adw", "MessageDialog"),
|
applies_in_subclass=[("Adw", "AlertDialog"), ("Adw", "MessageDialog")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def complete_adw_message_dialog(_ctx: CompletionContext):
|
def complete_adw_message_dialog(_ctx: CompletionContext):
|
||||||
|
@ -149,20 +149,6 @@ def complete_adw_message_dialog(_ctx: CompletionContext):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@completer(
|
|
||||||
applies_in=[ObjectContent],
|
|
||||||
applies_in_subclass=("Adw", "AlertDialog"),
|
|
||||||
matches=new_statement_patterns,
|
|
||||||
)
|
|
||||||
def complete_adw_alert_dialog(_ctx: CompletionContext):
|
|
||||||
yield Completion(
|
|
||||||
"responses",
|
|
||||||
CompletionItemKind.Keyword,
|
|
||||||
snippet="responses [\n\t$0\n]",
|
|
||||||
sort_text=get_sort_key(CompletionPriority.OBJECT_MEMBER, "responses"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@decompiler("responses")
|
@decompiler("responses")
|
||||||
def decompile_responses(ctx, gir):
|
def decompile_responses(ctx, gir):
|
||||||
ctx.print(f"responses [")
|
ctx.print(f"responses [")
|
||||||
|
|
|
@ -91,7 +91,7 @@ class ExtComboBoxItems(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "ComboBoxText"),
|
applies_in_subclass=[("Gtk", "ComboBoxText")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def items_completer(_ctx: CompletionContext):
|
def items_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -98,7 +98,7 @@ ext_file_filter_suffixes = create_node("suffixes", "suffix")
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "FileFilter"),
|
applies_in_subclass=[("Gtk", "FileFilter")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def file_filter_completer(_ctx: CompletionContext):
|
def file_filter_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -90,7 +90,7 @@ class ExtLayout(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "Widget"),
|
applies_in_subclass=[("Gtk", "Widget")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def layout_completer(_ctx: CompletionContext):
|
def layout_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -134,7 +134,7 @@ class ExtScaleMarks(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "Scale"),
|
applies_in_subclass=[("Gtk", "Scale")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def complete_marks(_ctx: CompletionContext):
|
def complete_marks(_ctx: CompletionContext):
|
||||||
|
|
|
@ -101,7 +101,7 @@ class ExtSizeGroupWidgets(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "SizeGroup"),
|
applies_in_subclass=[("Gtk", "SizeGroup")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def size_group_completer(_ctx: CompletionContext):
|
def size_group_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -72,7 +72,7 @@ class ExtStringListStrings(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "StringList"),
|
applies_in_subclass=[("Gtk", "StringList")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def strings_completer(_ctx: CompletionContext):
|
def strings_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -77,7 +77,7 @@ class ExtStyles(AstNode):
|
||||||
|
|
||||||
@completer(
|
@completer(
|
||||||
applies_in=[ObjectContent],
|
applies_in=[ObjectContent],
|
||||||
applies_in_subclass=("Gtk", "Widget"),
|
applies_in_subclass=[("Gtk", "Widget")],
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def style_completer(_ctx: CompletionContext):
|
def style_completer(_ctx: CompletionContext):
|
||||||
|
|
|
@ -31,7 +31,12 @@ ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [
|
||||||
|
|
||||||
|
|
||||||
class ChildInternal(AstNode):
|
class ChildInternal(AstNode):
|
||||||
grammar = ["internal-child", UseIdent("internal_child")]
|
grammar = [
|
||||||
|
"[",
|
||||||
|
"internal-child",
|
||||||
|
UseIdent("internal_child").expected("internal child name"),
|
||||||
|
Match("]").expected(),
|
||||||
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def internal_child(self) -> str:
|
def internal_child(self) -> str:
|
||||||
|
@ -39,7 +44,7 @@ class ChildInternal(AstNode):
|
||||||
|
|
||||||
|
|
||||||
class ChildType(AstNode):
|
class ChildType(AstNode):
|
||||||
grammar = UseIdent("child_type").expected("a child type")
|
grammar = ["[", UseIdent("child_type").expected("a child type"), "]"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def child_type(self) -> str:
|
def child_type(self) -> str:
|
||||||
|
@ -59,7 +64,7 @@ class ChildExtension(AstNode):
|
||||||
|
|
||||||
|
|
||||||
class ChildAnnotation(AstNode):
|
class ChildAnnotation(AstNode):
|
||||||
grammar = ["[", AnyOf(ChildInternal, ChildExtension, ChildType), "]"]
|
grammar = AnyOf(ChildInternal, ChildExtension, ChildType)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def child(self) -> T.Union[ChildInternal, ChildExtension, ChildType]:
|
def child(self) -> T.Union[ChildInternal, ChildExtension, ChildType]:
|
||||||
|
|
|
@ -28,19 +28,21 @@ class ExtResponse(AstNode):
|
||||||
|
|
||||||
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [("Gtk", "Dialog"), ("Gtk", "InfoBar")]
|
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [("Gtk", "Dialog"), ("Gtk", "InfoBar")]
|
||||||
|
|
||||||
grammar = [
|
grammar = Statement(
|
||||||
|
"[",
|
||||||
Keyword("action"),
|
Keyword("action"),
|
||||||
Keyword("response"),
|
Keyword("response"),
|
||||||
"=",
|
Match("=").expected(),
|
||||||
AnyOf(
|
AnyOf(
|
||||||
UseIdent("response_id"),
|
UseIdent("response_id"),
|
||||||
[
|
[
|
||||||
Optional(UseExact("sign", "-")),
|
Optional(UseExact("sign", "-")),
|
||||||
UseNumber("response_id"),
|
UseNumber("response_id"),
|
||||||
],
|
],
|
||||||
),
|
).expected("response ID"),
|
||||||
Optional([Keyword("default"), UseLiteral("is_default", True)]),
|
Optional([Keyword("default"), UseLiteral("is_default", True)]),
|
||||||
]
|
end="]",
|
||||||
|
)
|
||||||
|
|
||||||
@validate()
|
@validate()
|
||||||
def parent_has_action_widgets(self) -> None:
|
def parent_has_action_widgets(self) -> None:
|
||||||
|
|
|
@ -329,8 +329,9 @@ class Statement(ParseNode):
|
||||||
"""ParseNode that attempts to match all of its children in sequence. If any
|
"""ParseNode that attempts to match all of its children in sequence. If any
|
||||||
child raises an error, the error will be logged but parsing will continue."""
|
child raises an error, the error will be logged but parsing will continue."""
|
||||||
|
|
||||||
def __init__(self, *children):
|
def __init__(self, *children, end: str = ";"):
|
||||||
self.children = [to_parse_node(child) for child in children]
|
self.children = [to_parse_node(child) for child in children]
|
||||||
|
self.end = end
|
||||||
|
|
||||||
def _parse(self, ctx) -> bool:
|
def _parse(self, ctx) -> bool:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
|
@ -340,11 +341,16 @@ class Statement(ParseNode):
|
||||||
except CompileError as e:
|
except CompileError as e:
|
||||||
ctx.errors.append(e)
|
ctx.errors.append(e)
|
||||||
ctx.set_group_incomplete()
|
ctx.set_group_incomplete()
|
||||||
|
|
||||||
|
token = ctx.peek_token()
|
||||||
|
if str(token) == self.end:
|
||||||
|
ctx.next_token()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
token = ctx.peek_token()
|
token = ctx.peek_token()
|
||||||
if str(token) != ";":
|
if str(token) != self.end:
|
||||||
ctx.errors.append(CompileError("Expected `;`", token.range))
|
ctx.errors.append(CompileError(f"Expected `{self.end}`", token.range))
|
||||||
else:
|
else:
|
||||||
ctx.next_token()
|
ctx.next_token()
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
4,6,22,Action widget must have ID
|
4,5,24,Action widget must have ID
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
4,6,18,Gtk.Box doesn't have action widgets
|
4,5,20,Gtk.Box doesn't have action widgets
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue