mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
lsp: Add reference documentation on hover
For most constructs and keywords, show the relevant section of the reference documentation on hover.
This commit is contained in:
parent
b107a85947
commit
e19975e1f8
28 changed files with 326 additions and 21 deletions
|
@ -179,14 +179,16 @@ class AstNode:
|
|||
token = self.group.tokens.get(attr.token_name)
|
||||
if token and token.start <= idx < token.end:
|
||||
return getattr(self, name)
|
||||
else:
|
||||
return getattr(self, name)
|
||||
|
||||
for child in self.children:
|
||||
if idx in child.range:
|
||||
if docs := child.get_docs(idx):
|
||||
return docs
|
||||
|
||||
for name, attr in self._attrs_by_type(Docs):
|
||||
if not attr.token_name:
|
||||
return getattr(self, name)
|
||||
|
||||
return None
|
||||
|
||||
def get_semantic_tokens(self) -> T.Iterator[SemanticToken]:
|
||||
|
|
|
@ -207,6 +207,10 @@ class AdwBreakpointSetters(AstNode):
|
|||
def unique(self):
|
||||
self.validate_unique_in_parent("Duplicate setters block")
|
||||
|
||||
@docs("setters")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtAdwBreakpoint")
|
||||
|
||||
|
||||
@decompiler("condition", cdata=True)
|
||||
def decompile_condition(ctx: DecompileCtx, gir, cdata):
|
||||
|
|
|
@ -138,6 +138,10 @@ class ExtAdwResponseDialog(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate responses block")
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtAdwMessageDialog")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -58,6 +58,10 @@ class BindingFlag(AstNode):
|
|||
"Only bindings with a single lookup can have flags",
|
||||
)
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Binding")
|
||||
|
||||
|
||||
class Binding(AstNode):
|
||||
grammar = [
|
||||
|
@ -99,6 +103,10 @@ class Binding(AstNode):
|
|||
actions=[CodeAction("use 'bind'", "bind")],
|
||||
)
|
||||
|
||||
@docs("bind")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Binding")
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimpleBinding:
|
||||
|
|
|
@ -55,6 +55,7 @@ from ..lsp_utils import (
|
|||
SemanticToken,
|
||||
SemanticTokenType,
|
||||
SymbolKind,
|
||||
get_docs_section,
|
||||
)
|
||||
from ..parse_tree import *
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ class LookupOp(InfixExpr):
|
|||
|
||||
class CastExpr(InfixExpr):
|
||||
grammar = [
|
||||
"as",
|
||||
Keyword("as"),
|
||||
AnyOf(
|
||||
["<", TypeName, Match(">").expected()],
|
||||
[
|
||||
|
@ -220,6 +220,10 @@ class CastExpr(InfixExpr):
|
|||
],
|
||||
)
|
||||
|
||||
@docs("as")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax CastExpression")
|
||||
|
||||
|
||||
class ClosureArg(AstNode):
|
||||
grammar = Expression
|
||||
|
@ -269,6 +273,10 @@ class ClosureExpr(ExprBase):
|
|||
if not self.tokens["extern"]:
|
||||
raise CompileError(f"{self.closure_name} is not a builtin function")
|
||||
|
||||
@docs("name")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ClosureExpression")
|
||||
|
||||
|
||||
expr.children = [
|
||||
AnyOf(ClosureExpr, LiteralExpr, ["(", Expression, ")"]),
|
||||
|
|
|
@ -40,6 +40,10 @@ class SignalFlag(AstNode):
|
|||
f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag
|
||||
)
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Signal")
|
||||
|
||||
|
||||
class Signal(AstNode):
|
||||
grammar = Statement(
|
||||
|
@ -50,7 +54,7 @@ class Signal(AstNode):
|
|||
UseIdent("detail_name").expected("a signal detail name"),
|
||||
]
|
||||
),
|
||||
"=>",
|
||||
Keyword("=>"),
|
||||
Mark("detail_start"),
|
||||
Optional(["$", UseLiteral("extern", True)]),
|
||||
UseIdent("handler").expected("the name of a function to handle the signal"),
|
||||
|
@ -184,6 +188,10 @@ class Signal(AstNode):
|
|||
if prop is not None:
|
||||
return prop.doc
|
||||
|
||||
@docs("=>")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Signal")
|
||||
|
||||
|
||||
@decompiler("signal")
|
||||
def decompile_signal(
|
||||
|
|
|
@ -225,6 +225,10 @@ class ExtAccessibility(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate accessibility block")
|
||||
|
||||
@docs("accessibility")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtAccessibility")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -55,6 +55,10 @@ class Item(AstNode):
|
|||
f"Duplicate item '{self.name}'", lambda x: x.name == self.name
|
||||
)
|
||||
|
||||
@docs("name")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtComboBoxItems")
|
||||
|
||||
|
||||
class ExtComboBoxItems(AstNode):
|
||||
grammar = [
|
||||
|
@ -81,6 +85,10 @@ class ExtComboBoxItems(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate items block")
|
||||
|
||||
@docs("items")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtComboBoxItems")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -29,25 +29,23 @@ class Filters(AstNode):
|
|||
self.tokens["tag_name"],
|
||||
SymbolKind.Array,
|
||||
self.range,
|
||||
self.group.tokens[self.tokens["tag_name"]].range,
|
||||
self.group.tokens["tag_name"].range,
|
||||
)
|
||||
|
||||
@validate()
|
||||
def container_is_file_filter(self):
|
||||
validate_parent_type(self, "Gtk", "FileFilter", "file filter properties")
|
||||
|
||||
@validate()
|
||||
@validate("tag_name")
|
||||
def unique_in_parent(self):
|
||||
# The token argument to validate() needs to be calculated based on
|
||||
# the instance, hence wrapping it like this.
|
||||
@validate(self.tokens["tag_name"])
|
||||
def wrapped_validator(self):
|
||||
self.validate_unique_in_parent(
|
||||
f"Duplicate {self.tokens['tag_name']} block",
|
||||
check=lambda child: child.tokens["tag_name"] == self.tokens["tag_name"],
|
||||
)
|
||||
self.validate_unique_in_parent(
|
||||
f"Duplicate {self.tokens['tag_name']} block",
|
||||
check=lambda child: child.tokens["tag_name"] == self.tokens["tag_name"],
|
||||
)
|
||||
|
||||
wrapped_validator(self)
|
||||
@docs("tag_name")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtFileFilter")
|
||||
|
||||
|
||||
class FilterString(AstNode):
|
||||
|
@ -76,8 +74,7 @@ def create_node(tag_name: str, singular: str):
|
|||
return Group(
|
||||
Filters,
|
||||
[
|
||||
Keyword(tag_name),
|
||||
UseLiteral("tag_name", tag_name),
|
||||
UseExact("tag_name", tag_name),
|
||||
"[",
|
||||
Delimited(
|
||||
Group(
|
||||
|
|
|
@ -83,6 +83,10 @@ class ExtLayout(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate layout block")
|
||||
|
||||
@docs("layout")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtLayout")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -108,3 +108,7 @@ class ExtListItemFactory(AstNode):
|
|||
just hear to satisfy XmlOutput._emit_object_or_template
|
||||
"""
|
||||
return None
|
||||
|
||||
@docs("id")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtListItemFactory")
|
||||
|
|
|
@ -70,6 +70,25 @@ class Menu(AstNode):
|
|||
if self.id in RESERVED_IDS:
|
||||
raise CompileWarning(f"{self.id} may be a confusing object ID")
|
||||
|
||||
@docs("menu")
|
||||
def ref_docs_menu(self):
|
||||
return get_docs_section("Syntax Menu")
|
||||
|
||||
@docs("section")
|
||||
def ref_docs_section(self):
|
||||
return get_docs_section("Syntax Menu")
|
||||
|
||||
@docs("submenu")
|
||||
def ref_docs_submenu(self):
|
||||
return get_docs_section("Syntax Menu")
|
||||
|
||||
@docs("item")
|
||||
def ref_docs_item(self):
|
||||
if self.tokens["shorthand"]:
|
||||
return get_docs_section("Syntax MenuItemShorthand")
|
||||
else:
|
||||
return get_docs_section("Syntax Menu")
|
||||
|
||||
|
||||
class MenuAttribute(AstNode):
|
||||
tag_name = "attribute"
|
||||
|
@ -156,6 +175,7 @@ menu_item_shorthand = Group(
|
|||
[
|
||||
Keyword("item"),
|
||||
UseLiteral("tag", "item"),
|
||||
UseLiteral("shorthand", True),
|
||||
"(",
|
||||
Group(
|
||||
MenuAttribute,
|
||||
|
|
|
@ -94,6 +94,10 @@ class ExtScaleMark(AstNode):
|
|||
did_you_mean=(self.position, positions.keys()),
|
||||
)
|
||||
|
||||
@docs("mark")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtScaleMarks")
|
||||
|
||||
|
||||
class ExtScaleMarks(AstNode):
|
||||
grammar = [
|
||||
|
@ -123,6 +127,10 @@ class ExtScaleMarks(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate 'marks' block")
|
||||
|
||||
@docs("marks")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtScaleMarks")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -94,6 +94,10 @@ class ExtSizeGroupWidgets(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate widgets block")
|
||||
|
||||
@docs("widgets")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtSizeGroupWidgets")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -57,7 +57,7 @@ class ExtStringListStrings(AstNode):
|
|||
self.group.tokens["strings"].range,
|
||||
)
|
||||
|
||||
@validate("items")
|
||||
@validate("strings")
|
||||
def container_is_string_list(self):
|
||||
validate_parent_type(self, "Gtk", "StringList", "StringList items")
|
||||
|
||||
|
@ -65,6 +65,10 @@ class ExtStringListStrings(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate strings block")
|
||||
|
||||
@docs("strings")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtStringListStrings")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -70,6 +70,10 @@ class ExtStyles(AstNode):
|
|||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent("Duplicate styles block")
|
||||
|
||||
@docs("styles")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtStyles")
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[ObjectContent],
|
||||
|
|
|
@ -53,6 +53,10 @@ class ChildExtension(AstNode):
|
|||
def child(self) -> ExtResponse:
|
||||
return self.children[0]
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ChildExtension")
|
||||
|
||||
|
||||
class ChildAnnotation(AstNode):
|
||||
grammar = ["[", AnyOf(ChildInternal, ChildExtension, ChildType), "]"]
|
||||
|
|
|
@ -88,6 +88,10 @@ class Template(Object):
|
|||
f"Only one template may be defined per file, but this file contains {len(self.parent.children[Template])}",
|
||||
)
|
||||
|
||||
@docs("id")
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Template")
|
||||
|
||||
|
||||
@decompiler("template")
|
||||
def decompile_template(ctx: DecompileCtx, gir, klass, parent=None):
|
||||
|
|
|
@ -68,6 +68,10 @@ class GtkDirective(AstNode):
|
|||
# For better error handling, just assume it's 4.0
|
||||
return gir.get_namespace("Gtk", "4.0")
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax GtkDecl")
|
||||
|
||||
|
||||
class Import(AstNode):
|
||||
grammar = Statement(
|
||||
|
@ -105,3 +109,7 @@ class Import(AstNode):
|
|||
return gir.get_namespace(self.tokens["namespace"], self.tokens["version"])
|
||||
except CompileError:
|
||||
return None
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Using")
|
||||
|
|
|
@ -124,6 +124,16 @@ class ExtResponse(AstNode):
|
|||
object = self.parent_by_type(Child).object
|
||||
return object.id
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax ExtResponse")
|
||||
|
||||
@docs("response_id")
|
||||
def response_id_docs(self):
|
||||
if enum := self.root.gir.get_type("ResponseType", "Gtk"):
|
||||
if member := enum.members.get(self.response_id, None):
|
||||
return member.doc
|
||||
|
||||
|
||||
def decompile_response_type(parent_element, child_element):
|
||||
obj_id = None
|
||||
|
|
|
@ -29,3 +29,7 @@ class TranslationDomain(AstNode):
|
|||
@property
|
||||
def domain(self):
|
||||
return self.tokens["domain"]
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax TranslationDomain")
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
import typing as T
|
||||
|
||||
from blueprintcompiler.gir import ArrayType
|
||||
from blueprintcompiler.lsp_utils import SemanticToken
|
||||
|
||||
from .common import *
|
||||
from .contexts import ScopeCtx, ValueTypeCtx
|
||||
|
@ -56,6 +57,10 @@ class Translated(AstNode):
|
|||
f"Cannot convert translated string to {expected_type.full_name}"
|
||||
)
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Translated")
|
||||
|
||||
|
||||
class TypeLiteral(AstNode):
|
||||
grammar = [
|
||||
|
@ -101,6 +106,10 @@ class TypeLiteral(AstNode):
|
|||
],
|
||||
)
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax TypeLiteral")
|
||||
|
||||
|
||||
class QuotedLiteral(AstNode):
|
||||
grammar = UseQuoted("value")
|
||||
|
@ -258,6 +267,10 @@ class Flags(AstNode):
|
|||
if expected_type is not None and not isinstance(expected_type, gir.Bitfield):
|
||||
raise CompileError(f"{expected_type.full_name} is not a bitfield type")
|
||||
|
||||
@docs()
|
||||
def ref_docs(self):
|
||||
return get_docs_section("Syntax Flags")
|
||||
|
||||
|
||||
class IdentLiteral(AstNode):
|
||||
grammar = UseIdent("value")
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
|
||||
import enum
|
||||
import json
|
||||
import os
|
||||
import typing as T
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
@ -200,3 +202,27 @@ class TextEdit:
|
|||
|
||||
def to_json(self):
|
||||
return {"range": self.range.to_json(), "newText": self.newText}
|
||||
|
||||
|
||||
_docs_sections: T.Optional[dict[str, T.Any]] = None
|
||||
|
||||
|
||||
def get_docs_section(section_name: str) -> T.Optional[str]:
|
||||
global _docs_sections
|
||||
|
||||
if _docs_sections is None:
|
||||
try:
|
||||
with open(
|
||||
os.path.join(os.path.dirname(__file__), "reference_docs.json")
|
||||
) as f:
|
||||
_docs_sections = json.load(f)
|
||||
except FileNotFoundError:
|
||||
_docs_sections = {}
|
||||
|
||||
if section := _docs_sections.get(section_name):
|
||||
content = section["content"]
|
||||
link = section["link"]
|
||||
content += f"\n\n---\n\n[Online documentation]({link})"
|
||||
return content
|
||||
else:
|
||||
return None
|
||||
|
|
136
docs/collect-sections.py
Executable file
136
docs/collect-sections.py
Executable file
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
__all__ = ["get_docs_section"]
|
||||
|
||||
DOCS_ROOT = "https://jwestman.pages.gitlab.gnome.org/blueprint-compiler"
|
||||
|
||||
|
||||
sections: dict[str, "Section"] = {}
|
||||
|
||||
|
||||
@dataclass
|
||||
class Section:
|
||||
link: str
|
||||
lines: str
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"content": rst_to_md(self.lines),
|
||||
"link": self.link,
|
||||
}
|
||||
|
||||
|
||||
def load_reference_docs():
|
||||
for filename in Path(os.path.dirname(__file__), "reference").glob("*.rst"):
|
||||
with open(filename) as f:
|
||||
section_name = None
|
||||
lines = []
|
||||
|
||||
def close_section():
|
||||
if section_name:
|
||||
html_file = re.sub(r"\.rst$", ".html", filename.name)
|
||||
anchor = re.sub(r"[^a-z0-9]+", "-", section_name.lower())
|
||||
link = f"{DOCS_ROOT}/reference/{html_file}#{anchor}"
|
||||
sections[section_name] = Section(link, lines)
|
||||
|
||||
for line in f:
|
||||
if m := re.match(r"\.\.\s+_(.*):", line):
|
||||
close_section()
|
||||
section_name = m.group(1)
|
||||
lines = []
|
||||
else:
|
||||
lines.append(line)
|
||||
|
||||
close_section()
|
||||
|
||||
|
||||
# This isn't a comprehensive rST to markdown converter, it just needs to handle the
|
||||
# small subset of rST used in the reference docs.
|
||||
def rst_to_md(lines: list[str]) -> str:
|
||||
result = ""
|
||||
|
||||
def rst_to_md_inline(line):
|
||||
line = re.sub(r"``(.*?)``", r"`\1`", line)
|
||||
line = re.sub(
|
||||
r":ref:`(.*?)<(.*?)>`",
|
||||
lambda m: f"[{m.group(1)}]({sections[m.group(2)].link})",
|
||||
line,
|
||||
)
|
||||
line = re.sub(r"`([^`]*?) <([^`>]*?)>`_", r"[\1](\2)", line)
|
||||
return line
|
||||
|
||||
i = 0
|
||||
n = len(lines)
|
||||
heading_levels = {}
|
||||
|
||||
def print_block(lang: str = "", code: bool = True, strip_links: bool = False):
|
||||
nonlocal result, i
|
||||
block = ""
|
||||
while i < n:
|
||||
line = lines[i].rstrip()
|
||||
if line.startswith(" "):
|
||||
line = line[3:]
|
||||
elif line != "":
|
||||
break
|
||||
|
||||
if strip_links:
|
||||
line = re.sub(r":ref:`(.*?)<(.*?)>`", r"\1", line)
|
||||
|
||||
if not code:
|
||||
line = rst_to_md_inline(line)
|
||||
|
||||
block += line + "\n"
|
||||
i += 1
|
||||
|
||||
if code:
|
||||
result += f"```{lang}\n{block.strip()}\n```\n\n"
|
||||
else:
|
||||
result += block
|
||||
|
||||
while i < n:
|
||||
line = lines[i].rstrip()
|
||||
i += 1
|
||||
if line == ".. rst-class:: grammar-block":
|
||||
print_block(strip_links=True)
|
||||
elif line == ".. code-block:: blueprint":
|
||||
print_block("blueprint")
|
||||
elif line == ".. note::":
|
||||
result += "#### Note\n"
|
||||
print_block(code=False)
|
||||
elif m := re.match(r"\.\. image:: (.*)", line):
|
||||
result += f"})\n"
|
||||
elif i < n and re.match(r"^((-+)|(~+)|(\++))$", lines[i]):
|
||||
level_char = lines[i][0]
|
||||
if level_char not in heading_levels:
|
||||
heading_levels[level_char] = max(heading_levels.values(), default=1) + 1
|
||||
result += (
|
||||
"#" * heading_levels[level_char] + " " + rst_to_md_inline(line) + "\n"
|
||||
)
|
||||
i += 1
|
||||
else:
|
||||
result += rst_to_md_inline(line) + "\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: collect_sections.py <output_file>")
|
||||
sys.exit(1)
|
||||
|
||||
outfile = sys.argv[1]
|
||||
|
||||
load_reference_docs()
|
||||
|
||||
# print the sections to a json file
|
||||
with open(outfile, "w") as f:
|
||||
json.dump(
|
||||
{name: section.to_json() for name, section in sections.items()}, f, indent=2
|
||||
)
|
|
@ -9,3 +9,11 @@ custom_target('docs',
|
|||
)
|
||||
|
||||
endif
|
||||
|
||||
custom_target('reference_docs.json',
|
||||
output: 'reference_docs.json',
|
||||
command: [meson.current_source_dir() / 'collect-sections.py', '@OUTPUT@'],
|
||||
build_always_stale: true,
|
||||
install: true,
|
||||
install_dir: py.get_install_dir() / 'blueprintcompiler',
|
||||
)
|
|
@ -227,7 +227,7 @@ Valid in `Gtk.BuilderListItemFactory <https://docs.gtk.org/gtk4/class.BuilderLis
|
|||
|
||||
The ``template`` block defines the template that will be used to create list items. This block is unique within Blueprint because it defines a completely separate sub-blueprint which is used to create each list item. The sub-blueprint may not reference objects in the main blueprint or vice versa.
|
||||
|
||||
The template type must be `Gtk.ListItem <https://docs.gtk.org/gtk4/class.ListItem.html>`_, `Gtk.ColumnViewRow <https://docs.gtk.org/gtk4/class.ColumnViewRow.html>`_, or `Gtk.ColumnViewCell <https://docs.gtk.org/gtk4/class.ColumnViewCell.html>`_ The template object can be referenced with the ``template`` keyword.
|
||||
The template type must be `Gtk.ListItem <https://docs.gtk.org/gtk4/class.ListItem.html>`_, `Gtk.ColumnViewRow <https://docs.gtk.org/gtk4/class.ColumnViewRow.html>`_, or `Gtk.ColumnViewCell <https://docs.gtk.org/gtk4/class.ColumnViewCell.html>`_. The template object can be referenced with the ``template`` keyword.
|
||||
|
||||
.. code-block:: blueprint
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ project('blueprint-compiler',
|
|||
version: '0.14.0',
|
||||
)
|
||||
|
||||
subdir('docs')
|
||||
|
||||
prefix = get_option('prefix')
|
||||
datadir = join_paths(prefix, get_option('datadir'))
|
||||
|
||||
py = import('python').find_installation('python3')
|
||||
|
||||
subdir('docs')
|
||||
|
||||
configure_file(
|
||||
input: 'blueprint-compiler.pc.in',
|
||||
output: 'blueprint-compiler.pc',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue