{"id":18031770,"url":"https://github.com/dagronf/dsfattributedstringbuilder","last_synced_at":"2025-09-01T20:06:43.199Z","repository":{"id":149491743,"uuid":"178626053","full_name":"dagronf/DSFAttributedStringBuilder","owner":"dagronf","description":"A simple Swift/Objective-C NSAttributedString builder simplifying creation of a styled NSAttributedString.","archived":false,"fork":false,"pushed_at":"2020-08-07T01:39:10.000Z","size":70,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-01T20:05:59.886Z","etag":null,"topics":["attributedstring","nsattributedstring","objc","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/dagronf.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}},"created_at":"2019-03-31T00:35:07.000Z","updated_at":"2021-05-21T21:31:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"f444c57f-eb33-411a-be41-7a4893f80b3f","html_url":"https://github.com/dagronf/DSFAttributedStringBuilder","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/dagronf/DSFAttributedStringBuilder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFAttributedStringBuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFAttributedStringBuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFAttributedStringBuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFAttributedStringBuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dagronf","download_url":"https://codeload.github.com/dagronf/DSFAttributedStringBuilder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFAttributedStringBuilder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273183228,"owners_count":25059812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"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":["attributedstring","nsattributedstring","objc","swift"],"created_at":"2024-10-30T10:10:43.579Z","updated_at":"2025-09-01T20:06:43.162Z","avatar_url":"https://github.com/dagronf.png","language":"Swift","readme":"# DSFAttributedStringBuilder\n\nA simple Swift/Objective-C NSAttributedString builder simplifying creation of a styled `NSAttributedString`.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/tag/dagronf/DSFAttributedStringStream\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/macOS-10.10+-red\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/iOS-11.0+-blue\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/tvOS-11.0+-orange\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/macCatalyst-1.0+-yellow\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.0+-orange.svg\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/ObjectiveC-compatible-pink.svg\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-lightgrey\" /\u003e\n    \u003ca href=\"https://swift.org/package-manager\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n```swift\nlet featuredURL = URL(string: \"https://github.com/dagronf/DSFAttributedStringBuilder\")!\nlet attributedString = NSAttributedString.build {\n    $0.append(\"\u003e\u003e\u003e To learn more about attributed string builder, \") \n    $0.link(url: featuredURL, text: \"Click here\")\n    $0.append(\".\")\n}\n```\ngenerates\n\n\\\u003e\\\u003e\\\u003e To learn more about DSFAttributedStringBuilder, [click here](https://github.com/dagronf/DSFAttributedStringBuilder).\n\n\n## Why?\n\nI wanted to be able to use attributed strings within one of my projects, however I kept getting stung with trying to work out offsets (especially regarding complex characters such as emoji, and even moreso when parts of the string were dependent on variable values etc.).  And as the string gets longer, slight changes to the text have major impacts.\n\nI also wanted a _relatively_ safe method for defining the string.  I really like the idea of using HTML style tags, but this would require string parsing to determine offsets and handling parsing errors.\n\nThis library provides a very simple lightweight `NSAttributedString` builder.\n\n```swift\nlet attributedString = \n   NSAttributedString.build {\n      $0.set(NSFont.boldSystemFont(ofSize: 12))\n        .setUnderline(.double)\n        .append(NSLocalizedString(\"Important!\", comment: \"Important text\"))\n}\n```\n\n# Installation\n\n## Using Swift PM\n\nJust add `https://github.com/dagronf/DSFAttributedStringBuilder` to your project.\n\n## Direct\n\nAdd `Sources/DSFAttributedStringBuilder/DSFAttributedStringBuilder.swift` to your project\n\n# API and usage\n\n## Adding text and images\n\n### .append(`\u003ctext\u003e`)\n\nAppends text to the stream. The text will be styled using the currently active styles. For example,\n\n```swift\nlet result = NSAttributedString.build {\n   ...\n\t$0.append(\"This is a test\")\n   ...\n}\n```\n\n### .append(`\u003cimage\u003e`)\n\nAppends an image to the stream. This can be either NSImage or UIImage\n\n```swift\nlet result = NSAttributedString.build {\n   ...\n   let myImage = NSImage(named: NSImage.bookmarksTemplateName)!\n   $0.append(myImage)\n   ...\n  }\n```\n\n### .endl()\n\nAdds a line break\n\n```swift\nstream.append(\"This is a test\").endl().endl()\n      .append(\"Two lines later\")\n```\n\n### .tab()\n\nAdds a tab character\n\n```swift\nstream.append(\"item1\").tab().append(\"value1\").endl()\n      .append(\"item2\").tab().append(\"value2\").endl()\n```\n\n## Setting styles\n\nStyles are applied from the current position in the string onwards, until the end of the string or they are unset or overridden.\n\n### .set(`\u003cvalues\u003e`)\n\nCalling `.set()` on the stream allows you to set some characteristics to the current position and future text in the stream.\n\nCalling `.set()` with an attribute already in progress will override the previous `.set()` from the current point onwards\n\n### .unset(`\u003cvalues\u003e`)\n\nUnsetting a value turns off the style from the current position onwards.\n\n### .unsetAll\nCalling `.unsetAll()` turns off all attributes at the current position.\n\n#### Example: Italicize a section of text\n\n```swift\nlet attributedString = NSAttributedString.build { stream in\n   stream.set(NSColor.textColor)\n      .append(\"This is \")               // Add some plain text\n      .set([.obliqueness: 0.1])         // Turn on italic\n      .append(\"italic text \")           // Add some italic text\n      .set([.obliqueness: -0.1])        // Override previous .obliqueness call with new value from this point on\n      .append(\"backward italic text\")   // Add some backward italic text\n      .unset(.obliqueness)              // Turn off backward italic\n      .append(\". And this is not\")      // Add some plain text\n```\n\n#### Example: Add a tooltip to some text\n\n```swift\nlet attributedString = NSAttributedString.build { \n    $0.set(NSColor.textColor)\n    $0.set(NSFont.systemFont(ofSize: NSFont.systemFontSize))\n    $0.append(\"This could be better performed using a \")\n    $0.set([.toolTip: \"In functional programming, a monad is a design pattern that allows structuring programs generically while automating away boilerplate code needed by the program logic\"])\n    $0.append(\"monad\")\n    $0.set([.baselineOffset: 5])\n    $0.set(NSFont.systemFont(ofSize: NSFont.smallSystemFontSize))\n    $0.append(\"1\")\n    $0.unset([.baselineOffset, .toolTip])\n    $0.set(NSFont.systemFont(ofSize: NSFont.systemFontSize))\n    $0.append(\".\")\n    $0.endl().endl()\n}\n```\n\n### .link(`\u003cURL\u003e`, optional `\u003ctext\u003e`)\n\nAppends `text` to the stream, applying a link `URL` to the text.  The link attribute is automatically unset at the end of `text`.\n\n```swift\nlet attributedString = NSAttributedString.build {\n   $0.append(\"To visit our website, \")\n   $0.link(text: \"click here\", url: URL(string: \"https://apple.com\")!)\n}\n```\n\nOr to simply add a link with the link URL\n\n```swift\nlet attributedString = NSAttributedString.build {\n   $0.link(url: URL(string: \"https://swift.org/\")!)\n}\n```\n\nIf text is not supplied, the text reflects the URL\n\n## Convenience overloads\n\n### NSShadow\n\n`NSShadow` has a number of attributes which need to be defined upfront before it can be used.\n\n```swift\nlet attributedString = NSAttributedString.build { stream in\n   stream.set(NSShadow.build { (shadow) in\n                 shadow.shadowColor = NSColor.disabledControlTextColor\n                 shadow.shadowOffset = NSSize(width: 1, height: -1)\n                 shadow.shadowBlurRadius = 3.0\n              })\n   stream.append(\"This is some shadowed title text\")\n}\n```\n\n### NSParagraphStyle\n\n\n```swift\nlet attributedString = NSAttributedString.build { stream in\n   stream.set(NSParagraphStyle.build { style in\n\t\t\t\tstyle.alignment = .center\n\t\t\t})\n   stream.append(\"This is some centered text\")\n}\n```\n\n## Styles\n\nYou can pre-define styles using a simple class container, and use them to mimic a (basic) style sheet.\n\nFor example :-\n\n```swift\nclass Styles {\n   static var H1: [NSAttributedString.Key : Any] {\n      return [.font: NSFont.boldSystemFont(ofSize: 24), .foregroundColor: NSColor.red ]\n   }\n   static var H2: [NSAttributedString.Key : Any] {\n      return [.font: NSFont.boldSystemFont(ofSize: 18), .foregroundColor: NSColor.systemPink ]\n   }\n   static var P: [NSAttributedString.Key : Any] {\n      return [.font: NSFont.systemFont(ofSize: NSFont.systemFontSize), .foregroundColor: NSColor.textColor ]\n   }\n   static var italic: [NSAttributedString.Key : Any] {\n      return [ .obliqueness: 0.2 ]\n   }\n   static func underline(_ style: NSUnderlineStyle) -\u003e [NSAttributedString.Key : Any] {\n      return [ .underlineStyle: style.rawValue ]\n   }\n   static func underline() -\u003e [NSAttributedString.Key : Any] {\n      return [ .underlineStyle: NSUnderlineStyle.single.rawValue ]\n   }\n   static func PBold() -\u003e [NSAttributedString.Key : Any] {\n      return [.font: NSFont.boldSystemFont(ofSize: NSFont.systemFontSize), .foregroundColor: NSColor.textColor ]\n   }\n}\n\t\nlet attributedString = NSAttributedString.build {\n   $0.set(Styles.P).set(Styles.underline())\n   $0.append(\"Simple test using basic style sheet\")\n   $0.unset(Styles.underline()).endl().endl()\n   $0.set(Styles.H1).append(\"Heading\").endl()\n   $0.set(Styles.H2).append(\"Subheading\").endl()\n   $0.set(Styles.P).append(\"This is the \")\n   $0.set(Styles.italic).append(\"text\").unset(Styles.italic)\n   $0.append(\". \")\n}\n\n```\n\n## Objective-C\n\nA simple objective-c example\n\n```objective-c\nDSFAttributedStringBuilder* builder = [[DSFAttributedStringBuilder alloc] init];\n\n[builder setFont:[NSFont systemFontOfSize:32]];\n[builder setColor:[NSColor textColor]];\n[builder setStyle:NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)];\n[builder append:@\"Heading\"];\n[builder unsetStyle:NSUnderlineStyleAttributeName];\n[builder append:@\" \"];\n[builder appendScaledImage:[NSImage imageNamed:NSImageNameInfo]:CGSizeMake(28, 28)];\n[builder append:@\" With \"];\n[builder setColor:[NSColor systemBlueColor]];\n[builder setStyle:NSObliquenessAttributeName:@(0.2)];\n[builder append:@\"Image\"];\n[builder unsetAll];\n\n[[builder endl] endl];\n\nNSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];\n[style setAlignment:NSTextAlignmentRight];\n[builder setStyle:NSParagraphStyleAttributeName:style];\n[builder setColor:[NSColor textColor]];\n[builder append:@\"﷽\"];\n[[builder endl] endl];\n\nNSAttributedString* attributedString = [builder attributed];\n```\n\n# Alternatives\n\n## MarkdownAttributedString\n\n[Craig Hockenberry](https://github.com/chockenberry) has a fantastic Markdown ⟺ NSAttributedString library called [MarkdownAttributedString](https://github.com/chockenberry/MarkdownAttributedString) written in Objective-C.\n\nIf your formatting needs can be met using [Markdown](https://www.markdownguide.org/getting-started/) and you're not adverse to string parsing (it is in active use in The Iconfactory's [Tot application](https://tot.rocks)) it is highly recommended, especially when dealing with localizations.\n\n# License\n\n```\nMIT License\n\nCopyright (c) 2020 Darren Ford\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfattributedstringbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdagronf%2Fdsfattributedstringbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfattributedstringbuilder/lists"}