{"id":50401120,"url":"https://github.com/xll-gen/sugar","last_synced_at":"2026-05-30T23:30:36.008Z","repository":{"id":358179187,"uuid":"1127083372","full_name":"xll-gen/sugar","owner":"xll-gen","description":"Sweeten your Windows automation.","archived":false,"fork":false,"pushed_at":"2026-05-16T04:01:18.000Z","size":85,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T06:23:07.954Z","etag":null,"topics":["com","excel","go","golang","windows"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/xll-gen/sugar","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xll-gen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-03T06:18:13.000Z","updated_at":"2026-05-16T04:01:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/xll-gen/sugar","commit_stats":null,"previous_names":["xll-gen/sugar"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/xll-gen/sugar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xll-gen%2Fsugar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xll-gen%2Fsugar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xll-gen%2Fsugar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xll-gen%2Fsugar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xll-gen","download_url":"https://codeload.github.com/xll-gen/sugar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xll-gen%2Fsugar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33714033,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["com","excel","go","golang","windows"],"created_at":"2026-05-30T23:30:35.393Z","updated_at":"2026-05-30T23:30:35.996Z","avatar_url":"https://github.com/xll-gen.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sugar: Sweeten your Windows automation.\n\n\u003e **Warning:** This project is currently in the **Alpha stage (v0.x.x)**. APIs are subject to change and breaking changes may occur until the v1.0.0 release.\n\n`sugar` is a flexible and safe Go library for Component Object Model (COM) automation on Windows. Built on top of the powerful `go-ole` library, it introduces **Immutability** and the **Arena (Context) pattern** to help you write clean code without worrying about resource leaks.\n\n## Key Features\n\n- **Standard Execution Pattern (`Do`/`Go`):** Automatically handles thread locking (`LockOSThread`) and COM initialization (`CoInitialize`).\n- **Immutable Chain:** All operations (`Get`, `Call`, etc.) return a new `Chain` (Interface) instance, preventing side effects on original objects.\n- **Automatic Resource Management (Arena):** All COM objects created within a context are automatically released in reverse order when the block completes.\n- **Standard `context.Context` Integration:** Leverage Go's standard context features for cancellation, timeouts, and value passing.\n- **Expression-Based Automation:** Navigate complex object hierarchies using a single string expression.\n- **Application Specific Subpackages:** Use type-safe wrappers for popular applications like Excel.\n\n## Installation\n\n```sh\ngo get -u github.com/xll-gen/sugar\n```\n\n## Quick Start (Generic)\n\nA simple example using `sugar.Do` to launch Excel. Resource cleanup is handled automatically.\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"github.com/xll-gen/sugar\"\n)\n\nfunc main() {\n\t// sugar.Do guarantees COM initialization and automatic resource cleanup.\n\terr := sugar.Do(func(ctx sugar.Context) error {\n\t\texcel := ctx.Create(\"Excel.Application\")\n\t\tif err := excel.Err(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t\n\t\t// Schedule Excel to quit\n\t\tdefer excel.Call(\"Quit\")\n\n\t\t// Method chaining (Immutable pattern)\n\t\texcel.Put(\"Visible\", true).\n\t\t\tGet(\"Workbooks\").\n\t\t\tCall(\"Add\")\n            \n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Fatalf(\"Automation failed: %v\", err)\n\t}\n}\n```\n\n## Excel Subpackage (Type-Safe)\n\nFor common applications, `sugar` provides subpackages with friendly methods.\nThe `excel` package mirrors [xlwings](https://docs.xlwings.org/en/stable/api.html)\nnaming and behavior — see [AGENTS.md §2](./AGENTS.md) for the parity roadmap.\n\n```go\nimport \"github.com/xll-gen/sugar/excel\"\n\nsugar.Do(func(ctx sugar.Context) error {\n    app := excel.NewApplication(ctx)\n    defer app.Quit()\n\n    // xlwings-parity boolean properties on App.\n    // Setters return Application for fluent chaining; getters return a\n    // sugar.Chain — call .Value() to materialize the bool.\n    app.SetVisible(true).\n        SetDisplayAlerts(false).\n        SetScreenUpdating(false)\n\n    wb := app.Workbooks().Add()\n    sheet := wb.ActiveSheet()\n\n    // Type-safe Range manipulation\n    sheet.Range(\"A1\").SetValue(\"Hello from Sugar!\")\n\n    // Re-enable screen updates before exit.\n    app.SetScreenUpdating(true)\n    return nil\n})\n```\n\n### Excel object coverage\n\n| xlwings Object | sugar type            | Status                                                                                                                 |\n| -------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------- |\n| `App`          | `excel.Application`   | `Visible`, `DisplayAlerts`, `ScreenUpdating`, `Calculation` (get/set), `Version`, `PID`, `Hwnd`, `Workbooks`/`Books`, `ActiveWorkbook`, `Quit`, `Kill` |\n| `Books`        | `excel.Workbooks`     | `Add`, `Open`, `Item`, `Count`, `Active`                                                                               |\n| `Book`         | `excel.Workbook`      | `Worksheets`/`Sheets`, `ActiveSheet`, `App`, `Name`, `FullName`, `Path`, `Saved`/`SetSaved`, `Activate`, `Save`, `SaveAs`, `Close` |\n| `Sheets`       | `excel.Worksheets`    | `Add` (before/after/name), `Item`, `Count`, `Active`                                                                   |\n| `Sheet`        | `excel.Worksheet`     | `Range`, `Cells`, `UsedRange`, `Name`/`SetName`, `Index`, `Visible`/`SetVisible`, `Activate`, `Delete`, `Clear`, `ClearContents`, `AutoFit` |\n| `Range`        | `excel.Range`         | `Value` (with 2-D SAFEARRAY decode), `SetValue`, `Address`, `Formula`/`SetFormula`, `Formula2`/`SetFormula2`, `NumberFormat`/`SetNumberFormat`, `Cells`, `Offset`, `Resize`, `Rows`, `Columns`, `Row`, `Column`, `Count`, `Clear`, `ClearContents`, `Delete`, `Copy`, `Merge`/`UnMerge`/`MergeCells`, `AutoFit`, `Options(...)` |\n\nGaps still tracked in [AGENTS.md §2.1](./AGENTS.md): named ranges\n(`Name`/`Names`), charts, pictures, shapes.\n\n### Range.Options — xlwings-style value conversion\n\n`Range.Options(...)` is the Go analogue of xlwings' `Range.options(...)`. It\nreturns an `OptionedRange` that decodes the range lazily on `.Value()` or\n`.Get(\u0026dst)`, applying any combination of shape forcing, range expansion,\nheader-driven struct decode, empty-cell substitution, or a custom converter.\n\n```go\nimport \"github.com/xll-gen/sugar/excel\"\n\nsugar.Do(func(ctx sugar.Context) error {\n    app := excel.NewApplication(ctx)\n    defer app.Quit()\n    app.SetVisible(false).SetDisplayAlerts(false)\n\n    wb := app.Workbooks().Add()\n    sheet := wb.ActiveSheet()\n\n    // Seed a small table.\n    sheet.Range(\"A1\").SetValue(\"Name\")\n    sheet.Range(\"B1\").SetValue(\"Age\")\n    sheet.Range(\"A2\").SetValue(\"alice\")\n    sheet.Range(\"B2\").SetValue(30.0)\n    sheet.Range(\"A3\").SetValue(\"bob\")\n    sheet.Range(\"B3\").SetValue(25.0)\n\n    // 1. Force a scalar read.\n    var price float64\n    sheet.Range(\"B2\").Options(excel.Scalar()).Get(\u0026price) // -\u003e 30.0\n\n    // 2. Auto-grow from the anchor and decode rows into a struct slice.\n    type Person struct {\n        Name string\n        Age  int\n    }\n    var people []Person\n    err := sheet.Range(\"A1\").Options(\n        excel.Expand(\"table\"),\n        excel.Header(true),\n    ).Get(\u0026people)\n    if err != nil {\n        return err\n    }\n    // people -\u003e [{alice 30} {bob 25}]\n\n    // 3. Custom Convert escape hatch.\n    sum, _ := sheet.Range(\"B2\", \"B3\").Options(\n        excel.Convert(func(raw [][]interface{}) (interface{}, error) {\n            total := 0.0\n            for _, row := range raw {\n                if v, ok := row[0].(float64); ok {\n                    total += v\n                }\n            }\n            return total, nil\n        }),\n    ).Value()\n    _ = sum // -\u003e 55.0\n\n    return nil\n})\n```\n\nAvailable options: `Scalar()`, `Vector()` (alias `Vector1D`), `Grid()` (alias\n`Vector2D`), `Header(bool)`, `Empty(value)`, `DateFormat(layout)`,\n`Expand(\"table\"|\"down\"|\"right\")`, and `Convert(fn)`. See\n[options.go](./excel/options.go) for full docs.\n\n## Core Concepts\n\n### 1. Standard Execution (`sugar.Do` \u0026 `sugar.Go`)\n\nCOM is sensitive to the execution thread. `sugar` provides safe entry points to manage this.\n\n- **`sugar.Do`**: Locks the current goroutine to an OS thread and executes synchronously.\n- **`sugar.Go`**: Starts a new goroutine (new OS thread) and independently initializes the COM environment for asynchronous work. Returns a buffered `\u003c-chan error` that delivers the goroutine's terminal error — ignore it for fire-and-forget, or receive it to know when the work finished and whether it failed.\n\n### 2. Immutable Chain\n\nMethods like `Get`, `Call`, and `ForEach` always return a **NEW `Chain` instance**. `Chain` is now an **interface**, allowing for custom wrappers like the `excel` package.\n\n```go\nworkbooks := excel.Get(\"Workbooks\") // 'excel' still points to Application\nwb := workbooks.Call(\"Add\")         // 'workbooks' still points to the Workbooks collection\n```\n\n### 3. Iteration with `ForEach`\n\nYou can iterate over COM collections using the `ForEach` method. Each item is provided as a `Chain` instance. Returning `sugar.ErrForEachBreak` stops the iteration and the error is recorded in the Chain.\n\n```go\nsugar.Do(func(ctx sugar.Context) error {\n    excel := ctx.Create(\"Excel.Application\")\n    workbooks := excel.Get(\"Workbooks\")\n\n    // Iterate through all open workbooks\n    err := workbooks.ForEach(func(wb sugar.Chain) error {\n        name, _ := wb.Get(\"Name\").Value()\n        fmt.Printf(\"Workbook: %v\\n\", name)\n        \n        // Stop after first item if needed\n        return sugar.ErrForEachBreak\n    }).Err()\n\n    if errors.Is(err, sugar.ErrForEachBreak) {\n        // Handled break\n    }\n    return nil\n})\n```\n\n### 4. Arena Context\n\nThe `sugar.Context` acts as a resource collector (Arena). Any object created via `ctx.Create`, `ctx.From`, or derived from a chain is automatically registered with that context and cleaned up when the `Do` block ends.\n\n**Manual `Release()` calls are no longer necessary.**\n\n### 5. Nested Scopes\n\nUse `ctx.Do` to create a nested arena for early resource cleanup.\n\n```go\nsugar.Do(func(ctx sugar.Context) error {\n    excel := ctx.Create(\"Excel.Application\")\n    \n    ctx.Do(func(innerCtx sugar.Context) error {\n        // Objects created in this block are released immediately when it ends.\n        wb := excel.Get(\"Workbooks\").Call(\"Add\")\n        return nil\n    }) \n    // 'wb' is released here, while 'excel' remains valid.\n    return nil\n})\n```\n\n## Expression-Based Automation (Subpackage)\n\nThe `expression` package allows you to manipulate complex hierarchies with a single line of code.\n\n```go\nimport \"github.com/xll-gen/sugar/expression\"\n\nsugar.Do(func(ctx sugar.Context) error {\n    excel := ctx.Create(\"Excel.Application\")\n    \n    // Set complex paths at once\n    expression.Put(excel, \"ActiveSheet.Range('A1').Value\", \"Hello Sugar!\")\n    \n    // Read values\n    val, _ := expression.Get(excel, \"ActiveSheet.Range('A1').Value\")\n    fmt.Println(val)\n    return nil\n})\n```\n\n## Considerations\n\n- **Windows Only:** This library depends on Windows COM technology and only works on Windows OS.\n- **Object Sharing Between Threads:** Sharing raw `IDispatch` pointers between threads (goroutines) without proper marshaling is dangerous. We recommend creating independent objects in each goroutine using `sugar.Go`.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxll-gen%2Fsugar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxll-gen%2Fsugar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxll-gen%2Fsugar/lists"}