{"id":16271,"date":"2020-03-06T23:03:04","date_gmt":"2020-03-06T23:03:04","guid":{"rendered":"https:\/\/www.bartbusschots.ie\/s\/?p=16271"},"modified":"2020-03-06T23:03:04","modified_gmt":"2020-03-06T23:03:04","slug":"macos-quick-actions-for-text","status":"publish","type":"post","link":"https:\/\/www.bartbusschots.ie\/s\/2020\/03\/06\/macos-quick-actions-for-text\/","title":{"rendered":"MacOS Quick Actions for Text"},"content":{"rendered":"<p>While I wrote these MacOS Quick Actions to scratch my own proverbial itch, I think they could be of use to others, so I&#8217;m releasing them as open source.<\/p>\n<p>The actions allow you to calculate the word count, line count, and character count of selected text, to convert a text selection to upper case, lower case, or title case, to do the same to the contents of the clipboard, and to convert the clipboard from rich text to plain text and to trim the contents of the clipboard.<\/p>\n<p>You can <a href=\"https:\/\/github.com\/bbusschots\/macos-quickaction-text\" rel=\"noopener noreferrer\" target=\"_blank\">download the actions and read the docs on GitHub<\/a>.<\/p>\n<p>As well as describing what each of the Quick Actions do, the GitHub docs also describe how to install the actions, how to use them, and how to assign keyboard shortcuts to them if desired.<\/p>\n<p>If you&#8217;re curious to learn how these Quick Actions work, read on.<\/p>\n<p><!--more--><\/p>\n<h2>Automator Quick Actions<\/h2>\n<p>All of these Quick Actions are Automator workflows of type Quick Action.<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.40.07.png\" alt=\"Screenshot showing Quick Action as new Document Type in Automator\" width=\"480\" class=\"alignnone size-full wp-image-16277\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.40.07.png 1074w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.40.07-300x268.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.40.07-1024x913.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.40.07-768x685.png 768w\" sizes=\"(max-width: 1074px) 100vw, 1074px\" \/><\/p>\n<p>The actions for altering the clipboard are configured not to take any input and to be available in any app:<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.44.17.png\" alt=\"Screenshot showing workflow taking no input and being available in every app\" width=\"480\" class=\"alignnone size-full wp-image-16278\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.44.17.png 1228w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.44.17-300x55.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.44.17-1024x188.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.44.17-768x141.png 768w\" sizes=\"(max-width: 1228px) 100vw, 1228px\" \/><\/p>\n<p>The actions that alter or measure selected text are configured to take selected text in any app. Those for altering the text are configured to replace the exiting value, and those for measuring are not:<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.52.41.png\" alt=\"Screenshot showing automation action that takes text input in any app and does not replace it\" width=\"480\" class=\"alignnone size-full wp-image-16279\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.52.41.png 1234w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.52.41-300x56.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.52.41-1024x193.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.52.41-768x144.png 768w\" sizes=\"(max-width: 1234px) 100vw, 1234px\" \/><\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.54.29.png\" alt=\"Screenshot showing automation action that takes text input in any app and does replace it\" width=\"480\" class=\"alignnone size-full wp-image-16280\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.54.29.png 1230w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.54.29-300x55.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.54.29-1024x186.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-16.54.29-768x140.png 768w\" sizes=\"(max-width: 1230px) 100vw, 1230px\" \/><\/p>\n<h2>Displaying Messages<\/h2>\n<p>The actions that alter the clipboard or measure the selected text report their actions using the <em>Display Notification<\/em> Automator Action. The actions that measure the selection use a variable to output the calculated value:<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-17.00.11.png\" alt=\"Screenshot showing a Display Notification Automator Action with a variable\" width=\"480\" class=\"alignnone size-full wp-image-16281\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-17.00.11.png 1230w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-17.00.11-300x92.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-17.00.11-1024x315.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-12-at-17.00.11-768x236.png 768w\" sizes=\"(max-width: 1230px) 100vw, 1230px\" \/><\/p>\n<h2>Reading Input Text &#038; Outputting Replacement Text<\/h2>\n<p>The actions that interact with a text selection receive the selection as the input automatically, so no work is needed to fetch the data. The same holds for the output. If the <em>Output replaces selected text<\/em> checkbox is ticked the output of the last action in the workflow will replace the text selection automatically.<\/p>\n<p>Interacting with the clipboard is not automatic, but trivial.<\/p>\n<h3>Interacting with the Clipboard<\/h3>\n<p>The actions that alter the clipboard all have the same basic structure \u00e2\u20ac\u201d start by getting the current value of the clipboard using a <em>Get Contents of Clipboard<\/em> action, alter that value in some way, write the updated value back to the clipboard using a <em>Copy to Clipboard<\/em> action, and finally let the user know the action has completed:<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-10.30.16.png\" alt=\"Screenshot showing automation workflow interacting with the clipboard\" width=\"480\" class=\"alignnone size-full wp-image-16283\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-10.30.16.png 1224w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-10.30.16-300x236.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-10.30.16-1024x806.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-10.30.16-768x605.png 768w\" sizes=\"(max-width: 1224px) 100vw, 1224px\" \/><\/p>\n<h2>Processing the Text<\/h2>\n<p>Because JavaScript is more powerful, and because I&#8217;m very comfortable writing in that language, I prefer to use JavaScrip rather than AppleScript or shell script when writing code blocks in Automator Workflows. This is why most of the quick actions use the Run JavaScript action to process the text, however, I do use the Run Shell Script action for two of the workflows.<\/p>\n<h3>Automatic Conversion to Plain Text<\/h3>\n<p>If you enable the log at the bottom of the Automator window (<em>View<\/em> \u00e2\u2020\u2019 <em>Log<\/em> menu or <code>\u00e2\u0152\u00a5\u00e2\u0152\u02dcL<\/code>) you&#8217;ll see evidence of a extremely useful Automator behaviour. When you add either a <em>Run Shell Script<\/em> or <em>Run JavaScript<\/em> action into a work-flow Automator converts all inputs to those actions to plain text strings before the action executes. Thos means we can be guaranteed that the text that arrives into the scripting actions is plain text.<\/p>\n<p>Automator even tries to be clever about the conversion \u00e2\u20ac\u201d if one of the inputs is a file rather than rich or plain text, automator will replace it with the path to the file as a string. <\/p>\n<h3>String Processing with Shell Script<\/h3>\n<p>The Run Shell Script action gives you the choice of which shell to execute the script with, and how to send the input to the shell.<\/p>\n<p>Given Apple&#8217;s recent move to deprecate Bash and switch to Zsh I&#8217;m now using Zsh in my Automation Workflows.<\/p>\n<p>As for the input, that can either be as command line arguments, or, a STDIN. Most terminal commands are designed to receive information from STDIN, so that&#8217;s usually the best solution. The way to think of this input method is that it is as if the output from another command was piped into the command in the <code>Run Shell Script<\/code> action with the <code>|<\/code> operator.<\/p>\n<p>Regardless of the input method, the output from a Run Shell Script action is STDOUT.<\/p>\n<p>In this case I used the <code>wc<\/code> command with <code>-l<\/code> and <code>-w<\/code> flags to in the Quick actions for calculating the number of lines and words in a text selection. Since you can pipe text to the <code>wc<\/code> command (e.g. <code>cat \/etc\/hosts | wc -l<\/code>), it can accept input via STDIN. The <code>wc<\/code> command prints the number it calculated to STDOUT.<\/p>\n<p>So, because wc can take input form STDIN and outputs to STDOUT, the content of the Run Shell Script action simply needs to be the bare command, so <code>wc -l<\/code> to calculate the number of lines, and <code>wc -w<\/code> to calculate the number of words.<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-12.59.15.png\" alt=\"Screenshot showing Run Shell Script Automator Action\" width=\"480\" class=\"alignnone size-full wp-image-16286\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-12.59.15.png 1224w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-12.59.15-300x88.png 300w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-12.59.15-1024x300.png 1024w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-12.59.15-768x225.png 768w\" sizes=\"(max-width: 1224px) 100vw, 1224px\" \/><\/p>\n<p>Note that I did not use wc to calculate the character count. Why? Because wc is not sufficiently UTF-8-aware for my tastes. It counts accented characters like <em>\u00c3\u00a9<\/em> as two characters, and the same with emoji. For that reason I chose to use JavaScript to do the character count.<\/p>\n<h3>String Processing with JavaScript<\/h3>\n<p>The <em>Run JavaScript<\/em> Automator Action behaves a little differently to the<em> Run Shell Script<\/em> action. It&#8217;s simpler in the sense that it doesn&#8217;t need any configuration (no choosing of shell or input method), but its more complex in the sense that it takes some boiler-plate code to get the action working.<\/p>\n<p>Automator will load all the JavaScript in the action and then execute a function named <code>run()<\/code>. This means you are free to define any variables and helper functions you wish, but to get the action to actually do anything you must include a <code>run()<\/code> function.<\/p>\n<p>When Automator executes the <code>run()<\/code> function it passes the inputs received as an array of strings as the first argument. It passes a hash table with some status and configuration data as the second argument.<\/p>\n<p>Since we know our input will always be the contents of the clipboard or the contents of a text selection we know we&#8217;ll always be passed an array of zero or one strings. Why sometimes zero? If the clipboard contains something that can&#8217;t be converted to a string then the input will be an empty array.<\/p>\n<p>To measure or alter text we need to convert the input array to a string. I chose to do that by joining the input into a string using no separator:<\/p>\n<pre class=\"lang:js decode:true \" >input.join('').toLowerCase();<\/pre>\n<p>If the input is an array of one string that will evaluate to that string, and if the input is an empty array that will evaluate to an empty string.<\/p>\n<p>As a practical example, here is all the code in the <em>Run JavaScript<\/em> action in the <code>Selection to lower case<\/code> quick action:<\/p>\n<pre class=\"lang:js decode:true \" >\r\nfunction run(input, parameters) {\r\n\treturn input.join('').toLowerCase();\r\n}\r\n<\/pre>\n<h2>Using Variables to Store Information<\/h2>\n<p>In order to output the number of lines, words, or characters in an alert we need to capture the output of the relevant Run Shell Script or Run JavaScript action and store it in an Automator variable.<\/p>\n<p>Storing the variable is straight forward, simply add a <em>Set Value of Variable<\/em> action into the workflow directly after the scripting action that produced the output to be saved.<\/p>\n<p>Using the variable is a little less obvious, but just as easy. Be sure the list of variables is visible at the bottom of the Automator window via either the <em>View \u00e2\u2020\u2019 Variables<\/em> menu, or by clicking the very small variables icon at the very bottom of the window. This will show all variables that exist in the workflow. These can be dragged and dropped into other actions. In this case I dragged and dropped the variable holding the relevant count into the text box for the body of the notification in the <em>Show Notification<\/em> action:<\/p>\n<p style=\"text-align:center\"><img decoding=\"async\" src=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09.png\" alt=\"Screenshot showing a variable in use in an Automator workflow\" width=\"480\" class=\"alignnone size-full wp-image-16289\" style=\"border: 1px solid black\" srcset=\"https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09.png 1238w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09-231x300.png 231w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09-788x1024.png 788w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09-768x998.png 768w, https:\/\/www.bartbusschots.ie\/s\/wp-content\/uploads\/2020\/02\/Screenshot-2020-02-13-at-17.33.09-1183x1536.png 1183w\" sizes=\"(max-width: 1238px) 100vw, 1238px\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>While I wrote these MacOS Quick Actions to scratch my own proverbial itch, I think they could be of use to others, so I&#8217;m releasing them as open source. The actions allow you to calculate the word count, line count, and character count of selected text, to convert a text selection to upper case, lower [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[543,12,16],"tags":[269,420,549,457,580],"series":[],"class_list":["post-16271","post","type-post","status-publish","format-standard","hentry","category-automation","category-computers-tech","category-programming","tag-automator","tag-javascript","tag-macos","tag-software-release","tag-zsh"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7t9xK-4er","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/posts\/16271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/comments?post=16271"}],"version-history":[{"count":7,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/posts\/16271\/revisions"}],"predecessor-version":[{"id":16290,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/posts\/16271\/revisions\/16290"}],"wp:attachment":[{"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/media?parent=16271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/categories?post=16271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/tags?post=16271"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.bartbusschots.ie\/s\/wp-json\/wp\/v2\/series?post=16271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}