diff --git a/blueprintcompiler/completions.py b/blueprintcompiler/completions.py index a1090e8..aec01a4 100644 --- a/blueprintcompiler/completions.py +++ b/blueprintcompiler/completions.py @@ -27,14 +27,15 @@ from .completions_utils import ( CompletionPriority, completer, completers, - get_object_id_completions, + get_available_namespace_completions, get_property_completion, get_sort_key, + get_value_completions, new_statement_patterns, ) from .language.contexts import ValueTypeCtx from .language.types import ClassName -from .lsp_utils import Completion, CompletionItemKind, TextEdit, get_docs_section +from .lsp_utils import Completion, CompletionItemKind, get_docs_section from .parser import SKIP_TOKENS from .tokenizer import Token, TokenType @@ -155,27 +156,6 @@ def translation_domain(ctx: CompletionContext): ) -def _available_namespace_completions(ctx: CompletionContext): - imported_namespaces = set( - [import_.namespace for import_ in ctx.ast_node.root.using] - ) - - for ns, version in gir.get_available_namespaces(): - if ns not in imported_namespaces and ns != "Gtk": - yield Completion( - ns, - CompletionItemKind.Module, - text=ns + ".", - sort_text=get_sort_key(CompletionPriority.IMPORT_NAMESPACE, ns), - signature=f" using {ns} {version}", - additional_text_edits=[ - TextEdit( - ctx.ast_node.root.import_range(ns), f"\nusing {ns} {version};" - ) - ], - ) - - @completer( applies_in=[ language.UI, @@ -200,7 +180,7 @@ def namespace(ctx: CompletionContext): ), ) - yield from _available_namespace_completions(ctx) + yield from get_available_namespace_completions(ctx) @completer( @@ -321,61 +301,7 @@ def prop_value_completer(ctx: CompletionContext): if (vt := ctx.ast_node.value_type) is not None: assert isinstance(vt, ValueTypeCtx) - - if isinstance(vt.value_type, gir.Enumeration): - for name, member in vt.value_type.members.items(): - yield Completion( - name, - CompletionItemKind.EnumMember, - docs=member.doc, - detail=member.detail, - sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, name), - ) - - elif isinstance(vt.value_type, gir.BoolType): - yield Completion( - "true", - CompletionItemKind.Constant, - sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, "true"), - ) - yield Completion( - "false", - CompletionItemKind.Constant, - sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, "false"), - ) - - elif isinstance(vt.value_type, gir.Class) or isinstance( - vt.value_type, gir.Interface - ): - if vt.allow_null: - yield Completion( - "null", - CompletionItemKind.Constant, - sort_text=get_sort_key(CompletionPriority.KEYWORD, "null"), - ) - - yield from get_object_id_completions(ctx, vt.value_type) - - if isinstance(ctx.ast_node, language.Property): - yield from _available_namespace_completions(ctx) - - for ns in ctx.ast_node.root.gir.namespaces.values(): - for c in ns.classes.values(): - if not c.abstract and c.assignable_to(vt.value_type): - name = ( - c.name if ns.name == "Gtk" else ns.name + "." + c.name - ) - snippet = name - if str(ctx.next_token) != "{": - snippet += " {\n $0\n}" - yield Completion( - name, - CompletionItemKind.Class, - sort_text=get_sort_key(CompletionPriority.CLASS, name), - snippet=snippet, - detail=c.detail, - docs=c.doc, - ) + yield from get_value_completions(ctx, vt.value_type, vt.allow_null) @completer( @@ -474,3 +400,12 @@ def complete_response_default(ctx: CompletionContext): "default", kind=CompletionItemKind.Keyword, ) + + +@completer( + [language.ObjectContent], + matches=new_statement_patterns, + applies_in_subclass=["Adw.Breakpoint"], +) +def complete_breakpoint_condition(ctx: CompletionContext): + yield Completion("condition", CompletionItemKind.Keyword, snippet="condition ($0)") diff --git a/blueprintcompiler/completions_utils.py b/blueprintcompiler/completions_utils.py index 911f5c4..359fa82 100644 --- a/blueprintcompiler/completions_utils.py +++ b/blueprintcompiler/completions_utils.py @@ -24,7 +24,7 @@ from enum import Enum from . import gir, language from .ast_utils import AstNode -from .lsp_utils import Completion, CompletionItemKind +from .lsp_utils import Completion, CompletionItemKind, TextEdit from .tokenizer import Token, TokenType @@ -182,3 +182,79 @@ def get_object_id_completions( signature=" " + obj.signature, sort_text=get_sort_key(CompletionPriority.NAMED_OBJECT, id), ) + + +def get_available_namespace_completions(ctx: CompletionContext): + imported_namespaces = set( + [import_.namespace for import_ in ctx.ast_node.root.using] + ) + + for ns, version in gir.get_available_namespaces(): + if ns not in imported_namespaces and ns != "Gtk": + yield Completion( + ns, + CompletionItemKind.Module, + text=ns + ".", + sort_text=get_sort_key(CompletionPriority.IMPORT_NAMESPACE, ns), + signature=f" using {ns} {version}", + additional_text_edits=[ + TextEdit( + ctx.ast_node.root.import_range(ns), f"\nusing {ns} {version};" + ) + ], + ) + + +def get_value_completions( + ctx: CompletionContext, value_type: T.Optional[gir.GirType], allow_null: bool = True +): + if isinstance(value_type, gir.Enumeration): + for name, member in value_type.members.items(): + yield Completion( + name, + CompletionItemKind.EnumMember, + docs=member.doc, + detail=member.detail, + sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, name), + ) + + elif isinstance(value_type, gir.BoolType): + yield Completion( + "true", + CompletionItemKind.Constant, + sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, "true"), + ) + yield Completion( + "false", + CompletionItemKind.Constant, + sort_text=get_sort_key(CompletionPriority.ENUM_MEMBER, "false"), + ) + + elif isinstance(value_type, gir.Class) or isinstance(value_type, gir.Interface): + if allow_null: + yield Completion( + "null", + CompletionItemKind.Constant, + sort_text=get_sort_key(CompletionPriority.KEYWORD, "null"), + ) + + yield from get_object_id_completions(ctx, value_type) + + if isinstance(ctx.ast_node, language.Property): + yield from get_available_namespace_completions(ctx) + + for ns in ctx.ast_node.root.gir.namespaces.values(): + for c in ns.classes.values(): + if not c.abstract and c.assignable_to(value_type): + name = c.name if ns.name == "Gtk" else ns.name + "." + c.name + snippet = name + if str(ctx.next_token) != "{": + snippet += " {\n $0\n}" + yield Completion( + name, + CompletionItemKind.Class, + sort_text=get_sort_key(CompletionPriority.CLASS, name), + snippet=snippet, + detail=c.detail, + docs=c.doc, + ) diff --git a/blueprintcompiler/language/adw_breakpoint.py b/blueprintcompiler/language/adw_breakpoint.py index 3d2c10d..5ac834b 100644 --- a/blueprintcompiler/language/adw_breakpoint.py +++ b/blueprintcompiler/language/adw_breakpoint.py @@ -17,6 +17,7 @@ # # SPDX-License-Identifier: LGPL-3.0-or-later +from .. import annotations from .common import * from .contexts import ScopeCtx, ValueTypeCtx from .gobject_object import Object, validate_parent_type @@ -63,9 +64,9 @@ class AdwBreakpointSetter(AstNode): grammar = Statement( UseIdent("object"), Match(".").expected(), - UseIdent("property"), + UseIdent("property").expected("property"), Match(":").expected(), - Value, + to_parse_node(Value).expected("value"), ) @property @@ -252,3 +253,37 @@ def decompile_setter(ctx: DecompileCtx, gir, element): (child["translatable"], child["context"], child["comments"]), ) ctx.print(f"{comments} {object_id}.{property_name}: {string};") + + +@completer([AdwBreakpointSetters], new_statement_patterns) +def complete_object(ctx: CompletionContext): + yield from get_object_id_completions(ctx) + + +@completer([AdwBreakpointSetter], [[TokenType.IDENT, "."]]) +def complete_properties(ctx: CompletionContext): + obj = ctx.ast_node.context[ScopeCtx].objects.get(ctx.match_variables[0]) + if ( + obj is not None + and obj.gir_class is not None + and hasattr(obj.gir_class, "properties") + ): + for prop_name, prop in obj.gir_class.properties.items(): + yield get_property_completion( + prop_name, + prop.type, + ctx, + annotations.is_property_translated(prop), + prop.doc, + ) + + +@completer([AdwBreakpointSetter], [[TokenType.IDENT, ".", TokenType.IDENT, ":"]]) +def complete_property_value(ctx: CompletionContext): + assert isinstance(ctx.ast_node, AdwBreakpointSetter) + if ctx.ast_node.gir_property is None: + return + + t = ctx.ast_node.gir_property.type + if t is not None: + yield from get_value_completions(ctx, t)