Something changed - preview-result behaving differently?

Popclip 2024.5.2 (4615) macOS 12.7.5 (21H1222) (I can’t upgrade past this.)

Recently, an old extension of mine stopped working. A fix of sorts seems to be changing the “after” action to “copy-result” rather than either preview-result or show-result. Trying to figure out why and how to get my old preferred behaviour back?

I’ve been a happy user of PopClip since 2017. I don’t really know ruby or javascript. However, a few years back with cribbing from the documentation, this forum, and other extensions I put together an extension which would backslash escape a string so as to make it shell safe. It displayed the converted output in the popclip popup and left both the original text and the modified text as entries on the clipboard. My primary tool for clipboard is LaunchBar. That has worked fine for years but recently stopped working. This happened around the time of my upgrading to macOS 12.7.5 from 12.1 and converting from the appStore version of PopClip to the direct downloaded version from pilotmoon.

Since then my original ruby script stopped working. Note, when I say stopped working it would still transform and display the selected text but it would not leave the transformed text on the clipboard so that I could paste it somewhere else. Additionally, I have tried to recreate the extension using the newer snippet approach. I’ve tried that in ruby and python both without success when trying to use the preview-result after action with the former behaviour of display in popclip popup and save modified text on clipboard.

I’ve gone through the suggested troubleshooting. I do have Fantastical, although not the helper you mention, Launchbar, Keyboard Maestro, Bartender, BetterTouchTool installed and have made the changes suggested in the support document. However, my original extension nor any snippets I’ve attempted have worked. I’m starting to think my original success with an extension was a bug of some sort. Specifically, my usage was always pasting from the LaunchBar clipboard to a new place usually a different iterm window. Note, my original script was lacking in that it would leave both the escaped string and the original string on the launchbar clipboard history. I would prefer to only have the result from the script left on the clipboard history.

In my current testing, it seems that the behaviour of “preview-result” has changed at some point. In the console, I can see that the correct transformed string is on stdout for copy-result, preview-result, and show-result after actions. However, only copy-result and paste-result (which I don’t want) actually leave the transformed string on the clipboard.

I note in the documentation for the before and after strings “clipboard” is used in the copy-result description while in preview-result and show-result you use the term "pasteboard’. I had been thinking they were one and the same but I am now wondering if they are different. Similarly in copy-result it states “text returned from the script” while in preview-result and show-result you use the phrase “the result”. I have assumed “the result” and “text returned from script” are one and the same.

In the console, I see that stdout has the modified text and popclip logs that it has invoked preview-result and showed-result. But only the unmodified text is found on the clipboard.

I would appreciate any suggestions as to what is wrong with my new snippet. Specifically, why preview-result and show-result after actions only seem to display the result but do not leave them on the clipboard. Also, for reference I’m including the original contents of the popclipext folder for the original solution. My machine dual boots macOS 12.7.5 and macOS 10.14.6. I can confirm that the .popclipext version below performs as I have described under macOS 10.14.6 (18G103) with PopClip 2021.11 (1003785).

Here are the contents of my original ~/Library/Application Support/PopClip/Extensions/EscapedPath.popclipext

Config.plist
<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>Actions</key>
    <array>
    <dict>
    <key>Script Interpreter</key>
    <string>/usr/bin/ruby</string>
    <key>Shell Script File</key>
    <string>script.rb</string>
    <key>Title</key>
    <string>⎋d</string>
        <key>After</key>
    <string>preview-result</string>
    <key>Requirements</key>
    <array>
    <string>copy</string>
    </array>

    </dict>
    </array>
    <key>Extension Description</key>
    <string>convert pwd output to fish escaped path name</string>
    <key>Extension Identifier</key>
    <string>com.rkv.popclip.extension.EscapedPath</string>
      <key>Extension Name</key>
    <string>EscapedPath</string>
    <key>Version</key>
    <integer>2</integer>
    </dict>
    </plist>
script.rb
#!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby

input = ENV['POPCLIP_TEXT']

# popclip extensions first precedes character to be
# escaped with '@@@' and then converts '@@@' to '\\'
# can't recall why I did it this way but it did work in the past

input = input.gsub(/([\ \;\:\!\'\’\(\)\&\{\}\[\]])/,'@@@\1')
input = input.gsub('@@@','\\')
print input

Here’s a snippet version I’m now attempting to get working:

snippet which leaves only unmodified text on clipboard
# #popclip
# { name: escFish, icon: ⎋,  after: preview-result, interpreter: ruby }

input = ENV['POPCLIP_TEXT']

input = input.gsub(/([\ \;\:\!\'\’\(\)\&\{\}\[\]])/,'@@@\1')
input = input.gsub('@@@','\\')
print input

And this version leaves the modified contents on the clipboard as desired. However, it does not preview the modifications only shows the word copied which is as described for “copy-result” action.

snippet which leaves modified text on clipboard
# #popclip
# { name: escFish, icon: ⎋,  after: copy-result, interpreter: ruby }

input = ENV['POPCLIP_TEXT']

input = input.gsub(/([\ \;\:\!\'\’\(\)\&\{\}\[\]])/,'@@@\1')
input = input.gsub('@@@','\\')
print input

So is there an action which displays the output of the script and saves it to the clipboard? Is there a way to have multiple after actions, e.g, show-result and copy-result? Is there something wrong with my script or my interpretation of the preview-result action?

1 Like

You are quite correct that something changed. Both the copy-result and preview-result steps used to leave the text on the clipboard.

This changed in version 2024.5 after some users requested that these actions should not leave the result on the clipboard. It seemed a reasonable request (since, with preview-result we can still get the result to the clipboard by clicking or shift-clicking the button) so I decided to implement it.

However, I left in a “hidden pref” that re-enables the previous behaviour.

In terminal, run the following command:

defaults write com.pilotmoon.popclip CopyOnShow -bool YES

then Quit and restart PopClip.

Sorry for the trouble and the lack of documentation of this detail.

1 Like

There can only be one after action with a shell script action. But in a JavaScript action you can combine multiple such actions in the script itself (rather than using the after key) by using e.g. popclip.copyText() then popclip.showText() for example.

Thank you for both responses. Using Javascript is there a way to avoid the unmodified text being placed on the clipboard?

Also, I wasn’t aware of “shift-clicking” with preview. That might also be sufficient for my usage.

That’s probably something that has existed forever but I forgot to write down anywhere…

In general, shift-clicking any action that would normally paste will make it copy instead.

The unmodified text should not be appearing on the clipboard as a result of any extension’s action unless that action explicitly places it there. However, when PopClip captures the selected text, if can result in the unmodified (i.e. selected) text being briefly placed on the clipboard during the capture. This may be detected by clipboard managers.

For completeness, figured I would leave a copy of the new improved version of my script

// #popclip
// name: escapedJS
// icon: square ⎋
// language: javascript
const shellSafe = popclip.input.text.replace(/([\ \;\:\!\'\'\(\)\&\{\}\[\]])/g, '\\$1');
popclip.copyText(shellSafe);
popclip.showText(shellSafe);

Thanks for the help.

1 Like

Nice job! I love the icon choice :slight_smile:

… By the way, if you find the “Copied” notification annoying (since it obscures the display from showText()), you can use pasteboard.text=shellSafe instead. Under the hood, this is the same thing (putting the text on the clipboard/pasteboard (same thing, we are cursed with two words)) but without the notification.

1 Like