From 52e651a1689886d5f44133619b46a6f1dd4e0c0c Mon Sep 17 00:00:00 2001 From: Megadash452 Date: Sun, 2 Oct 2022 15:23:48 +0000 Subject: [PATCH 01/14] Created Tutorial page; TODOs pending. --- docs/tutorial.rst | 452 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 452 insertions(+) create mode 100644 docs/tutorial.rst diff --git a/docs/tutorial.rst b/docs/tutorial.rst new file mode 100644 index 0000000..09f2d8a --- /dev/null +++ b/docs/tutorial.rst @@ -0,0 +1,452 @@ +======== +Tutorial +======== + +.. margin at column 75 + +Read this if you want to learn how to use Blueprint and never used +the XML syntax that can be read by GtkBuilder. + +For compatibility with Blueprint IDE extensions, blueprint files +should end with `.blp`. + + +Namespaces +---------- + +Blueprint needs the widget library to be imported. These include Gtk, +Libadwaita, Shumate, etc. To import a namespace, write `using` followed +by the library and version number. + +.. code-block:: + using Gtk 4.0; + using Adw 1; + +The Gtk import is required in all blueprints and the minor version +number must be 0. + + +Comments +-------- + +Blueprint has inline or multi-line comments + +.. code-block:: + // This is an inline comment + /* This is + a multiline + comment */ + +Multi-line comments can't have inner multi-line comments. The compiler +will interpret the inner comment's closing token as the outer comment's +closing token. For example, the following will not compile: + +.. code-block:: + // Bad comment below: + /* Outer comment + /* Inner comment */ + */ + + +Widgets +------- + +Create widgets in the following format: + +.. code-block:: + Namespace.WidgetClass { + + } + +The Gtk namespace is implied for widgets, so you can just write the +widget class + +.. code-block:: + Box { + + } + +Other namespaces must be written explicitly. + +.. code-block:: + Adw.Leaflet { + + } + +Consult the widget library's documentation for a list of widgets. Here is +for `Link Gtk `. + +Naming Widgets +~~~~~~~~~~~~~~ + +Widgets can be given **name**s so that they can be referenced by other +widgets in the blueprint. + +.. code-block:: + Namespace.WidgetClass widget-name { + + } + +Any time you want to use this widget as a property (more about that in the +next section) or something else, write the widget's **name** (e.g. +`main-window`). + + +Properties +---------- + +Every widget has properties defined by their GObject class. For example, +Libadwaita Toast properties can be found +`Link here `_. +Write properties inside the curly brackets of a widget: + +.. code-block:: + Namespace.WidgetClass { + property-name: value; + } + +Properties are *all lowercase* (except strings) and must end with a +semicolon (;). + +Property Types +~~~~~~~~~~~~~~ + +These are the **types** of values that can be used in properties: + - Booleans: `true`, `false` + - Numbers: e.g. `1`, `1.5`, `-2`, `-2.5` + - Strings (single- or double-quoted): e.g. `"a string"`, `'another string'` + - Enums + - Widgets + +Properties are **strongly typed**, so you can't use, for example, a string +for the orientation property, which requires an `Orientation` enum +vartiant as its value. + +Enum Properties +~~~~~~~~~~~~~~~ + +In the Gtk documentation, enum variants have long names and are +capitalized. For example, these are the +`Link Orientation `_ +enum variants: + + - GTK_ORIENTATION_HORIZONTAL + - GTK_ORIENTATION_VERTICAL + +In the blueprint, you would only write the *variant* part of the enum in +*lowercase*, just like you would in the XML. + +.. code-block:: + Box { + orientation: horizontal; + } + +Widget Properties +~~~~~~~~~~~~~~~~~ + +Some widgets take other widgets as properties. For example, the +`Gtk.StackSidebar` has a stack property which takes a `Gtk.Stack` widget. +You can create a new widget for the value, or you can reference another +widget by its **name**. + +.. code-block:: + StackSidebar { + stack: Stack { }; + } + +OR + +.. code-block:: + StackSidebar { + stack: my-stack; + } + + Stack my-stack { + + } + +Note the use of a semicolon at the end of the property in both cases. +Widget properties are not exempt of this rule. + + +Property Bindings +----------------- + +If you want a widget's property to have the same value as another widget's +property (without hard-coding the value), you could `bind` two widgets' +properties of the same type. Bindings must reference a *source* widget by +**name**. As long as the two properties have the same type, you can bind +properties of different names and of widgets with different widget classes. + +.. code-block:: + Box my-box { + halign: fill; // Source + } + + Button { + valign: bind my-box.halign; // Target + } + +Binding Flags +~~~~~~~~~~~~~ + +Modify the behavior of bindings with flags. Flags are written after the +binding. + +.. code-block:: + Box my-box { + hexpand: true; // Source + } + + Button { + vexpand: bind my-box.hexpand inverted bidirectional; // Target + } + +no-sync-create + .. TODO: I'm not exactly sure what this does + Only update the target value when the *Source* value changes, not when + the binding is first created. + +bidirectional + When either the *Source* or *Target* value is modified, the other's + value will be updated. For example, if the logic of the program + changes the Button's vexpand value to `false`, then the Box's halign + value will also be updated to `false`. + +inverted + If the property is a boolean, the value of the bind can be negated + with this flag. For example, if the Box's hexpand property is `true`, + the Button's vexpand property will be `false` in the code below. + + +Signals +------- + +Gtk allows you to register signals in your program. This can be done by +getting the object from the GtkBuilder and connecting a handler to the +signal. Or register the handler with the application and reference it in +the blueprint. + +Signals have an *event name*, a *handler* (aka callback), and optionally +some *flags*. Each widget will have a set of defined signals. Consult the +widget's documentation for a list of its signals. + +To register a handler with the application, consult the documentation for +your language's bindings of Gtk. + +.. code-block:: + WidgetClass { + event-name => handler_name() flags; + } + +.. TODO: add a list of flags and their descriptions + +By default, signals in the blueprint will pass the widget that the signal +is for as an argument to the *handler*. However, you can specify the +widget that is passed to the handler by referencing its name inside the +parenthesis. + +.. code-block:: + Label my-label { + label: "Hide me"; + } + + Button { + clicked => hide_widget(my-label); + } + + +Custom Widget Classes +--------------------- + +Some programs have custom widgets defined in their logic, and so blueprint +won't know that they exist. Writing widgets not defined in the GIR will +result in an error. Prepend a custom widget with a `.` to prevent the +compiler from trying to validate the widget. This is essentially leaving +out the *namespace*. + +To register a custom widget with the application consult the documentation +for your language's bindings of Gtk. + +.. code-block:: + .MyCustomWidget { + + } + + +Templates +--------- +.. TODO + + +CSS Style Classes +----------------- +.. Unsure if to group styles with widget-specific items +Widgets can be given style classes that can be used with your CSS or +`Link predefined styles `_ +in libraries like Libadwaita. + +.. code-block:: + Button { + label: "Click me"; + styles ["my-style", "pill"] + } + +Note the lack of a *colon* after "styles" and a *semicolon* at the end of +the line. This syntax looks like the properties syntax, but it compiles to +XML completely different from properties. + +The syntax may change to `styles! [...]` in the future so that it is not +confused with the properties syntax. + +Consult your language's bindings of Gtk to use a CSS file. + +Non-property Elements +~~~~~~~~~~~~~~~~~~~~~ +.. TODO: ^^^ should it be called that? + +Some widgets will have elements which are not properties, but they sort +of act like properties. Most of the time they will be specific only to a +certain widget. *Styles* is one of these elements, except that styles can +be used for any widget. Similarly to how every widget has styles, +`Gtk.ComboBoxText` has *items*: + +.. code-block:: + Gtk.ComboBoxText { + items [ + item1: "Item 1", + item2: _("Items can be translated"), + "The item ID is not required", + ] + } + +See the `Link examples page `_ for a list of more of these +widget-specific items. + + +Menus +----- + +Menus are usually the widgets that are placed along the top-bar of a +window, or pop up when you right-click some other widget. In Blueprint a +`menu` is a `Gio.MenuModel` that can be shown by MenuButtons or other +widgets. + +Similarly to how it is explained in +`Link Gtk.PopoverMenu `_, +in Blueprint `menu`s have *items*, *sections*, and *submenus*. `Menu`s can +also be given a **name** like a widget. Please read the **Menu Model** +section of `Gtk.PopoverMenu` for more details on the menu model. + +Here is an example of a menu: + +.. code-block:: + menu my-menu { + section { + label: "File"; + item { + label: "Open"; + action: "win.open"; + icon-name: "document-open-symbolic"; + } + item { + label: "Save"; + action: "win.save"; + icon-name: "document-save-symbolic"; + } + submenu { + label: "Save As"; + icon-name: "document-save-as-symbolic"; + item { + label: "PDF"; + action: "win.save_as_pdf"; + } + } + } + } + +There is a shorthand for *items*. Items require at least a label. The +action and icon-name are optional. + +.. code-block:: + menu { + item ( "Item 2" ) + item ( "Item 2", "app.action", "icon-name" ) + } + +A widget that uses a `menu` is `Gtk.MenuButton`. It has the *menu-model* +property, which takes a menu. You can write the menu inline with the +property, or write the menu separately and reference it by **name**. + +.. code-block:: + MenuButton { + menu-model: my-menu; + } + + +Child Types +----------- + +Child types describe how a child widget is placed on a parent widget. For +example, HeaderBars widgets can have children placed either at the *start* +or the *end* of the Headerbar. Child widgets of HeaderBars can have the +*start* or *end* types. Values for child types a widget can have are +defined in the widget's documentation. + +Child types in blueprint are written between square brackets [] and before +the child the type is for. + +The following blueprint code... + +.. code-block:: + HeaderBar { + [start] + Button { + label: "Button"; + } + } + +\... would look like this: + + --------------------------- + | Button | + --------------------------- + +And the following blueprint code... + +.. code-block:: + HeaderBar { + [end] + Button { + label: "Button"; + } + } + +\... would look like this: + + --------------------------- + | Button | + --------------------------- + + +Translatable Strings +-------------------- + +Mark any string as translatable using this syntax: `_("...")`. + +Two strings that are the same in English could be translated in different +ways in other languages because of different *contexts*. Translatable +strings with context look like this: `C_("...", "context")`. An example +where a context is needed is the word "have", which in Spanish could +translate to "tener" or "haber". + +.. code-block:: + Label { + label: C_("have", "1st have"); + } + + Label { + label: C_("have", "2nd have"); + } + +See `Link translations page `_ for more details. \ No newline at end of file From 4dd55ab2aa0d5724fc0221d2747b976e27b268c1 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Oct 2022 01:19:44 +0000 Subject: [PATCH 02/14] Apply 1 suggestion(s) to 1 file(s) --- docs/tutorial.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 09f2d8a..47ed955 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -95,9 +95,9 @@ next section) or something else, write the widget's **name** (e.g. Properties ---------- -Every widget has properties defined by their GObject class. For example, -Libadwaita Toast properties can be found -`Link here `_. +Every widget has properties defined by their GObject class. +For example, the Libadwaita documentation lists the +`properties of the Toast class `_. Write properties inside the curly brackets of a widget: .. code-block:: From cce1af5f093b4f3bd2490d086844487785f7d350 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Oct 2022 01:32:19 +0000 Subject: [PATCH 03/14] Apply 6 suggestion(s) to 1 file(s) --- docs/tutorial.rst | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 47ed955..6274f29 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -127,7 +127,7 @@ Enum Properties In the Gtk documentation, enum variants have long names and are capitalized. For example, these are the -`Link Orientation `_ +`Orientation `_ enum variants: - GTK_ORIENTATION_HORIZONTAL @@ -195,11 +195,11 @@ binding. .. code-block:: Box my-box { - hexpand: true; // Source + hexpand: true; // Source } Button { - vexpand: bind my-box.hexpand inverted bidirectional; // Target + vexpand: bind my-box.hexpand inverted bidirectional; // Target } no-sync-create @@ -283,7 +283,7 @@ CSS Style Classes ----------------- .. Unsure if to group styles with widget-specific items Widgets can be given style classes that can be used with your CSS or -`Link predefined styles `_ +`predefined styles `_ in libraries like Libadwaita. .. code-block:: @@ -320,7 +320,7 @@ be used for any widget. Similarly to how every widget has styles, ] } -See the `Link examples page `_ for a list of more of these +See `examples `_ for a list of more of these widget-specific items. @@ -332,11 +332,10 @@ window, or pop up when you right-click some other widget. In Blueprint a `menu` is a `Gio.MenuModel` that can be shown by MenuButtons or other widgets. -Similarly to how it is explained in -`Link Gtk.PopoverMenu `_, -in Blueprint `menu`s have *items*, *sections*, and *submenus*. `Menu`s can -also be given a **name** like a widget. Please read the **Menu Model** -section of `Gtk.PopoverMenu` for more details on the menu model. +In Blueprint, `menu`s have *items*, *sections*, and *submenus*. +Like widgets, `menu`s can also be given a **name**. +The `Menu Model section of the Gtk.PopoverMenu documentation `_ +has complete details on the menu model. Here is an example of a menu: @@ -449,4 +448,4 @@ translate to "tener" or "haber". label: C_("have", "2nd have"); } -See `Link translations page `_ for more details. \ No newline at end of file +See `translations `_ for more details. \ No newline at end of file From 9e293a31e676f62fbdde2b2fbea7f097e27adcc7 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Oct 2022 01:45:33 +0000 Subject: [PATCH 04/14] Apply 1 suggestion(s) to 1 file(s) --- docs/tutorial.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 6274f29..60a3542 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -73,8 +73,9 @@ Other namespaces must be written explicitly. } -Consult the widget library's documentation for a list of widgets. Here is -for `Link Gtk `. +Consult the widget library's documentation for a list of widgets. +A good place to start is +`the Gtk4 widget list `. Naming Widgets ~~~~~~~~~~~~~~ From c74c5ac232d8f1ffbedc96fd74c6741351af0d1d Mon Sep 17 00:00:00 2001 From: Megadash452 Date: Wed, 19 Oct 2022 02:22:51 +0000 Subject: [PATCH 05/14] Tutorial: changed terminology *name* to *id* --- docs/tutorial.rst | 60 ++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 60a3542..3111f6f 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -80,17 +80,17 @@ A good place to start is Naming Widgets ~~~~~~~~~~~~~~ -Widgets can be given **name**s so that they can be referenced by other +Widgets can be given **name/ID**s so that they can be referenced by other widgets in the blueprint. .. code-block:: - Namespace.WidgetClass widget-name { + Namespace.WidgetClass widget_id { } Any time you want to use this widget as a property (more about that in the -next section) or something else, write the widget's **name** (e.g. -`main-window`). +next section) or something else, write the widget's **ID** (e.g. +`main_window`). Properties @@ -106,7 +106,7 @@ Write properties inside the curly brackets of a widget: property-name: value; } -Properties are *all lowercase* (except strings) and must end with a +Properties values are *all lowercase* (except strings) and must end with a semicolon (;). Property Types @@ -148,7 +148,7 @@ Widget Properties Some widgets take other widgets as properties. For example, the `Gtk.StackSidebar` has a stack property which takes a `Gtk.Stack` widget. You can create a new widget for the value, or you can reference another -widget by its **name**. +widget by its **ID**. .. code-block:: StackSidebar { @@ -159,10 +159,10 @@ OR .. code-block:: StackSidebar { - stack: my-stack; + stack: my_stack; } - Stack my-stack { + Stack my_stack { } @@ -176,16 +176,16 @@ Property Bindings If you want a widget's property to have the same value as another widget's property (without hard-coding the value), you could `bind` two widgets' properties of the same type. Bindings must reference a *source* widget by -**name**. As long as the two properties have the same type, you can bind +**ID**. As long as the two properties have the same type, you can bind properties of different names and of widgets with different widget classes. .. code-block:: - Box my-box { + Box my_box { halign: fill; // Source } Button { - valign: bind my-box.halign; // Target + valign: bind my_box.halign; // Target } Binding Flags @@ -195,12 +195,12 @@ Modify the behavior of bindings with flags. Flags are written after the binding. .. code-block:: - Box my-box { - hexpand: true; // Source + Box my_box { + hexpand: true; // Source } Button { - vexpand: bind my-box.hexpand inverted bidirectional; // Target + vexpand: bind my_box.hexpand inverted bidirectional; // Target } no-sync-create @@ -217,7 +217,7 @@ bidirectional inverted If the property is a boolean, the value of the bind can be negated with this flag. For example, if the Box's hexpand property is `true`, - the Button's vexpand property will be `false` in the code below. + the Button's vexpand property will be `false` in the code above. Signals @@ -237,23 +237,23 @@ your language's bindings of Gtk. .. code-block:: WidgetClass { - event-name => handler_name() flags; + event_name => handler_name() flags; } .. TODO: add a list of flags and their descriptions By default, signals in the blueprint will pass the widget that the signal is for as an argument to the *handler*. However, you can specify the -widget that is passed to the handler by referencing its name inside the +widget that is passed to the handler by referencing its **id** inside the parenthesis. .. code-block:: - Label my-label { + Label my_label { label: "Hide me"; } Button { - clicked => hide_widget(my-label); + clicked => hide_widget(my_label); } @@ -297,14 +297,10 @@ Note the lack of a *colon* after "styles" and a *semicolon* at the end of the line. This syntax looks like the properties syntax, but it compiles to XML completely different from properties. -The syntax may change to `styles! [...]` in the future so that it is not -confused with the properties syntax. - Consult your language's bindings of Gtk to use a CSS file. Non-property Elements ~~~~~~~~~~~~~~~~~~~~~ -.. TODO: ^^^ should it be called that? Some widgets will have elements which are not properties, but they sort of act like properties. Most of the time they will be specific only to a @@ -334,14 +330,14 @@ window, or pop up when you right-click some other widget. In Blueprint a widgets. In Blueprint, `menu`s have *items*, *sections*, and *submenus*. -Like widgets, `menu`s can also be given a **name**. +Like widgets, `menu`s can also be given a **ID**. The `Menu Model section of the Gtk.PopoverMenu documentation `_ has complete details on the menu model. Here is an example of a menu: .. code-block:: - menu my-menu { + menu my_menu { section { label: "File"; item { @@ -375,12 +371,12 @@ action and icon-name are optional. } A widget that uses a `menu` is `Gtk.MenuButton`. It has the *menu-model* -property, which takes a menu. You can write the menu inline with the -property, or write the menu separately and reference it by **name**. +property, which takes a menu. Write the menu at the root of the blueprint +(meaning not inside any widgets) and reference it by **ID**. .. code-block:: MenuButton { - menu-model: my-menu; + menu-model: my_menu; } @@ -436,17 +432,17 @@ Mark any string as translatable using this syntax: `_("...")`. Two strings that are the same in English could be translated in different ways in other languages because of different *contexts*. Translatable -strings with context look like this: `C_("...", "context")`. An example +strings with context look like this: `C_("context", "...")`. An example where a context is needed is the word "have", which in Spanish could translate to "tener" or "haber". .. code-block:: Label { - label: C_("have", "1st have"); + label: C_("1st have", "have"); } Label { - label: C_("have", "2nd have"); + label: C_("2nd have", "have"); } -See `translations `_ for more details. \ No newline at end of file +See `translations `_ for more details. From 14d1892254b5a1dd552c2678a58c34bbc60036c0 Mon Sep 17 00:00:00 2001 From: Megadash452 Date: Wed, 19 Oct 2022 02:24:20 +0000 Subject: [PATCH 06/14] Tutorial: added doc for binding flag `no-sync-create` --- docs/tutorial.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 3111f6f..6683b65 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -192,7 +192,9 @@ Binding Flags ~~~~~~~~~~~~~ Modify the behavior of bindings with flags. Flags are written after the -binding. +binding. The default behavior is that the *Target*'s value will be +changed to the *Source*'s value when the binding is created and when the +*Source* value changes. .. code-block:: Box my_box { @@ -204,9 +206,10 @@ binding. } no-sync-create - .. TODO: I'm not exactly sure what this does - Only update the target value when the *Source* value changes, not when - the binding is first created. + Prevent setting the *Tartget* with the *Source*'s value, + updating the target value when the *Source* value changes, not when + the binding is first created. Useful when the *Target* property has + another initial value that is not the *Source* value. bidirectional When either the *Source* or *Target* value is modified, the other's From 0fe58ffc37707015110a11e52b18a7a590855b3e Mon Sep 17 00:00:00 2001 From: Megadash452 Date: Wed, 19 Oct 2022 02:30:23 +0000 Subject: [PATCH 07/14] Tutorial: Fixed .rst rendering issues --- docs/tutorial.rst | 66 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 6683b65..9305b51 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -8,17 +8,18 @@ Read this if you want to learn how to use Blueprint and never used the XML syntax that can be read by GtkBuilder. For compatibility with Blueprint IDE extensions, blueprint files -should end with `.blp`. +should end with ``.blp``. Namespaces ---------- Blueprint needs the widget library to be imported. These include Gtk, -Libadwaita, Shumate, etc. To import a namespace, write `using` followed +Libadwaita, Shumate, etc. To import a namespace, write ``using`` followed by the library and version number. .. code-block:: + using Gtk 4.0; using Adw 1; @@ -32,6 +33,7 @@ Comments Blueprint has inline or multi-line comments .. code-block:: + // This is an inline comment /* This is a multiline @@ -42,6 +44,7 @@ will interpret the inner comment's closing token as the outer comment's closing token. For example, the following will not compile: .. code-block:: + // Bad comment below: /* Outer comment /* Inner comment */ @@ -54,6 +57,7 @@ Widgets Create widgets in the following format: .. code-block:: + Namespace.WidgetClass { } @@ -62,6 +66,7 @@ The Gtk namespace is implied for widgets, so you can just write the widget class .. code-block:: + Box { } @@ -69,6 +74,7 @@ widget class Other namespaces must be written explicitly. .. code-block:: + Adw.Leaflet { } @@ -84,13 +90,14 @@ Widgets can be given **name/ID**s so that they can be referenced by other widgets in the blueprint. .. code-block:: + Namespace.WidgetClass widget_id { } Any time you want to use this widget as a property (more about that in the next section) or something else, write the widget's **ID** (e.g. -`main_window`). +``main_window``). Properties @@ -102,6 +109,7 @@ For example, the Libadwaita documentation lists the Write properties inside the curly brackets of a widget: .. code-block:: + Namespace.WidgetClass { property-name: value; } @@ -113,14 +121,14 @@ Property Types ~~~~~~~~~~~~~~ These are the **types** of values that can be used in properties: - - Booleans: `true`, `false` - - Numbers: e.g. `1`, `1.5`, `-2`, `-2.5` - - Strings (single- or double-quoted): e.g. `"a string"`, `'another string'` + - Booleans: ``true``, ``false`` + - Numbers: e.g. ``1``, ``1.5``, ``-2``, ``-2.5`` + - Strings (single- or double-quoted): e.g. ``"a string"``, ``'another string'`` - Enums - Widgets Properties are **strongly typed**, so you can't use, for example, a string -for the orientation property, which requires an `Orientation` enum +for the orientation property, which requires an ``Orientation`` enum vartiant as its value. Enum Properties @@ -138,6 +146,7 @@ In the blueprint, you would only write the *variant* part of the enum in *lowercase*, just like you would in the XML. .. code-block:: + Box { orientation: horizontal; } @@ -146,11 +155,12 @@ Widget Properties ~~~~~~~~~~~~~~~~~ Some widgets take other widgets as properties. For example, the -`Gtk.StackSidebar` has a stack property which takes a `Gtk.Stack` widget. +``Gtk.StackSidebar`` has a stack property which takes a ``Gtk.Stack`` widget. You can create a new widget for the value, or you can reference another widget by its **ID**. .. code-block:: + StackSidebar { stack: Stack { }; } @@ -158,6 +168,7 @@ widget by its **ID**. OR .. code-block:: + StackSidebar { stack: my_stack; } @@ -174,12 +185,13 @@ Property Bindings ----------------- If you want a widget's property to have the same value as another widget's -property (without hard-coding the value), you could `bind` two widgets' +property (without hard-coding the value), you could ``bind`` two widgets' properties of the same type. Bindings must reference a *source* widget by **ID**. As long as the two properties have the same type, you can bind properties of different names and of widgets with different widget classes. .. code-block:: + Box my_box { halign: fill; // Source } @@ -197,6 +209,7 @@ changed to the *Source*'s value when the binding is created and when the *Source* value changes. .. code-block:: + Box my_box { hexpand: true; // Source } @@ -214,13 +227,13 @@ no-sync-create bidirectional When either the *Source* or *Target* value is modified, the other's value will be updated. For example, if the logic of the program - changes the Button's vexpand value to `false`, then the Box's halign - value will also be updated to `false`. + changes the Button's vexpand value to ``false``, then the Box's halign + value will also be updated to ``false``. inverted If the property is a boolean, the value of the bind can be negated - with this flag. For example, if the Box's hexpand property is `true`, - the Button's vexpand property will be `false` in the code above. + with this flag. For example, if the Box's hexpand property is ``true``, + the Button's vexpand property will be ``false`` in the code above. Signals @@ -239,6 +252,7 @@ To register a handler with the application, consult the documentation for your language's bindings of Gtk. .. code-block:: + WidgetClass { event_name => handler_name() flags; } @@ -251,6 +265,7 @@ widget that is passed to the handler by referencing its **id** inside the parenthesis. .. code-block:: + Label my_label { label: "Hide me"; } @@ -265,7 +280,7 @@ Custom Widget Classes Some programs have custom widgets defined in their logic, and so blueprint won't know that they exist. Writing widgets not defined in the GIR will -result in an error. Prepend a custom widget with a `.` to prevent the +result in an error. Prepend a custom widget with a ``.`` to prevent the compiler from trying to validate the widget. This is essentially leaving out the *namespace*. @@ -273,6 +288,7 @@ To register a custom widget with the application consult the documentation for your language's bindings of Gtk. .. code-block:: + .MyCustomWidget { } @@ -291,6 +307,7 @@ Widgets can be given style classes that can be used with your CSS or in libraries like Libadwaita. .. code-block:: + Button { label: "Click me"; styles ["my-style", "pill"] @@ -309,9 +326,10 @@ Some widgets will have elements which are not properties, but they sort of act like properties. Most of the time they will be specific only to a certain widget. *Styles* is one of these elements, except that styles can be used for any widget. Similarly to how every widget has styles, -`Gtk.ComboBoxText` has *items*: +``Gtk.ComboBoxText`` has *items*: .. code-block:: + Gtk.ComboBoxText { items [ item1: "Item 1", @@ -329,17 +347,18 @@ Menus Menus are usually the widgets that are placed along the top-bar of a window, or pop up when you right-click some other widget. In Blueprint a -`menu` is a `Gio.MenuModel` that can be shown by MenuButtons or other +``menu`` is a ``Gio.MenuModel`` that can be shown by MenuButtons or other widgets. -In Blueprint, `menu`s have *items*, *sections*, and *submenus*. -Like widgets, `menu`s can also be given a **ID**. +In Blueprint, ``menu``s have *items*, *sections*, and *submenus*. +Like widgets, ``menu``s can also be given a **ID**. The `Menu Model section of the Gtk.PopoverMenu documentation `_ has complete details on the menu model. Here is an example of a menu: .. code-block:: + menu my_menu { section { label: "File"; @@ -368,16 +387,18 @@ There is a shorthand for *items*. Items require at least a label. The action and icon-name are optional. .. code-block:: + menu { item ( "Item 2" ) item ( "Item 2", "app.action", "icon-name" ) } -A widget that uses a `menu` is `Gtk.MenuButton`. It has the *menu-model* +A widget that uses a ``menu`` is ``Gtk.MenuButton``. It has the *menu-model* property, which takes a menu. Write the menu at the root of the blueprint (meaning not inside any widgets) and reference it by **ID**. .. code-block:: + MenuButton { menu-model: my_menu; } @@ -398,6 +419,7 @@ the child the type is for. The following blueprint code... .. code-block:: + HeaderBar { [start] Button { @@ -414,6 +436,7 @@ The following blueprint code... And the following blueprint code... .. code-block:: + HeaderBar { [end] Button { @@ -431,15 +454,16 @@ And the following blueprint code... Translatable Strings -------------------- -Mark any string as translatable using this syntax: `_("...")`. +Mark any string as translatable using this syntax: ``_("...")``. Two strings that are the same in English could be translated in different ways in other languages because of different *contexts*. Translatable -strings with context look like this: `C_("context", "...")`. An example +strings with context look like this: ``C_("context", "...")``. An example where a context is needed is the word "have", which in Spanish could translate to "tener" or "haber". .. code-block:: + Label { label: C_("1st have", "have"); } From ba8ec804562f407a6b22af346c0a799544725858 Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Oct 2022 12:04:47 +0000 Subject: [PATCH 08/14] Apply 6 suggestion(s) to 1 file(s) --- docs/tutorial.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 9305b51..138a24a 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -86,7 +86,7 @@ A good place to start is Naming Widgets ~~~~~~~~~~~~~~ -Widgets can be given **name/ID**s so that they can be referenced by other +Widgets can be given a **name/ID** so that they can be referenced by other widgets in the blueprint. .. code-block:: @@ -301,7 +301,9 @@ Templates CSS Style Classes ----------------- -.. Unsure if to group styles with widget-specific items + +.. TODO: Unsure if to group styles with widget-specific items + Widgets can be given style classes that can be used with your CSS or `predefined styles `_ in libraries like Libadwaita. @@ -350,8 +352,8 @@ window, or pop up when you right-click some other widget. In Blueprint a ``menu`` is a ``Gio.MenuModel`` that can be shown by MenuButtons or other widgets. -In Blueprint, ``menu``s have *items*, *sections*, and *submenus*. -Like widgets, ``menu``s can also be given a **ID**. +In Blueprint, a ``menu`` can have *items*, *sections*, and *submenus*. +Like widgets, a ``menu`` can also be given an **ID**. The `Menu Model section of the Gtk.PopoverMenu documentation `_ has complete details on the menu model. @@ -413,7 +415,7 @@ or the *end* of the Headerbar. Child widgets of HeaderBars can have the *start* or *end* types. Values for child types a widget can have are defined in the widget's documentation. -Child types in blueprint are written between square brackets [] and before +Child types in blueprint are written between square brackets ``[]`` and before the child the type is for. The following blueprint code... @@ -429,6 +431,8 @@ The following blueprint code... \... would look like this: +.. code-block:: + --------------------------- | Button | --------------------------- @@ -446,6 +450,8 @@ And the following blueprint code... \... would look like this: +.. code-block:: + --------------------------- | Button | --------------------------- From 13e477aa25c9e0951dc14f89810f10fad3df25df Mon Sep 17 00:00:00 2001 From: Megadash452 Date: Wed, 19 Oct 2022 12:39:14 +0000 Subject: [PATCH 09/14] Tutorial: Fixed a broken link, and some other tweaks. --- docs/tutorial.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 138a24a..07495e3 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -81,13 +81,13 @@ Other namespaces must be written explicitly. Consult the widget library's documentation for a list of widgets. A good place to start is -`the Gtk4 widget list `. +`the Gtk4 widget list `_. Naming Widgets ~~~~~~~~~~~~~~ -Widgets can be given a **name/ID** so that they can be referenced by other -widgets in the blueprint. +Widgets can be given a **name/ID** so that they can be referenced by your +program or other widgets in the blueprint. .. code-block:: @@ -178,7 +178,7 @@ OR } Note the use of a semicolon at the end of the property in both cases. -Widget properties are not exempt of this rule. +Inline widget properties are not exempt of this rule. Property Bindings @@ -261,7 +261,7 @@ your language's bindings of Gtk. By default, signals in the blueprint will pass the widget that the signal is for as an argument to the *handler*. However, you can specify the -widget that is passed to the handler by referencing its **id** inside the +widget that is passed to the handler by referencing its **ID** inside the parenthesis. .. code-block:: @@ -278,11 +278,11 @@ parenthesis. Custom Widget Classes --------------------- -Some programs have custom widgets defined in their logic, and so blueprint +Some programs have custom widgets defined in their logic, so blueprint won't know that they exist. Writing widgets not defined in the GIR will result in an error. Prepend a custom widget with a ``.`` to prevent the -compiler from trying to validate the widget. This is essentially leaving -out the *namespace*. +compiler from trying to validate the widget. This is essentially saying +the widget has no *namespace*. To register a custom widget with the application consult the documentation for your language's bindings of Gtk. @@ -340,7 +340,7 @@ be used for any widget. Similarly to how every widget has styles, ] } -See `examples `_ for a list of more of these +See :doc:`examples ` for a list of more of these widget-specific items. @@ -348,7 +348,7 @@ Menus ----- Menus are usually the widgets that are placed along the top-bar of a -window, or pop up when you right-click some other widget. In Blueprint a +window, or pop up when you right-click some other widget. In Blueprint, a ``menu`` is a ``Gio.MenuModel`` that can be shown by MenuButtons or other widgets. @@ -410,7 +410,7 @@ Child Types ----------- Child types describe how a child widget is placed on a parent widget. For -example, HeaderBars widgets can have children placed either at the *start* +example, HeaderBar widgets can have children placed either at the *start* or the *end* of the Headerbar. Child widgets of HeaderBars can have the *start* or *end* types. Values for child types a widget can have are defined in the widget's documentation. From e1f972ef164a9ac9b2888c909d7910d9479e7f8e Mon Sep 17 00:00:00 2001 From: "FeRD (Frank Dana)" Date: Wed, 19 Oct 2022 14:00:09 +0000 Subject: [PATCH 10/14] Apply 5 suggestion(s) to 1 file(s) --- docs/tutorial.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 07495e3..7fdbf5a 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -115,7 +115,7 @@ Write properties inside the curly brackets of a widget: } Properties values are *all lowercase* (except strings) and must end with a -semicolon (;). +semicolon (``;``). Property Types ~~~~~~~~~~~~~~ @@ -280,7 +280,7 @@ Custom Widget Classes Some programs have custom widgets defined in their logic, so blueprint won't know that they exist. Writing widgets not defined in the GIR will -result in an error. Prepend a custom widget with a ``.`` to prevent the +result in an error. Prepend a custom widget with a period (``.``) to prevent the compiler from trying to validate the widget. This is essentially saying the widget has no *namespace*. @@ -327,7 +327,7 @@ Non-property Elements Some widgets will have elements which are not properties, but they sort of act like properties. Most of the time they will be specific only to a certain widget. *Styles* is one of these elements, except that styles can -be used for any widget. Similarly to how every widget has styles, +be used for any widget. Similar to how every widget has styles, ``Gtk.ComboBoxText`` has *items*: .. code-block:: @@ -411,11 +411,11 @@ Child Types Child types describe how a child widget is placed on a parent widget. For example, HeaderBar widgets can have children placed either at the *start* -or the *end* of the Headerbar. Child widgets of HeaderBars can have the +or the *end* of the HeaderBar. Child widgets of HeaderBars can have the *start* or *end* types. Values for child types a widget can have are defined in the widget's documentation. -Child types in blueprint are written between square brackets ``[]`` and before +Child types in blueprint are written between square brackets (``[`` ``]``) and before the child the type is for. The following blueprint code... From ac70ea7403abebc895b3b60082842604156babfd Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Wed, 13 Nov 2024 00:48:16 +0200 Subject: [PATCH 11/14] Port to libgirepository-2.0 pygobject 3.52 has switched [1] to using libgirepository-2.0 which comes from glib itself now, rather than the 1.0 which came from gobject-introspection. This means that it fails to load the incompatible "GIRepository 2.0" and thus must be ported to 3.0 (which is provided by libgirepository-2.0). Migration guide is here [2] [1]: https://gitlab.gnome.org/GNOME/pygobject/-/merge_requests/320 [2]: https://docs.gtk.org/girepository/migrating-gi.html This commit adds suppport for importing with "gi.require_version("GIRepository", "3.0") and falling back to the existing "GIRepository 2.0" if not found. --- blueprintcompiler/gir.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/blueprintcompiler/gir.py b/blueprintcompiler/gir.py index 30a5eaa..e54b849 100644 --- a/blueprintcompiler/gir.py +++ b/blueprintcompiler/gir.py @@ -24,8 +24,20 @@ from functools import cached_property import gi # type: ignore -gi.require_version("GIRepository", "2.0") -from gi.repository import GIRepository # type: ignore +try: + gi.require_version("GIRepository", "3.0") + from gi.repository import GIRepository # type: ignore + + _repo = GIRepository.Repository() +except ValueError: + # We can remove this once we can bump the minimum dependencies + # to glib 2.80 and pygobject 3.52 + # dependency('glib-2.0', version: '>= 2.80.0') + # dependency('girepository-2.0', version: '>= 2.80.0') + gi.require_version("GIRepository", "2.0") + from gi.repository import GIRepository # type: ignore + + _repo = GIRepository.Repository from . import typelib, xml_reader from .errors import CompileError, CompilerBugError @@ -42,7 +54,7 @@ def add_typelib_search_path(path: str): def get_namespace(namespace: str, version: str) -> "Namespace": - search_paths = [*GIRepository.Repository.get_search_path(), *_user_search_paths] + search_paths = [*_repo.get_search_path(), *_user_search_paths] filename = f"{namespace}-{version}.typelib" @@ -74,7 +86,7 @@ def get_available_namespaces() -> T.List[T.Tuple[str, str]]: return _available_namespaces search_paths: list[str] = [ - *GIRepository.Repository.get_search_path(), + *_repo.get_search_path(), *_user_search_paths, ] From 5b0f662478343270a1ada82938534cc0c91bef07 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 21 Dec 2024 17:22:56 -0600 Subject: [PATCH 12/14] completions: Detect translatable properties Looked through the Gtk documentation (and a few other libraries) to make a list of all the properties that should probably be translated. If a property is on the list, the language server will mark it as translated in completions. --- blueprintcompiler/annotations.py | 191 +++++++++++++++++++++++++++++++ blueprintcompiler/completions.py | 10 +- 2 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 blueprintcompiler/annotations.py diff --git a/blueprintcompiler/annotations.py b/blueprintcompiler/annotations.py new file mode 100644 index 0000000..c40de13 --- /dev/null +++ b/blueprintcompiler/annotations.py @@ -0,0 +1,191 @@ +# annotations.py +# +# Copyright 2024 James Westman +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see . +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# Extra information about types in common libraries that's used for things like completions. + +import typing as T +from dataclasses import dataclass + +from . import gir + + +@dataclass +class Annotation: + translatable_properties: T.List[str] + + +def is_property_translated(property: gir.Property): + ns = property.get_containing(gir.Namespace) + ns_name = ns.name + "-" + ns.version + if annotation := _ANNOTATIONS.get(ns_name): + assert property.container is not None + return ( + property.container.name + ":" + property.name + in annotation.translatable_properties + ) + else: + return False + + +_ANNOTATIONS = { + "Gtk-4.0": Annotation( + translatable_properties=[ + "AboutDialog:comments", + "AboutDialog:translator-credits", + "AboutDialog:website-label", + "AlertDialog:detail", + "AlertDialog:message", + "AppChooserButton:heading", + "AppChooserDialog:heading", + "AppChooserWidget:default-text", + "AssistantPage:title", + "Button:label", + "CellRendererText:markup", + "CellRendererText:placeholder-text", + "CellRendererText:text", + "CheckButton:label", + "ColorButton:title", + "ColorDialog:title", + "ColumnViewColumn:title", + "ColumnViewRow:accessible-description", + "ColumnViewRow:accessible-label", + "Entry:placeholder-text", + "Entry:primary-icon-tooltip-markup", + "Entry:primary-icon-tooltip-text", + "Entry:secondary-icon-tooltip-markup", + "Entry:secondary-icon-tooltip-text", + "EntryBuffer:text", + "Expander:label", + "FileChooserNative:accept-label", + "FileChooserNative:cancel-label", + "FileChooserWidget:subtitle", + "FileDialog:accept-label", + "FileDialog:title", + "FileDialog:initial-name", + "FileFilter:name", + "FontButton:title", + "FontDialog:title", + "Frame:label", + "Inscription:markup", + "Inscription:text", + "Label:label", + "ListItem:accessible-description", + "ListItem:accessible-label", + "LockButton:text-lock", + "LockButton:text-unlock", + "LockButton:tooltip-lock", + "LockButton:tooltip-not-authorized", + "LockButton:tooltip-unlock", + "MenuButton:label", + "MessageDialog:secondary-text", + "MessageDialog:text", + "NativeDialog:title", + "NotebookPage:menu-label", + "NotebookPage:tab-label", + "PasswordEntry:placeholder-text", + "Picture:alternative-text", + "PrintDialog:accept-label", + "PrintDialog:title", + "Printer:name", + "PrintJob:title", + "PrintOperation:custom-tab-label", + "PrintOperation:export-filename", + "PrintOperation:job-name", + "ProgressBar:text", + "SearchEntry:placeholder-text", + "ShortcutLabel:disabled-text", + "ShortcutsGroup:title", + "ShortcutsSection:title", + "ShortcutsShortcut:title", + "ShortcutsShortcut:subtitle", + "StackPage:title", + "Text:placeholder-text", + "TextBuffer:text", + "TreeViewColumn:title", + "Widget:tooltip-markup", + "Widget:tooltip-text", + "Window:title", + "Editable:text", + "FontChooser:preview-text", + ] + ), + "Adw-1": Annotation( + translatable_properties=[ + "AboutDialog:comments", + "AboutDialog:translator-credits", + "AboutWindow:comments", + "AboutWindow:translator-credits", + "ActionRow:subtitle", + "ActionRow:title", + "AlertDialog:body", + "AlertDialog:heading", + "Avatar:text", + "Banner:button-label", + "Banner:title", + "ButtonContent:label", + "Dialog:title", + "ExpanderRow:subtitle", + "MessageDialog:body", + "MessageDialog:heading", + "NavigationPage:title", + "PreferencesGroup:description", + "PreferencesGroup:title", + "PreferencesPage:description", + "PreferencesPage:title", + "PreferencesRow:title", + "SplitButton:dropdown-tooltip", + "SplitButton:label", + "StatusPage:description", + "StatusPage:title", + "TabPage:indicator-tooltip", + "TabPage:keyword", + "TabPage:title", + "Toast:button-label", + "Toast:title", + "ViewStackPage:title", + "ViewSwitcherTitle:subtitle", + "ViewSwitcherTitle:title", + "WindowTitle:subtitle", + "WindowTitle:title", + ] + ), + "Shumate-1.0": Annotation( + translatable_properties=[ + "License:extra-text", + "MapSource:license", + "MapSource:name", + ] + ), + "GtkSource-5": Annotation( + translatable_properties=[ + "CompletionCell:markup", + "CompletionCell:text", + "CompletionSnippets:title", + "CompletionWords:title", + "GutterRendererText:markup", + "GutterRendererText:text", + "SearchSettings:search-text", + "Snippet:description", + "Snippet:name", + "SnippetChunk:tooltip-text", + "StyleScheme:description", + "StyleScheme:name", + ] + ), +} diff --git a/blueprintcompiler/completions.py b/blueprintcompiler/completions.py index e05d6ee..e682513 100644 --- a/blueprintcompiler/completions.py +++ b/blueprintcompiler/completions.py @@ -20,7 +20,7 @@ import sys import typing as T -from . import gir, language +from . import annotations, gir, language from .ast_utils import AstNode from .completions_utils import * from .language.types import ClassName @@ -154,11 +154,17 @@ def property_completer(lsp, ast_node, match_variables): detail=prop.detail, ) elif isinstance(prop.type, gir.StringType): + snippet = ( + f'{prop_name}: _("$0");' + if annotations.is_property_translated(prop) + else f'{prop_name}: "$0";' + ) + yield Completion( prop_name, CompletionItemKind.Property, sort_text=f"0 {prop_name}", - snippet=f'{prop_name}: "$0";', + snippet=snippet, docs=prop.doc, detail=prop.detail, ) From 9b9fab832bb5dc3a23b6a25ac8233f7db1c62976 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sun, 22 Dec 2024 18:00:39 -0600 Subject: [PATCH 13/14] Add tests, remove unused code, fix bugs - Added tests for more error messages - Test the "go to reference" feature at every character index of every test case - Delete unused code and imports - Fix some bugs I found along the way --- blueprintcompiler/ast_utils.py | 32 +++++++++++---- blueprintcompiler/completions.py | 11 ++--- blueprintcompiler/completions_utils.py | 11 ----- blueprintcompiler/formatter.py | 7 ++-- blueprintcompiler/gir.py | 41 +++++++------------ blueprintcompiler/language/__init__.py | 3 +- .../language/adw_response_dialog.py | 5 --- blueprintcompiler/language/attributes.py | 32 --------------- blueprintcompiler/language/expression.py | 21 ---------- .../language/gobject_property.py | 2 +- blueprintcompiler/language/gobject_signal.py | 2 +- blueprintcompiler/language/gtk_a11y.py | 4 +- .../language/gtk_combo_box_text.py | 1 - .../language/gtk_list_item_factory.py | 11 ++--- blueprintcompiler/language/imports.py | 14 ++----- blueprintcompiler/outputs/xml/__init__.py | 5 ++- blueprintcompiler/outputs/xml/xml_emitter.py | 4 +- blueprintcompiler/parse_tree.py | 35 +--------------- tests/formatting/comment_in.blp | 2 + tests/formatting/comment_out.blp | 2 + .../sample_errors/float_to_int_assignment.blp | 5 +++ .../sample_errors/float_to_int_assignment.err | 1 + tests/sample_errors/int_object.blp | 3 ++ tests/sample_errors/int_object.err | 1 + tests/sample_errors/menu_assignment.blp | 7 ++++ tests/sample_errors/menu_assignment.err | 1 + .../string_to_num_assignment.blp | 5 +++ .../string_to_num_assignment.err | 1 + .../string_to_object_assignment.blp | 5 +++ .../string_to_object_assignment.err | 1 + .../string_to_type_assignment.blp | 6 +++ .../string_to_type_assignment.err | 1 + tests/sample_errors/translated_assignment.blp | 5 +++ tests/sample_errors/translated_assignment.err | 1 + tests/sample_errors/typeof_assignment.blp | 5 +++ tests/sample_errors/typeof_assignment.err | 1 + tests/sample_errors/unrecognized_syntax.blp | 1 + tests/sample_errors/unrecognized_syntax.err | 1 + tests/sample_errors/upgrade_sync_create.blp | 5 +++ tests/sample_errors/upgrade_sync_create.err | 1 + .../upgrade_template_list_item.blp | 5 +++ .../upgrade_template_list_item.err | 1 + tests/samples/property_binding.blp | 1 + tests/samples/property_binding.ui | 1 + tests/samples/property_binding_dec.blp | 11 ----- tests/test_formatter.py | 1 + tests/test_samples.py | 8 +++- 47 files changed, 140 insertions(+), 190 deletions(-) delete mode 100644 blueprintcompiler/language/attributes.py create mode 100644 tests/formatting/comment_in.blp create mode 100644 tests/formatting/comment_out.blp create mode 100644 tests/sample_errors/float_to_int_assignment.blp create mode 100644 tests/sample_errors/float_to_int_assignment.err create mode 100644 tests/sample_errors/int_object.blp create mode 100644 tests/sample_errors/int_object.err create mode 100644 tests/sample_errors/menu_assignment.blp create mode 100644 tests/sample_errors/menu_assignment.err create mode 100644 tests/sample_errors/string_to_num_assignment.blp create mode 100644 tests/sample_errors/string_to_num_assignment.err create mode 100644 tests/sample_errors/string_to_object_assignment.blp create mode 100644 tests/sample_errors/string_to_object_assignment.err create mode 100644 tests/sample_errors/string_to_type_assignment.blp create mode 100644 tests/sample_errors/string_to_type_assignment.err create mode 100644 tests/sample_errors/translated_assignment.blp create mode 100644 tests/sample_errors/translated_assignment.err create mode 100644 tests/sample_errors/typeof_assignment.blp create mode 100644 tests/sample_errors/typeof_assignment.err create mode 100644 tests/sample_errors/unrecognized_syntax.blp create mode 100644 tests/sample_errors/unrecognized_syntax.err create mode 100644 tests/sample_errors/upgrade_sync_create.blp create mode 100644 tests/sample_errors/upgrade_sync_create.err create mode 100644 tests/sample_errors/upgrade_template_list_item.blp create mode 100644 tests/sample_errors/upgrade_template_list_item.err delete mode 100644 tests/samples/property_binding_dec.blp diff --git a/blueprintcompiler/ast_utils.py b/blueprintcompiler/ast_utils.py index bd5befa..8f742e0 100644 --- a/blueprintcompiler/ast_utils.py +++ b/blueprintcompiler/ast_utils.py @@ -160,6 +160,11 @@ class AstNode: yield e if e.fatal: return + except MultipleErrors as e: + for error in e.errors: + yield error + if error.fatal: + return for child in self.children: yield from child._get_errors() @@ -249,14 +254,7 @@ def validate( if skip_incomplete and self.incomplete: return - try: - func(self) - except CompileError as e: - # If the node is only partially complete, then an error must - # have already been reported at the parsing stage - if self.incomplete: - return - + def fill_error(e: CompileError): if e.range is None: e.range = ( Range.join( @@ -266,8 +264,26 @@ def validate( or self.range ) + try: + func(self) + except CompileError as e: + # If the node is only partially complete, then an error must + # have already been reported at the parsing stage + if self.incomplete: + return + + fill_error(e) + # Re-raise the exception raise e + except MultipleErrors as e: + if self.incomplete: + return + + for error in e.errors: + fill_error(error) + + raise e inner._validator = True return inner diff --git a/blueprintcompiler/completions.py b/blueprintcompiler/completions.py index e682513..5d36739 100644 --- a/blueprintcompiler/completions.py +++ b/blueprintcompiler/completions.py @@ -17,7 +17,6 @@ # # SPDX-License-Identifier: LGPL-3.0-or-later -import sys import typing as T from . import annotations, gir, language @@ -31,10 +30,6 @@ from .tokenizer import Token, TokenType Pattern = T.List[T.Tuple[TokenType, T.Optional[str]]] -def debug(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) - - def _complete( lsp, ast_node: AstNode, tokens: T.List[Token], idx: int, token_idx: int ) -> T.Iterator[Completion]: @@ -139,7 +134,7 @@ def gtk_object_completer(lsp, ast_node, match_variables): matches=new_statement_patterns, ) def property_completer(lsp, ast_node, match_variables): - if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.ExternType): + if ast_node.gir_class and hasattr(ast_node.gir_class, "properties"): for prop_name, prop in ast_node.gir_class.properties.items(): if ( isinstance(prop.type, gir.BoolType) @@ -194,7 +189,7 @@ def property_completer(lsp, ast_node, match_variables): @completer( - applies_in=[language.Property, language.BaseAttribute], + applies_in=[language.Property, language.A11yProperty], matches=[[(TokenType.IDENT, None), (TokenType.OP, ":")]], ) def prop_value_completer(lsp, ast_node, match_variables): @@ -218,7 +213,7 @@ def prop_value_completer(lsp, ast_node, match_variables): matches=new_statement_patterns, ) def signal_completer(lsp, ast_node, match_variables): - if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.ExternType): + if ast_node.gir_class and hasattr(ast_node.gir_class, "signals"): for signal_name, signal in ast_node.gir_class.signals.items(): if not isinstance(ast_node.parent, language.Object): name = "on" diff --git a/blueprintcompiler/completions_utils.py b/blueprintcompiler/completions_utils.py index 03bec0f..eccf125 100644 --- a/blueprintcompiler/completions_utils.py +++ b/blueprintcompiler/completions_utils.py @@ -31,17 +31,6 @@ new_statement_patterns = [ ] -def applies_to(*ast_types): - """Decorator describing which AST nodes the completer should apply in.""" - - def decorator(func): - for c in ast_types: - c.completers.append(func) - return func - - return decorator - - def completer(applies_in: T.List, matches: T.List = [], applies_in_subclass=None): def decorator(func): def inner(prev_tokens: T.List[Token], ast_node, lsp): diff --git a/blueprintcompiler/formatter.py b/blueprintcompiler/formatter.py index c003d45..35da5d2 100644 --- a/blueprintcompiler/formatter.py +++ b/blueprintcompiler/formatter.py @@ -20,7 +20,8 @@ import re from enum import Enum -from . import tokenizer, utils +from . import tokenizer +from .errors import CompilerBugError from .tokenizer import TokenType OPENING_TOKENS = ("{", "[") @@ -192,8 +193,8 @@ def format(data, tab_size=2, insert_space=True): commit_current_line(LineType.COMMENT, newlines_before=newlines) - else: - commit_current_line() + else: # pragma: no cover + raise CompilerBugError() elif str_item == "(" and ( re.match(r"^([A-Za-z_\-])+\s*\(", current_line) or watch_parentheses diff --git a/blueprintcompiler/gir.py b/blueprintcompiler/gir.py index e54b849..333f4ac 100644 --- a/blueprintcompiler/gir.py +++ b/blueprintcompiler/gir.py @@ -467,10 +467,13 @@ class Signature(GirNode): return result @cached_property - def return_type(self) -> GirType: - return self.get_containing(Repository)._resolve_type_id( - self.tl.SIGNATURE_RETURN_TYPE - ) + def return_type(self) -> T.Optional[GirType]: + if self.tl.SIGNATURE_RETURN_TYPE == 0: + return None + else: + return self.get_containing(Repository)._resolve_type_id( + self.tl.SIGNATURE_RETURN_TYPE + ) class Signal(GirNode): @@ -490,7 +493,10 @@ class Signal(GirNode): args = ", ".join( [f"{a.type.full_name} {a.name}" for a in self.gir_signature.args] ) - return f"signal {self.container.full_name}::{self.name} ({args})" + result = f"signal {self.container.full_name}::{self.name} ({args})" + if self.gir_signature.return_type is not None: + result += f" -> {self.gir_signature.return_type.full_name}" + return result @property def online_docs(self) -> T.Optional[str]: @@ -902,14 +908,6 @@ class Namespace(GirNode): if isinstance(entry, Class) } - @cached_property - def interfaces(self) -> T.Mapping[str, Interface]: - return { - name: entry - for name, entry in self.entries.items() - if isinstance(entry, Interface) - } - def get_type(self, name) -> T.Optional[GirType]: """Gets a type (class, interface, enum, etc.) from this namespace.""" return self.entries.get(name) @@ -933,13 +931,8 @@ class Namespace(GirNode): """Looks up a type in the scope of this namespace (including in the namespace's dependencies).""" - if type_name in _BASIC_TYPES: - return _BASIC_TYPES[type_name]() - elif "." in type_name: - ns, name = type_name.split(".", 1) - return self.get_containing(Repository).get_type(name, ns) - else: - return self.get_type(type_name) + ns, name = type_name.split(".", 1) + return self.get_containing(Repository).get_type(name, ns) @property def online_docs(self) -> T.Optional[str]: @@ -958,7 +951,7 @@ class Repository(GirNode): self.includes = { name: get_namespace(name, version) for name, version in deps } - except: + except: # pragma: no cover raise CompilerBugError(f"Failed to load dependencies.") else: self.includes = {} @@ -966,12 +959,6 @@ class Repository(GirNode): def get_type(self, name: str, ns: str) -> T.Optional[GirType]: return self.lookup_namespace(ns).get_type(name) - def get_type_by_cname(self, name: str) -> T.Optional[GirType]: - for ns in [self.namespace, *self.includes.values()]: - if type := ns.get_type_by_cname(name): - return type - return None - def lookup_namespace(self, ns: str): """Finds a namespace among this namespace's dependencies.""" if ns == self.namespace.name: diff --git a/blueprintcompiler/language/__init__.py b/blueprintcompiler/language/__init__.py index b302686..e797eaa 100644 --- a/blueprintcompiler/language/__init__.py +++ b/blueprintcompiler/language/__init__.py @@ -4,7 +4,6 @@ from .adw_breakpoint import ( AdwBreakpointSetters, ) from .adw_response_dialog import ExtAdwResponseDialog -from .attributes import BaseAttribute from .binding import Binding from .common import * from .contexts import ScopeCtx, ValueTypeCtx @@ -20,7 +19,7 @@ from .expression import ( from .gobject_object import Object, ObjectContent from .gobject_property import Property from .gobject_signal import Signal -from .gtk_a11y import ExtAccessibility +from .gtk_a11y import A11yProperty, ExtAccessibility from .gtk_combo_box_text import ExtComboBoxItems from .gtk_file_filter import ( Filters, diff --git a/blueprintcompiler/language/adw_response_dialog.py b/blueprintcompiler/language/adw_response_dialog.py index 5493d4d..d2680fd 100644 --- a/blueprintcompiler/language/adw_response_dialog.py +++ b/blueprintcompiler/language/adw_response_dialog.py @@ -20,7 +20,6 @@ from ..decompiler import decompile_translatable, truthy from .common import * -from .contexts import ValueTypeCtx from .gobject_object import ObjectContent, validate_parent_type from .values import StringValue @@ -94,10 +93,6 @@ class ExtAdwResponseDialogResponse(AstNode): self.value.range.text, ) - @context(ValueTypeCtx) - def value_type(self) -> ValueTypeCtx: - return ValueTypeCtx(StringType()) - @validate("id") def unique_in_parent(self): self.validate_unique_in_parent( diff --git a/blueprintcompiler/language/attributes.py b/blueprintcompiler/language/attributes.py deleted file mode 100644 index 8ff1f0b..0000000 --- a/blueprintcompiler/language/attributes.py +++ /dev/null @@ -1,32 +0,0 @@ -# attributes.py -# -# Copyright 2022 James Westman -# -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. -# -# This file is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program. If not, see . -# -# SPDX-License-Identifier: LGPL-3.0-or-later - - -from .common import * - - -class BaseAttribute(AstNode): - """A helper class for attribute syntax of the form `name: literal_value;`""" - - tag_name: str = "" - attr_name: str = "name" - - @property - def name(self): - return self.tokens["name"] diff --git a/blueprintcompiler/language/expression.py b/blueprintcompiler/language/expression.py index ae9c399..f305035 100644 --- a/blueprintcompiler/language/expression.py +++ b/blueprintcompiler/language/expression.py @@ -38,10 +38,6 @@ class ExprBase(AstNode): def type(self) -> T.Optional[GirType]: raise NotImplementedError() - @property - def type_complete(self) -> bool: - return True - @property def rhs(self) -> T.Optional["ExprBase"]: if isinstance(self.parent, Expression): @@ -65,10 +61,6 @@ class Expression(ExprBase): def type(self) -> T.Optional[GirType]: return self.last.type - @property - def type_complete(self) -> bool: - return self.last.type_complete - class InfixExpr(ExprBase): @property @@ -99,15 +91,6 @@ class LiteralExpr(ExprBase): def type(self) -> T.Optional[GirType]: return self.literal.value.type - @property - def type_complete(self) -> bool: - from .values import IdentLiteral - - if isinstance(self.literal.value, IdentLiteral): - if object := self.context[ScopeCtx].objects.get(self.literal.value.ident): - return not object.gir_class.incomplete - return True - class LookupOp(InfixExpr): grammar = [".", UseIdent("property")] @@ -211,10 +194,6 @@ class CastExpr(InfixExpr): def type(self) -> T.Optional[GirType]: return self.children[TypeName][0].gir_type - @property - def type_complete(self) -> bool: - return True - @validate() def cast_makes_sense(self): if self.type is None or self.lhs.type is None: diff --git a/blueprintcompiler/language/gobject_property.py b/blueprintcompiler/language/gobject_property.py index 5d0c867..b553909 100644 --- a/blueprintcompiler/language/gobject_property.py +++ b/blueprintcompiler/language/gobject_property.py @@ -51,7 +51,7 @@ class Property(AstNode): @property def document_symbol(self) -> DocumentSymbol: - if isinstance(self.value, ObjectValue): + if isinstance(self.value, ObjectValue) or self.value is None: detail = None else: detail = self.value.range.text diff --git a/blueprintcompiler/language/gobject_signal.py b/blueprintcompiler/language/gobject_signal.py index 79f9ae7..0e0332e 100644 --- a/blueprintcompiler/language/gobject_signal.py +++ b/blueprintcompiler/language/gobject_signal.py @@ -122,7 +122,7 @@ class Signal(AstNode): ) def get_reference(self, idx: int) -> T.Optional[LocationLink]: - if idx in self.group.tokens["object"].range: + if self.object_id is not None and idx in self.group.tokens["object"].range: obj = self.context[ScopeCtx].objects.get(self.object_id) if obj is not None: return LocationLink( diff --git a/blueprintcompiler/language/gtk_a11y.py b/blueprintcompiler/language/gtk_a11y.py index 3657565..0cc3cb3 100644 --- a/blueprintcompiler/language/gtk_a11y.py +++ b/blueprintcompiler/language/gtk_a11y.py @@ -19,8 +19,6 @@ import typing as T -from ..decompiler import escape_quote -from .attributes import BaseAttribute from .common import * from .contexts import ValueTypeCtx from .gobject_object import ObjectContent, validate_parent_type @@ -119,7 +117,7 @@ def _get_docs(gir, name): return gir_type.doc -class A11yProperty(BaseAttribute): +class A11yProperty(AstNode): grammar = Statement( UseIdent("name"), ":", diff --git a/blueprintcompiler/language/gtk_combo_box_text.py b/blueprintcompiler/language/gtk_combo_box_text.py index 312750a..32b3486 100644 --- a/blueprintcompiler/language/gtk_combo_box_text.py +++ b/blueprintcompiler/language/gtk_combo_box_text.py @@ -19,7 +19,6 @@ from .common import * -from .contexts import ValueTypeCtx from .gobject_object import ObjectContent, validate_parent_type from .values import StringValue diff --git a/blueprintcompiler/language/gtk_list_item_factory.py b/blueprintcompiler/language/gtk_list_item_factory.py index 3309c08..c9e1399 100644 --- a/blueprintcompiler/language/gtk_list_item_factory.py +++ b/blueprintcompiler/language/gtk_list_item_factory.py @@ -50,7 +50,7 @@ class ExtListItemFactory(AstNode): else: return self.root.gir.get_type("ListItem", "Gtk") - @validate("template") + @validate("id") def container_is_builder_list(self): validate_parent_type( self, @@ -59,7 +59,7 @@ class ExtListItemFactory(AstNode): "sub-templates", ) - @validate("template") + @validate("id") def unique_in_parent(self): self.validate_unique_in_parent("Duplicate template block") @@ -76,7 +76,7 @@ class ExtListItemFactory(AstNode): f"Only Gtk.ListItem, Gtk.ListHeader, Gtk.ColumnViewRow, or Gtk.ColumnViewCell is allowed as a type here" ) - @validate("template") + @validate("id") def type_name_upgrade(self): if self.type_name is None: raise UpgradeWarning( @@ -103,10 +103,7 @@ class ExtListItemFactory(AstNode): @property def action_widgets(self): - """ - The sub-template shouldn't have it`s own actions this is - just hear to satisfy XmlOutput._emit_object_or_template - """ + # The sub-template shouldn't have its own actions, this is just here to satisfy XmlOutput._emit_object_or_template return None @docs("id") diff --git a/blueprintcompiler/language/imports.py b/blueprintcompiler/language/imports.py index 3060bea..2d4bcf6 100644 --- a/blueprintcompiler/language/imports.py +++ b/blueprintcompiler/language/imports.py @@ -59,14 +59,8 @@ class GtkDirective(AstNode): @property def gir_namespace(self): - # validate the GTK version first to make sure the more specific error - # message is emitted - self.gtk_version() - if self.tokens["version"] is not None: - return gir.get_namespace("Gtk", self.tokens["version"]) - else: - # For better error handling, just assume it's 4.0 - return gir.get_namespace("Gtk", "4.0") + # For better error handling, just assume it's 4.0 + return gir.get_namespace("Gtk", "4.0") @docs() def ref_docs(self): @@ -90,7 +84,7 @@ class Import(AstNode): @validate("namespace", "version") def namespace_exists(self): - gir.get_namespace(self.tokens["namespace"], self.tokens["version"]) + gir.get_namespace(self.namespace, self.version) @validate() def unused(self): @@ -106,7 +100,7 @@ class Import(AstNode): @property def gir_namespace(self): try: - return gir.get_namespace(self.tokens["namespace"], self.tokens["version"]) + return gir.get_namespace(self.namespace, self.version) except CompileError: return None diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index 5e43834..420f6ef 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -366,12 +366,13 @@ class XmlOutput(OutputFormat): elif isinstance(extension, ExtScaleMarks): xml.start_tag("marks") - for mark in extension.children: + for mark in extension.marks: + label = mark.label.child if mark.label is not None else None xml.start_tag( "mark", value=mark.value, position=mark.position, - **self._translated_string_attrs(mark.label and mark.label.child), + **self._translated_string_attrs(label), ) if mark.label is not None: xml.put_text(mark.label.string) diff --git a/blueprintcompiler/outputs/xml/xml_emitter.py b/blueprintcompiler/outputs/xml/xml_emitter.py index ca87a49..ea91e03 100644 --- a/blueprintcompiler/outputs/xml/xml_emitter.py +++ b/blueprintcompiler/outputs/xml/xml_emitter.py @@ -40,7 +40,9 @@ class XmlEmitter: self._tag_stack = [] self._needs_newline = False - def start_tag(self, tag, **attrs: T.Union[str, GirType, ClassName, bool, None]): + def start_tag( + self, tag, **attrs: T.Union[str, GirType, ClassName, bool, None, float] + ): self._indent() self.result += f"<{tag}" for key, val in attrs.items(): diff --git a/blueprintcompiler/parse_tree.py b/blueprintcompiler/parse_tree.py index fff6e4a..ae062fb 100644 --- a/blueprintcompiler/parse_tree.py +++ b/blueprintcompiler/parse_tree.py @@ -95,19 +95,11 @@ class ParseGroup: try: return self.ast_type(self, children, self.keys, incomplete=self.incomplete) - except TypeError as e: + except TypeError: # pragma: no cover raise CompilerBugError( f"Failed to construct ast.{self.ast_type.__name__} from ParseGroup. See the previous stacktrace." ) - def __str__(self): - result = str(self.ast_type.__name__) - result += "".join([f"\n{key}: {val}" for key, val in self.keys.items()]) + "\n" - result += "\n".join( - [str(child) for children in self.children.values() for child in children] - ) - return result.replace("\n", "\n ") - class ParseContext: """Contains the state of the parser.""" @@ -265,10 +257,6 @@ class ParseNode: """Convenience method for err().""" return self.err("Expected " + expect) - def warn(self, message) -> "Warning": - """Causes this ParseNode to emit a warning if it parses successfully.""" - return Warning(self, message) - class Err(ParseNode): """ParseNode that emits a compile error if it fails to parse.""" @@ -290,27 +278,6 @@ class Err(ParseNode): return True -class Warning(ParseNode): - """ParseNode that emits a compile warning if it parses successfully.""" - - def __init__(self, child, message: str): - self.child = to_parse_node(child) - self.message = message - - def _parse(self, ctx: ParseContext): - ctx.skip() - start_idx = ctx.index - if self.child.parse(ctx).succeeded(): - start_token = ctx.tokens[start_idx] - end_token = ctx.tokens[ctx.index] - ctx.warnings.append( - CompileWarning(self.message, start_token.start, end_token.end) - ) - return True - else: - return False - - class Fail(ParseNode): """ParseNode that emits a compile error if it parses successfully.""" diff --git a/tests/formatting/comment_in.blp b/tests/formatting/comment_in.blp new file mode 100644 index 0000000..32a907c --- /dev/null +++ b/tests/formatting/comment_in.blp @@ -0,0 +1,2 @@ +using Gtk 4.0; +//comment \ No newline at end of file diff --git a/tests/formatting/comment_out.blp b/tests/formatting/comment_out.blp new file mode 100644 index 0000000..d5dca95 --- /dev/null +++ b/tests/formatting/comment_out.blp @@ -0,0 +1,2 @@ +using Gtk 4.0; +// comment diff --git a/tests/sample_errors/float_to_int_assignment.blp b/tests/sample_errors/float_to_int_assignment.blp new file mode 100644 index 0000000..73b5dc4 --- /dev/null +++ b/tests/sample_errors/float_to_int_assignment.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Entry { + margin-bottom: 10.5; +} diff --git a/tests/sample_errors/float_to_int_assignment.err b/tests/sample_errors/float_to_int_assignment.err new file mode 100644 index 0000000..0e9dc41 --- /dev/null +++ b/tests/sample_errors/float_to_int_assignment.err @@ -0,0 +1 @@ +4,18,4,Cannot convert 10.5 to integer \ No newline at end of file diff --git a/tests/sample_errors/int_object.blp b/tests/sample_errors/int_object.blp new file mode 100644 index 0000000..35b2562 --- /dev/null +++ b/tests/sample_errors/int_object.blp @@ -0,0 +1,3 @@ +using Gtk 4.0; + +int {} diff --git a/tests/sample_errors/int_object.err b/tests/sample_errors/int_object.err new file mode 100644 index 0000000..221e6e6 --- /dev/null +++ b/tests/sample_errors/int_object.err @@ -0,0 +1 @@ +3,1,3,int is not a class \ No newline at end of file diff --git a/tests/sample_errors/menu_assignment.blp b/tests/sample_errors/menu_assignment.blp new file mode 100644 index 0000000..9188d8a --- /dev/null +++ b/tests/sample_errors/menu_assignment.blp @@ -0,0 +1,7 @@ +using Gtk 4.0; + +Overlay { + child: my_menu; +} + +menu my_menu {} diff --git a/tests/sample_errors/menu_assignment.err b/tests/sample_errors/menu_assignment.err new file mode 100644 index 0000000..fb3187f --- /dev/null +++ b/tests/sample_errors/menu_assignment.err @@ -0,0 +1 @@ +4,10,7,Cannot assign Gio.Menu to Gtk.Widget \ No newline at end of file diff --git a/tests/sample_errors/string_to_num_assignment.blp b/tests/sample_errors/string_to_num_assignment.blp new file mode 100644 index 0000000..22e8fba --- /dev/null +++ b/tests/sample_errors/string_to_num_assignment.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Entry { + margin-bottom: "10"; +} diff --git a/tests/sample_errors/string_to_num_assignment.err b/tests/sample_errors/string_to_num_assignment.err new file mode 100644 index 0000000..98a6160 --- /dev/null +++ b/tests/sample_errors/string_to_num_assignment.err @@ -0,0 +1 @@ +4,18,4,Cannot convert string to number \ No newline at end of file diff --git a/tests/sample_errors/string_to_object_assignment.blp b/tests/sample_errors/string_to_object_assignment.blp new file mode 100644 index 0000000..0c070ba --- /dev/null +++ b/tests/sample_errors/string_to_object_assignment.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Button { + child: "Click me"; +} diff --git a/tests/sample_errors/string_to_object_assignment.err b/tests/sample_errors/string_to_object_assignment.err new file mode 100644 index 0000000..f9492af --- /dev/null +++ b/tests/sample_errors/string_to_object_assignment.err @@ -0,0 +1 @@ +4,10,10,Cannot convert string to Gtk.Widget \ No newline at end of file diff --git a/tests/sample_errors/string_to_type_assignment.blp b/tests/sample_errors/string_to_type_assignment.blp new file mode 100644 index 0000000..90f531b --- /dev/null +++ b/tests/sample_errors/string_to_type_assignment.blp @@ -0,0 +1,6 @@ +using Gtk 4.0; +using Gio 2.0; + +Gio.ListStore { + item-type: "Button"; +} diff --git a/tests/sample_errors/string_to_type_assignment.err b/tests/sample_errors/string_to_type_assignment.err new file mode 100644 index 0000000..adb9eb0 --- /dev/null +++ b/tests/sample_errors/string_to_type_assignment.err @@ -0,0 +1 @@ +5,14,8,Cannot convert string to GType \ No newline at end of file diff --git a/tests/sample_errors/translated_assignment.blp b/tests/sample_errors/translated_assignment.blp new file mode 100644 index 0000000..fa8fa9d --- /dev/null +++ b/tests/sample_errors/translated_assignment.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Button { + child: _("Click me"); +} diff --git a/tests/sample_errors/translated_assignment.err b/tests/sample_errors/translated_assignment.err new file mode 100644 index 0000000..78f6b96 --- /dev/null +++ b/tests/sample_errors/translated_assignment.err @@ -0,0 +1 @@ +4,10,13,Cannot convert translated string to Gtk.Widget \ No newline at end of file diff --git a/tests/sample_errors/typeof_assignment.blp b/tests/sample_errors/typeof_assignment.blp new file mode 100644 index 0000000..a20d92c --- /dev/null +++ b/tests/sample_errors/typeof_assignment.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Button { + label: typeof