<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Swift on Jingyuan</title>
        <link>https://jingyuan-zheng.github.io/tags/swift/</link>
        <description>Recent content in Swift on Jingyuan</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-US</language>
        <copyright>Jingyuan Zheng</copyright>
        <lastBuildDate>Thu, 09 Jul 2026 18:45:00 +0200</lastBuildDate><atom:link href="https://jingyuan-zheng.github.io/tags/swift/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Text Tray for macOS: A Temporary Workspace for Copied Text</title>
            <link>https://jingyuan-zheng.github.io/p/text-tray-macos-temporary-text-workspace/</link>
            <pubDate>Thu, 09 Jul 2026 18:45:00 +0200</pubDate>
            <guid>https://jingyuan-zheng.github.io/p/text-tray-macos-temporary-text-workspace/</guid>
            <description>&lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/featured.jpg&#34; alt=&#34;Featured image of post Text Tray for macOS: A Temporary Workspace for Copied Text&#34; /&gt;&lt;p&gt;This post introduces Text Tray, a small open-source macOS app that gives copied or passed-in text a temporary place to be read, edited, cleaned up, translated, saved, or copied again.&lt;/p&gt;&#xA;&lt;p&gt;I have open-sourced &lt;strong&gt;Text Tray&lt;/strong&gt;, a tiny macOS utility for a very specific kind of everyday friction: you have some text in the clipboard, but opening Notes, a full editor, a browser AI tool, or a translation app feels heavier than the job deserves.&lt;/p&gt;&#xA;&lt;p&gt;The project is here: &lt;a class=&#34;link&#34; href=&#34;https://github.com/Jingyuan-Zheng/TextTray&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Jingyuan-Zheng/TextTray&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-kind-of-problem-it-solves&#34;&gt;The Kind of Problem It Solves&#xA;&lt;/h2&gt;&lt;p&gt;There is a category of text work that is too small to become a document but too annoying to do in the original app.&lt;/p&gt;&#xA;&lt;p&gt;Maybe a copied email is too narrow to read comfortably. Maybe a PDF paragraph comes out with broken line endings. Maybe you need to count characters before submitting a form. Maybe you only want to rewrite a reply, extract the dates, translate a paragraph, or save a short snippet as Markdown.&lt;/p&gt;&#xA;&lt;p&gt;Text Tray is built for that middle space. It is not a note-taking app, and it is not a clipboard manager. It opens a focused editor for the current clipboard or supplied text, lets you do the small operation, then gets out of the way.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/featured.jpg&#34; alt=&#34;Text Tray main window showing temporary text, line numbers, and text statistics&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 1: Text Tray gives temporary text a larger, editable workspace.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;h2 id=&#34;temporary-by-design&#34;&gt;Temporary by Design&#xA;&lt;/h2&gt;&lt;p&gt;The most important design choice is that Text Tray treats text as temporary.&lt;/p&gt;&#xA;&lt;p&gt;It does not keep a clipboard history, monitor the clipboard in the background, auto-save the editor content, or clear the system clipboard when it closes. Preferences such as language, font size, line numbers, word wrap, statistics, and pinning are saved, but the text itself is not stored.&lt;/p&gt;&#xA;&lt;p&gt;That makes the tool feel closer to a scratch tray than a permanent notebook. You can paste a contract clause, a message draft, or a copied table into it without wondering whether you just created another long-lived record to clean up later.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reading-editing-and-basic-counts&#34;&gt;Reading, Editing, and Basic Counts&#xA;&lt;/h2&gt;&lt;p&gt;The main window is intentionally plain: a text view, line numbers, word wrap, adjustable font size, and a compact status area.&lt;/p&gt;&#xA;&lt;p&gt;The status area shows useful small signals such as character count, word count, line count, selection length, font size, and cursor position. Those are boring features until you need them, which is exactly why I wanted them nearby instead of hidden inside a heavier editor.&lt;/p&gt;&#xA;&lt;p&gt;The window can also stay on top of other apps, which is useful when copying from one place and editing in another.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cleanup-for-text-that-comes-from-pdfs&#34;&gt;Cleanup for Text That Comes from PDFs&#xA;&lt;/h2&gt;&lt;p&gt;One of the first practical cleanup actions is &lt;strong&gt;Repair PDF Line Breaks&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Text copied from PDFs often preserves visual line breaks instead of logical paragraphs. Text Tray includes a local cleanup pass that joins ordinary paragraph lines while protecting common list shapes such as bullets, numbered items, and indented blocks.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/pdf-line-breaks.jpg&#34; alt=&#34;Text Tray repairing copied PDF line breaks&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 2: PDF line-break repair turns copied visual lines back into readable paragraphs.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;There are also smaller cleanup actions for trimming leading and trailing whitespace, removing extra blank lines, normalizing line endings, and removing trailing spaces on each line. The app keeps one-step undo for the last processing operation, which is enough for this kind of quick utility without turning the interface into a workflow editor.&lt;/p&gt;&#xA;&lt;h2 id=&#34;smart-actions-without-leaving-the-window&#34;&gt;Smart Actions Without Leaving the Window&#xA;&lt;/h2&gt;&lt;p&gt;Text Tray also has an AI menu for lightweight structure extraction and rewriting tasks. The current actions include extracting tasks, dates, amounts, and contacts, summarizing requirements, explaining text, checking risks, drafting replies, and organizing content as a checklist or table.&lt;/p&gt;&#xA;&lt;p&gt;On supported systems, these actions use Apple&amp;rsquo;s Foundation Models framework. The app checks whether the system model is available and shows a clear message when Apple Intelligence is not enabled, the device is not eligible, or the model is not ready.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/ai-tasks.jpg&#34; alt=&#34;Text Tray extracting tasks from an email&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 3: AI actions are meant for small, structured operations on the text already in the tray.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;This is deliberately not trying to replace a full AI chat app. The point is speed: if the text is already there, the next action should be one menu command, not another round trip through copy, paste, prompt, copy back.&lt;/p&gt;&#xA;&lt;h2 id=&#34;system-writing-tools-and-translation&#34;&gt;System Writing Tools and Translation&#xA;&lt;/h2&gt;&lt;p&gt;Text Tray also integrates with macOS system Writing Tools when available, so the editor can participate in the same system-level writing assistance used by other native apps.&lt;/p&gt;&#xA;&lt;p&gt;For translation, it uses Apple&amp;rsquo;s Translation framework on supported macOS versions. It can translate to Chinese, translate to English, or produce a Chinese-English bilingual version.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/translation.jpg&#34; alt=&#34;Text Tray showing a translation result&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 4: Translation lives inside the same temporary text window.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The base app targets macOS 13 or later. The newer Apple Intelligence and system translation actions depend on the macOS versions and device support required by Apple&amp;rsquo;s frameworks, so older Macs still get the core editor, cleanup, counting, copy, save, and print features.&lt;/p&gt;&#xA;&lt;h2 id=&#34;saving-when-temporary-text-becomes-useful&#34;&gt;Saving When Temporary Text Becomes Useful&#xA;&lt;/h2&gt;&lt;p&gt;Most tray text can disappear after copying, but sometimes a scratch note turns into something worth keeping.&lt;/p&gt;&#xA;&lt;p&gt;Text Tray can save the current text as &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.csv&lt;/code&gt;, &lt;code&gt;.html&lt;/code&gt;, &lt;code&gt;.swift&lt;/code&gt;, &lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, or a custom extension. The default file name uses a timestamp such as &lt;code&gt;Text_YYYYMMDDHHMMSS.txt&lt;/code&gt;, which is simple but avoids accidental overwrites.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/export.jpg&#34; alt=&#34;Text Tray save and export options&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 5: Save options cover plain text, Markdown, code snippets, and custom extensions.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;There is also a print action, mostly for the occasional case where temporary text needs to leave the screen.&lt;/p&gt;&#xA;&lt;h2 id=&#34;launching-from-shortcuts&#34;&gt;Launching from Shortcuts&#xA;&lt;/h2&gt;&lt;p&gt;The app can be launched normally, but it is more useful when wired into macOS Shortcuts or another automation.&lt;/p&gt;&#xA;&lt;p&gt;For a basic launcher:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;open -n &lt;span class=&#34;s2&#34;&gt;&amp;#34;/Applications/Text Tray.app&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;To pass text directly through standard input:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;APP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/Applications/Text Tray.app&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;%s&amp;#39;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$SHORTCUT_INPUT&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$APP&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/Contents/MacOS/TemporaryClipboardViewer&amp;#34;&lt;/span&gt; --stdin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;div class=&#34;post-figure&#34;&gt;&#xA;    &lt;img src=&#34;https://jingyuan-zheng.github.io/img/text-tray/shortcut-setup.jpg&#34; alt=&#34;macOS Shortcuts setup for launching Text Tray&#34;&gt;&#xA;    &lt;div class=&#34;caption&#34;&gt;Figure 6: Shortcuts makes Text Tray feel like a system text action.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The source is intentionally small: the app is built with Swift, AppKit, SwiftUI, Apple&amp;rsquo;s Foundation Models framework, and the Translation framework. The build script produces a normal &lt;code&gt;.app&lt;/code&gt; bundle and packages it as &lt;code&gt;TextTray.zip&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;where-it-fits&#34;&gt;Where It Fits&#xA;&lt;/h2&gt;&lt;p&gt;Text Tray is not for long writing, project notes, knowledge management, or clipboard archiving. Those jobs already have better tools.&lt;/p&gt;&#xA;&lt;p&gt;It is for the awkward thirty-second text task: make this readable, count this, clean this, extract the dates, draft a reply, translate this paragraph, save this snippet, then move on.&lt;/p&gt;&#xA;&lt;p&gt;That is a small niche, but it appears many times a day. Text Tray gives that niche a proper little window.&lt;/p&gt;&#xA;&lt;h2 id=&#34;related-posts&#34;&gt;Related Posts&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;For document-level translation from Finder, see &lt;a class=&#34;link&#34; href=&#34;https://jingyuan-zheng.github.io/p/translate-document-quick-action/&#34; &gt;Translate Document Quick Action&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;For local AI translation on Apple Silicon, see &lt;a class=&#34;link&#34; href=&#34;https://jingyuan-zheng.github.io/p/mac-lite-translator-apple-silicon-mlx/&#34; &gt;Mac-Lite-Translator&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;For packaging small macOS tools, see &lt;a class=&#34;link&#34; href=&#34;https://jingyuan-zheng.github.io/p/dmg-maker-create-beautiful-macos-installers-automatically/&#34; &gt;How to Make a macOS DMG Installer with a Custom Background&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
        </item></channel>
</rss>
