This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch main
in repository ego.

View the commit online.

commit d25428675373550438a06f795a1d345332c2742e
Author: [email protected] <[email protected]>
AuthorDate: Wed Apr 1 19:30:00 2026 -0600

    feat(ego-gen): add PartData model and part introspection logic
    
    Add PartData/PartMethodData structs, buildPartsData with collision
    detection, and partMethodsForClass for extracting part interfaces.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 cmd/ego-gen/generator.go      |  25 +++++++++
 cmd/ego-gen/generator_test.go |  67 ++++++++++++++++++++++
 cmd/ego-gen/part.go           | 128 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 220 insertions(+)

diff --git a/cmd/ego-gen/generator.go b/cmd/ego-gen/generator.go
index a2807f8..de4a538 100644
--- a/cmd/ego-gen/generator.go
+++ b/cmd/ego-gen/generator.go
@@ -42,6 +42,7 @@ type ClassData struct {
 	GlobalFunctions []GlobalFunctionData // package-level functions with no Eo receiver
 	CallbackTypes   []CallbackTypeData   // distinct callback typedefs used by this class
 	HasCallbacks    bool                 // true if CallbackTypes is non-empty (controls imports/trampolines)
+	Parts           []PartData           // declared widget parts with accessors
 }
 
 // ConstructorData describes a constructor option for an EFL class. Each entry
@@ -238,6 +239,30 @@ type IteratorMethodData struct {
 	StructCAccessPrefix string
 }
 
+// PartMethodData describes a single method on a part proxy.
+type PartMethodData struct {
+	GoName       string // e.g. "Content", "SetContent", "SetText"
+	CHelper      string // e.g. "_ego_part_content_get" — C function combining efl_part + interface call
+	IsGetter     bool
+	IsSetter     bool
+	GoReturnType string // for getters
+	GoParamName  string // for setters
+	GoParamType  string // for setters
+	IsEoParam    bool   // true if param is efl.Objecter
+	IsString     bool   // true if param/return is string
+	IsBool       bool   // true if return is bool
+	IsColor      bool   // true if return/param is color.RGBA
+}
+
+// PartData describes a declared part on a widget class.
+type PartData struct {
+	GoAccessorName string           // e.g. "Icon" — method on the widget
+	PartName       string           // e.g. "icon" — Eolian part name
+	ProxyTypeName  string           // e.g. "defaultItemIconPart" — unexported struct
+	PartClassName  string           // e.g. "Efl.Ui.Layout_Part_Content"
+	PartMethods    []PartMethodData // methods the proxy supports
+}
+
 // EventData describes a single event on an EFL class.
 type EventData struct {
 	GoName        string
diff --git a/cmd/ego-gen/generator_test.go b/cmd/ego-gen/generator_test.go
index d755dbe..0f1c20f 100644
--- a/cmd/ego-gen/generator_test.go
+++ b/cmd/ego-gen/generator_test.go
@@ -1490,3 +1490,70 @@ func TestGenerateClass_EinaContentParam(t *testing.T) {
 		}
 	}
 }
+
+func TestGenerateClass_PartAccessor(t *testing.T) {
+	g, outDir := newTestGenerator(t)
+
+	data := ClassData{
+		PackageName:   "ui",
+		GoName:        "DefaultItem",
+		EolianName:    "Efl.Ui.Default_Item",
+		CClassName:    "EFL_UI_DEFAULT_ITEM_CLASS",
+		CClassGetFunc: "efl_ui_default_item_class_get",
+		CPrefix:       "efl_ui_default_item",
+		EOHeaderFile:  "efl_ui_default_item.eo.h",
+		IsAbstract:    true,
+		Parts: []PartData{
+			{
+				GoAccessorName: "Icon",
+				PartName:       "icon",
+				ProxyTypeName:  "defaultItemIconPart",
+				PartMethods: []PartMethodData{
+					{
+						GoName:       "Content",
+						CHelper:      "_ego_part_content_get",
+						IsGetter:     true,
+						GoReturnType: "unsafe.Pointer",
+					},
+					{
+						GoName:      "SetContent",
+						CHelper:     "_ego_part_content_set",
+						IsSetter:    true,
+						GoParamName: "val",
+						GoParamType: "efl.Objecter",
+						IsEoParam:   true,
+					},
+				},
+			},
+		},
+	}
+
+	if err := g.GenerateClass(data); err != nil {
+		t.Fatalf("GenerateClass: %v", err)
+	}
+
+	outFile := filepath.Join(outDir, "ui", "default_item.go")
+	content, err := os.ReadFile(outFile)
+	if err != nil {
+		t.Fatalf("not found: %v", err)
+	}
+
+	src := string(content)
+
+	// These will fail until Task 3 adds the template — that's expected.
+	// For now, just verify the file is generated without error.
+	t.Logf("Generated file length: %d bytes", len(content))
+
+	// Check that these are NOT present yet (template hasn't been updated):
+	partsPatterns := []string{
+		"type defaultItemIconPart struct",
+		"func (o *DefaultItem) Icon()",
+	}
+	for _, p := range partsPatterns {
+		if strings.Contains(src, p) {
+			t.Logf("Found part pattern (template already supports parts): %q", p)
+		} else {
+			t.Logf("Part pattern not yet present (expected, template not updated): %q", p)
+		}
+	}
+}
diff --git a/cmd/ego-gen/part.go b/cmd/ego-gen/part.go
new file mode 100644
index 0000000..2b325a0
--- /dev/null
+++ b/cmd/ego-gen/part.go
@@ -0,0 +1,128 @@
+package main
+
+// partMethodsForClass returns the PartMethodData entries for a given part class.
+func partMethodsForClass(partClass *Class) []PartMethodData {
+	var methods []PartMethodData
+
+	for _, f := range partClass.Functions(FunctionProperty) {
+		propName := f.Name()
+		goGetter, goSetter := PropertyToGetterSetter(propName)
+		cGetName := f.FullCName(FunctionPropGet)
+		cSetName := f.FullCName(FunctionPropSet)
+
+		ft := f.Type()
+		hasGet := ft == FunctionProperty || ft == FunctionPropGet
+		hasSet := ft == FunctionProperty || ft == FunctionPropSet
+
+		var goType string
+		var isEo, isString, isBool, isColor bool
+
+		// Determine type from getter return/values.
+		if vals := f.PropertyValues(FunctionPropGet); len(vals) == 1 {
+			pt := vals[0].Type()
+			if pt != nil {
+				cType := pt.CType()
+				goType = CTypeToGo(cType)
+				isEo = pt.IsClass()
+				isString = NeedsStringConversion(cType)
+				isBool = IsBoolType(cType)
+			}
+		} else if rt := f.ReturnType(FunctionPropGet); rt != nil {
+			cType := rt.CType()
+			goType = CTypeToGo(cType)
+			isEo = rt.IsClass()
+			isString = NeedsStringConversion(cType)
+			isBool = IsBoolType(cType)
+		}
+
+		// Check for 4-value color pattern.
+		if vals := f.PropertyValues(FunctionPropGet); len(vals) == 4 {
+			multi, ok := buildMultiValueData(vals)
+			if ok && isColorPattern(multi) {
+				isColor = true
+				goType = "color.RGBA"
+			}
+		}
+
+		if hasGet && goType != "" {
+			methods = append(methods, PartMethodData{
+				GoName:       goGetter,
+				CHelper:      "_ego_part_" + cGetName,
+				IsGetter:     true,
+				GoReturnType: goType,
+				IsString:     isString,
+				IsBool:       isBool,
+				IsColor:      isColor,
+				IsEoParam:    isEo,
+			})
+		}
+
+		if hasSet && goType != "" {
+			paramType := goType
+			if isEo {
+				paramType = "efl.Objecter"
+			}
+			if isString {
+				paramType = "string"
+			}
+			if isColor {
+				paramType = "color.RGBA"
+			}
+			methods = append(methods, PartMethodData{
+				GoName:      goSetter,
+				CHelper:     "_ego_part_" + cSetName,
+				IsSetter:    true,
+				GoParamName: "val",
+				GoParamType: paramType,
+				IsEoParam:   isEo,
+				IsString:    isString,
+				IsBool:      isBool,
+				IsColor:     isColor,
+			})
+		}
+	}
+
+	return methods
+}
+
+// buildPartsData collects part accessors for a class, with collision detection.
+func buildPartsData(c *Class, goName string, existingNames map[string]bool) []PartData {
+	parts := c.Parts()
+	if len(parts) == 0 {
+		return nil
+	}
+
+	var result []PartData
+	for _, p := range parts {
+		partName := p.Name()
+		accessorName := SnakeToCamel(partName)
+
+		// Collision detection: skip if the widget already has a method/property
+		// with the same Go name.
+		if existingNames[accessorName] {
+			continue
+		}
+
+		partClass := p.Class()
+		if partClass == nil {
+			continue
+		}
+
+		proxyType := lowerFirst(goName) + accessorName + "Part"
+		methods := partMethodsForClass(partClass)
+
+		if len(methods) == 0 {
+			continue
+		}
+
+		result = append(result, PartData{
+			GoAccessorName: accessorName,
+			PartName:       partName,
+			ProxyTypeName:  proxyType,
+			PartClassName:  partClass.Name(),
+			PartMethods:    methods,
+		})
+	}
+
+	return result
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to