├── .gitignore ├── Blockquote.popclipext ├── Config.plist ├── README.md ├── blockquote.png └── blockquote.rb ├── BulletList.popclipext ├── Config.plist ├── README.md ├── bulletlist.pl └── bulletlist.png ├── CHANGELOG.md ├── CheckURLs.popclipext ├── Config.plist ├── PreviewURL.workflow │ └── Contents │ │ ├── Info.plist │ │ ├── QuickLook │ │ └── Thumbnail.png │ │ ├── Resources │ │ ├── background.color │ │ └── workflowCustomImage.png │ │ └── document.wflow ├── README.md ├── script.rb └── urlcheck.png ├── Code.popclipext ├── Config.plist ├── README.md ├── code.png └── code.rb ├── Comment.popclipext ├── Config.plist ├── README.md ├── comment.png └── comment.rb ├── CopyCleanLinks.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── CopyPlus.popclipext ├── Config.plist ├── README.md ├── copyplus.png └── copyplus.sh ├── CopyURLS.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── CriticMarkup.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── DefineAbbr.popclipext ├── Config.plist ├── README.md └── script.rb ├── Editor.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── FixPoorlyObscuredEmail.popclipext ├── Config.plist ├── README.md └── script.rb ├── HardWrap.popclipext ├── Config.plist ├── README.md ├── hardwrap.png └── hardwrap.rb ├── IncrementTemplated.popclipext ├── Config.plist ├── README.md ├── increment.png └── script.rb ├── LinkCleaner.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── Markdown2Mindmap.popclipext ├── Config.plist ├── README.md ├── md2mm.png └── md2mm.rb ├── NumberedList.popclipext ├── Config.plist ├── README.md ├── numberlist.pl └── numberlist.png ├── OpenURLS.popclipext ├── Config.plist ├── README.md ├── openurls.png └── openurls.rb ├── Outdent.popclipext ├── Config.plist ├── README.md ├── outdent.png └── outdent.rb ├── PoorText.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.sh ├── README.md ├── SearchLink.popclipext ├── Config.plist ├── README.md ├── searchlink.png └── searchlink.rb ├── SkypeCall.popclipext ├── Config.plist ├── README.md ├── skypecall.png └── skypecall.rb ├── Slugify.popclipext ├── Config.plist ├── README.md ├── hyphen.png └── slugger.rb ├── Sum.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── Twitterify.popclipext ├── Config.plist ├── README.md ├── icon.png └── script.rb ├── URLEncode.popclipext ├── Config.plist ├── README.md └── urlencode.rb ├── VERSION ├── WebMarkdown.popclipext ├── Config.plist ├── README.md ├── download.applescript └── process.sh ├── Wrappers.popclipext ├── Config.plist ├── README.md ├── script.rb └── wrapped.png ├── increment.gif ├── markdownify.popclipext ├── Config.plist ├── README.md └── markdownify.py ├── mise.toml └── nvUltra.popclipext ├── Config.plist ├── README.md ├── _Signature.plist ├── nvUltra.rb └── rocket.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build.sh 3 | *.bak 4 | buildnotes.md 5 | -------------------------------------------------------------------------------- /Blockquote.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | blockquote.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | blockquote.rb 14 | Title 15 | Quote 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Turn indented text into nested Markdown blockquote. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.blockquote 35 | Extension Name 36 | Blockquote 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Blockquote.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Blockquote 2 | 3 | Turn indented text (or any text) into nested Markdown blockquotes. 4 | 5 | * Clicking adds a ">" for each indentation level in the selected text 6 | * Command-click to decrease quote level 7 | * Command-Option-click key to remove all quoting 8 | 9 | When adding quote levels, multiple line breaks between lines creates separate block quotes (by design). If there's a single blank line between to paragraphs, they'll be joined together as paragraphs within a blockquote. More than one starts a new quote. 10 | -------------------------------------------------------------------------------- /Blockquote.popclipext/blockquote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Blockquote.popclipext/blockquote.png -------------------------------------------------------------------------------- /Blockquote.popclipext/blockquote.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | if ARGV[0] =~ /\-?d(ebug)?/ 4 | input = STDIN.read 5 | # ENV['POPCLIP_MODIFIER_FLAGS'] = 1048576.to_s 6 | else 7 | input = ENV['POPCLIP_TEXT'] 8 | end 9 | 10 | def trailing_whitespace(input) 11 | out = [] 12 | input.reverse.each {|line| 13 | if line =~ /^([\s\t])*$/ 14 | out.push("#{$1}") 15 | else 16 | break 17 | end 18 | } 19 | out.reverse.join("\n") 20 | end 21 | 22 | def quote_block(input) 23 | while input[-1] =~ /^\s*$/ 24 | input.pop 25 | end 26 | output = "" 27 | input.each do |line| 28 | quote = ">" 29 | tabs = line.match(/^([\s\t]+)/) 30 | 31 | unless tabs.nil? 32 | count = tabs[1].gsub(/\t/," ").length / 4 33 | count.times do 34 | quote += " >" 35 | end 36 | end 37 | 38 | # don't quote reference definitions 39 | unless line =~ /^\s*\[.*?\]: .*/ 40 | output += line =~ /^\s*$/ ? "#{quote}\n" : "#{quote} #{line.sub(/^[\s\t]*/,'')}\n" 41 | else 42 | output += line 43 | end 44 | end 45 | output 46 | end 47 | 48 | trail_match = input.match(/(?i-m)[\s\n\t]++$/) 49 | trailing = trail_match.nil? ? "" : trail_match[0] 50 | 51 | input = input.split("\n") 52 | output = [] 53 | 54 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 55 | when 1048576 # Command (remove one level of blockquoting) 56 | input.each do |line| 57 | output.push(line.sub(/^(\s*)>\s*/,'\1')) 58 | end 59 | when 1572864 # Option-Command (remove all blockquoting) 60 | input.each do |line| 61 | output.push(line.sub(/^(\s*)(>\s*)*/,'\1')) 62 | end 63 | else # Increase quote level by one 64 | block = [] 65 | skipping = false 66 | input.each_with_index do |line, i| 67 | if line =~ /\S/ && skipping 68 | skipping = false 69 | block = [line] 70 | elsif line =~ /^\s*$/ && (input[i+1] =~ /^\s*$/ || i == input.length - 1) && !skipping 71 | skipping = true 72 | output.push(quote_block(block)) unless block.empty? 73 | block = [] 74 | elsif line =~ /^\s*$/ && skipping 75 | next 76 | else 77 | block.push(line) 78 | end 79 | end 80 | output.push(quote_block(block)) unless block.empty? 81 | end 82 | 83 | print output.join("\n") + trailing #.sub(/\n$/s,'') 84 | 85 | -------------------------------------------------------------------------------- /BulletList.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | bulletlist.png 10 | Script Interpreter 11 | /usr/bin/perl 12 | Shell Script File 13 | bulletlist.pl 14 | Title 15 | Bullet List 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Options 25 | 26 | 27 | Option Identifier 28 | bulletprefix 29 | Option Type 30 | multiple 31 | Option Default Value 32 | * 33 | Option Label 34 | Bullet Prefix 35 | Option Values 36 | 37 | * 38 | + 39 | - 40 | 41 | 42 | 43 | Credits 44 | 45 | Name 46 | Brett Terpstra 47 | Link 48 | http://brettterpstra.com 49 | 50 | Extension Description 51 | Turn lines into a Markdown bullet list. Hold option for numbered list. 52 | Extension Identifier 53 | com.brettterpstra.popclip.extension.bulletlist 54 | Extension Name 55 | BulletList 56 | Version 57 | 2 58 | 59 | 60 | -------------------------------------------------------------------------------- /BulletList.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### BulletList 2 | 3 | PopClip extension to turn lines of text into Markdown bullet items. Indentation is handled as nested lists and existing markers are overwritten (numbered list becomes bullet list). 4 | 5 | #### Numbered lists 6 | 7 | Holding Option (⌥) while clicking the button for the extension in the PopClip bar will create/update a numbered list instead. When the list is already a numbered list, it will be re-numbered to fix any gaps or out-of-order numbering within nest levels. 8 | 9 | #### Clear list formatting 10 | 11 | Holding Command (⌘) while clicking will remove all list prefixes. 12 | 13 | #### Bullet format 14 | 15 | When you install this extension, you'll get an options page where you can select the type of bullet you prefer for unordered lists. This can be accessed again later by clicking the pencil button at the bottom of the list, then clicking the gear button next to the BulletList extension. 16 | -------------------------------------------------------------------------------- /BulletList.popclipext/bulletlist.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # ThisService Perl service script example 4 | # Service type: Filter. 5 | # Revision 1. 6 | 7 | # Perl practices: 8 | # Enables strict mode, requiring that variables are first declared with 'my'. 9 | # This, along with specifying '-w' in the magic first line, is widely 10 | # considered good Perl practice. 11 | use strict; 12 | 13 | # Unicode considerations: 14 | # '-CIO' in the magic first line enables Perl to consider STDIN to always 15 | # contain UTF-8, and to always output to STDOUT in UTF-8. 16 | 17 | my $result = ""; 18 | my %last_marker = (); # Store last marker used for each list depth 19 | $last_marker{0} = ""; 20 | 21 | my $last_leading_space = ""; 22 | my $g_tab_width = 4; 23 | my $g_list_level = 0; 24 | 25 | my $line; 26 | my $marker; 27 | my $item; 28 | my $leading_space; 29 | my $prefix = $ENV{"POPCLIP_OPTION_BULLETPREFIX"}; 30 | 31 | my @resultLines = split /\n/, $ENV{"POPCLIP_TEXT"}; 32 | foreach my $line (@resultLines) { 33 | next if $line =~ /^[\s\t]*$/; 34 | if ( $ENV{"POPCLIP_MODIFIER_FLAGS"} == 524288 ) { # Option, use numbered list 35 | $line =~ s/^([ \t]*)(\d+\. |[\*\+\-] )?/${1}1. /; 36 | } elsif ( $ENV{"POPCLIP_MODIFIER_FLAGS"} == 1572864 ) { # Command-option, clear list 37 | $line =~ s/^([ \t]*)(\d+\. |[\*\+\-] )?\s*(.*)/${1}${3}\n\n/; 38 | } else { 39 | $line =~ s/^([ \t]*)(\d+\. |[\*\+\-] )?/${1}$prefix /; # None, use bullet list 40 | } 41 | $line =~ /^([ \t]*)([\*\+\-]|\d+\.)(\.?\s*)(.*)/; 42 | $leading_space = $1; 43 | $marker = $2; 44 | $item = " " . $4; 45 | 46 | $leading_space =~ s/\t/ /g; # Convert tabs to spaces 47 | 48 | if ( $line !~ /^([ \t]*)([\*\+\-]|\d+\.)/) { 49 | #$result .= "a"; 50 | # not a list line 51 | $result .= $line; 52 | $marker = $last_marker{$g_list_level}; 53 | } elsif (length($leading_space) > length($last_leading_space)+3) { 54 | # New list level 55 | #$result .= "b"; 56 | $g_list_level++; 57 | 58 | $marker =~ s{ 59 | (\d+) 60 | }{ 61 | # Reset count 62 | "1"; 63 | }ex; 64 | 65 | $last_leading_space = $leading_space; 66 | 67 | $result .= "\t" x $g_list_level; 68 | $result .= $marker . $item . "\n"; 69 | } elsif (length($leading_space)+3 < length($last_leading_space)) { 70 | #$result .= "c"; 71 | # back to prior list level 72 | $g_list_level = length($leading_space) / 4; 73 | 74 | # update marker 75 | $marker = $last_marker{$g_list_level}; 76 | $marker =~ s{ 77 | (\d+) 78 | }{ 79 | $1+1; 80 | }ex; 81 | 82 | $last_leading_space = $leading_space; 83 | 84 | $result .= "\t" x $g_list_level; 85 | $result .= $marker . $item . "\n"; 86 | } else { 87 | # No change in level 88 | #$result .= "d"; 89 | 90 | # update marker if it exists 91 | if ($last_marker{$g_list_level} ne "") { 92 | $marker = $last_marker{$g_list_level}; 93 | $marker =~ s{ 94 | (\d+) 95 | }{ 96 | $1+1; 97 | }ex; 98 | } 99 | 100 | 101 | $last_leading_space = $leading_space; 102 | 103 | $result .= "\t" x $g_list_level; 104 | $result .= $marker . $item . "\n"; 105 | } 106 | 107 | $last_marker{$g_list_level} = $marker; 108 | } 109 | 110 | $result =~ s/\n$//; 111 | print $result; 112 | -------------------------------------------------------------------------------- /BulletList.popclipext/bulletlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/BulletList.popclipext/bulletlist.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.45.5 2 | 3 | 2024-12-18 05:40 4 | 5 | ### 1.45.4 6 | 7 | 2024-12-18 05:38 8 | 9 | ### 1.45.3 10 | 11 | 2024-12-18 05:04 12 | 13 | ### 1.44.8 14 | 15 | 2023-02-06 11:19 16 | 17 | ### 1.44.7 18 | 19 | 2023-02-06 11:14 20 | 21 | #### IMPROVED 22 | 23 | - Allow string arrays in template modifiers for Increment Templated 24 | 25 | ### 1.44.6 26 | 27 | 2023-02-06 11:01 28 | 29 | #### IMPROVED 30 | 31 | - Allow string arrays in template modifiers for Increment Templated 32 | 33 | ### 1.44.5 34 | 35 | 2023-02-06 10:21 36 | 37 | #### IMPROVED 38 | 39 | - Using extension READMEs to generate main README 40 | - Updated READMEs 41 | - Allow more complex mathematical equations with i and x in Increment Templated 42 | 43 | ### 1.44.4 44 | 45 | 2023-01-31 08:07 46 | 47 | #### IMPROVED 48 | 49 | - Using extension READMEs to generate main README 50 | - Updated READMEs 51 | 52 | ### 1.44 53 | 54 | * Fix SearchLink extension 55 | 56 | ### 1.43 57 | 58 | * If SearchLink isn't installed, install it when running the SearchLink extension 59 | 60 | ### 1.42 61 | 62 | * Fix nvUltra extension 63 | * Add SearchLink extension 64 | 65 | ### 1.41 66 | 67 | * Update WebMarkdown to allow for gather installs in /opt/homebrew/bin. 68 | 69 | ### 1.40 70 | 71 | * Remove the popcliphtml2text CLI from WebMarkdown that was causing "malicious software" warnings. Now offers to download and install using the signed and notarized package. 72 | 73 | ### 1.38 74 | 75 | * Fix a couple of bugs and improve output of html2text for WebMarkdown 76 | 77 | ### 1.35 78 | 79 | * Convert WebMarkdown to use Swift-based HTML2Text, avoiding need for Python executable 80 | 81 | ### 1.34 82 | 83 | * Fix for WebMarkdown, change to python3 and update html2text 84 | 85 | ### 1.33 86 | 87 | * Fix for bad option default type in some of the plists. 88 | 89 | ### 1.31 90 | 91 | * Increment Templated updates/fixes 92 | 93 | ### 1.28 94 | 95 | * Add "Increment Templated" extension 96 | 97 | ### 1.27 98 | 99 | * Add "HardWrap" extension 100 | 101 | ### 1.25 102 | 103 | * Replace PreviewURL with CheckURLs 104 | * Allows results from preview navigation to modify selected text 105 | * Better icon 106 | 107 | ### 1.24 108 | 109 | * Updated PreviewURL 110 | * Ignore URLs without http(s) protocol 111 | * Handle multiple URLs 112 | * Center preview pane on display 113 | 114 | ### 1.19 --- 1.23 115 | 116 | * stupid commits because I'm having trouble with the build script. Don't mind me. 117 | 118 | ### 1.18 119 | 120 | * Quick little format stripper (PoorText) 121 | 122 | ### 1.17 123 | 124 | * Added "DefineAbbr" extension 125 | 126 | ### 1.16 127 | 128 | * Updated (rewritten) blockquote extension 129 | 130 | ### 1.15 131 | 132 | * Added "Sum" extension 133 | 134 | ### 1.14 135 | 136 | * Added LinkCleaner and CopyCleanLinks extensions 137 | 138 | ### 1.12 139 | 140 | * Added Twitterify extension. 141 | 142 | ### 1.11 143 | 144 | * Added the WebMarkdown extension. 145 | 146 | ### 1.10 147 | 148 | * Updated OpenURLS 149 | * Better regex for extracting URLs 150 | * Hold down Option to combine lines and fix broken urls 151 | * This can cause issues with full urls on consecutive lines, but is handy for a single broken link. 152 | * Leaves leading space on lines, so urls broken with an indent are still screwed. Ran into too many problems trying to parse around that. 153 | 154 | * Added CopyURLs 155 | 156 | Duplicate of OpenURLs, but copies a plain, newline-separated list to the clipboard 157 | 158 | * Added FixPoorlyObscuredEmails 159 | * Fixes "me AT here DOT com" style email obfuscations 160 | * Hold Option to compose new email for matched addresses 161 | 162 | ### 1.8 163 | 164 | * Blockquote: 165 | * Handle line breaks better 166 | * Command-click to decrease quote level 167 | * Command-Option-click key to remove all quoting 168 | * don't quote reference link definitions 169 | * BulletList: Bullet type configuration options, Command modifier to remove list formatting 170 | * CopyPlus: Option modifier to concatenate strings with no extra whitespace 171 | * Credits block for all extensions 172 | * URLEncode extension (also available at [Pilot Moon](http://pilotmoon.com/popclip/extensions/page/URLEncode)) 173 | 174 | ### 1.7 175 | 176 | * Outdent: Command-click to outdent all lines fully 177 | * Too Many Wrappers: Removed Shift-click options as they were breaking stuff. 178 | * CopyPlus: Command-click to add extra linebreak between entries 179 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | urlcheck.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | Check 16 | Regular Expression 17 | (?si)(.*)?((http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#\(\)_]*[\w\-\@^=%&/~\+#])?(.*)? 18 | After 19 | paste-result 20 | Requirements 21 | 22 | paste 23 | 24 | 25 | 26 | Credits 27 | 28 | Name 29 | Brett Terpstra 30 | Link 31 | http://brettterpstra.com 32 | 33 | Extension Description 34 | Preview and update all URLs in selection. 35 | Extension Identifier 36 | com.brettterpstra.popclip.extension.checkurls 37 | Extension Name 38 | CheckURLs 39 | Version 40 | 2 41 | 42 | 43 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/PreviewURL.workflow/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSServices 6 | 7 | 8 | NSBackgroundColorName 9 | background 10 | NSBackgroundSystemColorName 11 | systemBlueColor 12 | NSIconName 13 | workflowCustomImage 14 | NSMenuItem 15 | 16 | default 17 | Preview URL 18 | 19 | NSMessage 20 | runWorkflowAsService 21 | NSRequiredContext 22 | 23 | NSTextContent 24 | URL 25 | 26 | NSSendTypes 27 | 28 | public.utf8-plain-text 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/PreviewURL.workflow/Contents/QuickLook/Thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CheckURLs.popclipext/PreviewURL.workflow/Contents/QuickLook/Thumbnail.png -------------------------------------------------------------------------------- /CheckURLs.popclipext/PreviewURL.workflow/Contents/Resources/background.color: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CheckURLs.popclipext/PreviewURL.workflow/Contents/Resources/background.color -------------------------------------------------------------------------------- /CheckURLs.popclipext/PreviewURL.workflow/Contents/Resources/workflowCustomImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CheckURLs.popclipext/PreviewURL.workflow/Contents/Resources/workflowCustomImage.png -------------------------------------------------------------------------------- /CheckURLs.popclipext/PreviewURL.workflow/Contents/document.wflow: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AMApplicationBuild 6 | 492 7 | AMApplicationVersion 8 | 2.10 9 | AMDocumentVersion 10 | 2 11 | actions 12 | 13 | 14 | action 15 | 16 | AMAccepts 17 | 18 | Container 19 | List 20 | Optional 21 | 22 | Types 23 | 24 | com.apple.cocoa.url 25 | 26 | 27 | AMActionVersion 28 | 2.0.1 29 | AMApplication 30 | 31 | Safari 32 | 33 | AMParameterProperties 34 | 35 | outputTypeTag 36 | 37 | positionTag 38 | 39 | sizeFormatTag 40 | 41 | targetSizeX 42 | 43 | targetSizeY 44 | 45 | userAgentTag 46 | 47 | 48 | AMProvides 49 | 50 | Container 51 | List 52 | Types 53 | 54 | com.apple.cocoa.string 55 | 56 | 57 | ActionBundlePath 58 | /System/Library/Automator/Website Popup.action 59 | ActionName 60 | Website Popup 61 | ActionParameters 62 | 63 | outputTypeTag 64 | 3 65 | positionTag 66 | 0 67 | sizeFormatTag 68 | 99 69 | targetSizeX 70 | 600 71 | targetSizeY 72 | 800 73 | userAgentTag 74 | 0 75 | 76 | BundleIdentifier 77 | com.apple.Automator.WebsitePopup 78 | CFBundleVersion 79 | 2.0.1 80 | CanShowSelectedItemsWhenRun 81 | 82 | CanShowWhenRun 83 | 84 | Category 85 | 86 | AMCategoryInternet 87 | 88 | Class Name 89 | AMWebsitePoppupAction 90 | InputUUID 91 | 8BAAF496-518D-4618-867D-6EBE459A9513 92 | Keywords 93 | 94 | OutputUUID 95 | 9BBAA1F5-1D86-4B6F-A699-2CF8751706F9 96 | UUID 97 | 09D90FBD-1B77-4B38-8148-E6B20C9D35EB 98 | UnlocalizedApplications 99 | 100 | Safari 101 | 102 | arguments 103 | 104 | 0 105 | 106 | default value 107 | 0 108 | name 109 | userAgentTag 110 | required 111 | 0 112 | type 113 | 0 114 | uuid 115 | 0 116 | 117 | 1 118 | 119 | default value 120 | 0 121 | name 122 | positionTag 123 | required 124 | 0 125 | type 126 | 0 127 | uuid 128 | 1 129 | 130 | 2 131 | 132 | default value 133 | 0 134 | name 135 | sizeFormatTag 136 | required 137 | 0 138 | type 139 | 0 140 | uuid 141 | 2 142 | 143 | 3 144 | 145 | default value 146 | 0.0 147 | name 148 | targetSizeY 149 | required 150 | 0 151 | type 152 | 0 153 | uuid 154 | 3 155 | 156 | 4 157 | 158 | default value 159 | 0 160 | name 161 | outputTypeTag 162 | required 163 | 0 164 | type 165 | 0 166 | uuid 167 | 4 168 | 169 | 5 170 | 171 | default value 172 | 0.0 173 | name 174 | targetSizeX 175 | required 176 | 0 177 | type 178 | 0 179 | uuid 180 | 5 181 | 182 | 183 | isViewVisible 184 | 185 | location 186 | 502.500000:322.000000 187 | nibPath 188 | /System/Library/Automator/Website Popup.action/Contents/Resources/Base.lproj/main.nib 189 | 190 | isViewVisible 191 | 192 | 193 | 194 | connectors 195 | 196 | workflowMetaData 197 | 198 | applicationBundleIDsByPath 199 | 200 | applicationPaths 201 | 202 | backgroundColor 203 | 204 | YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9i 205 | amVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGpCwwXGBki 206 | KCkwVSRudWxs1Q0ODxAREhMUFRZWJGNsYXNzW05TQ29sb3JOYW1lXE5TQ29s 207 | b3JTcGFjZV1OU0NhdGFsb2dOYW1lV05TQ29sb3KACIADEAaAAoAEVlN5c3Rl 208 | bV8QD3N5c3RlbUJsdWVDb2xvctUaGw8cDR0eHyASXE5TQ29tcG9uZW50c1VO 209 | U1JHQl8QEk5TQ3VzdG9tQ29sb3JTcGFjZUcwIDAgMSAxTxARMCAwIDAuOTk4 210 | MTg4OTcyNQAQAYAFgAjTIyQNJSYnVE5TSURVTlNJQ0MQB4AGgAdPEQxIAAAM 211 | SExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAA 212 | SUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAA 213 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAA 214 | AVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZ 215 | WgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABw 216 | ZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gA 217 | AAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAA 218 | BDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTgg 219 | SGV3bGV0dC1QYWNrYXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVD 220 | NjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAA 221 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZ 222 | WiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAA 223 | AAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSg 224 | AAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAA 225 | AAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAA 226 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAuSUVD 227 | IDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAA 228 | AAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3Bh 229 | Y2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJl 230 | ZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAA 231 | AAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5 232 | NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4A 233 | FF8uABDPFAAD7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521l 234 | YXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JU 235 | IGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBK 236 | AE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcA 237 | vADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4 238 | AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB 239 | 4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKs 240 | ArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6ID 241 | rgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATT 242 | BOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicG 243 | NwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/ 244 | B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJ 245 | jwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuA 246 | C5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakN 247 | ww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAm 248 | EEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS 249 | 4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9 250 | FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY 251 | +hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxS 252 | HHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+og 253 | FSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPw 254 | JB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0o 255 | PyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyi 256 | LNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUox 257 | gjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZy 258 | Nq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o7 259 | 6DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFq 260 | QaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVH 261 | e0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2T 262 | TdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZU 263 | QlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1 264 | W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfVi 265 | SWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2ma 266 | afFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpx 267 | lXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJ 268 | eed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2C 269 | MIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrK 270 | izCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aU 271 | IJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951k 272 | ndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2n 273 | bqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFg 274 | sdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8 275 | IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbD 276 | x0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7S 277 | P9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W 278 | 3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp 279 | 0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe 280 | 9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//0iorLC1aJGNs 281 | YXNzbmFtZVgkY2xhc3Nlc1xOU0NvbG9yU3BhY2WiLi9cTlNDb2xvclNwYWNl 282 | WE5TT2JqZWN00iorMTJXTlNDb2xvcqIxLwAIABEAGgAkACkAMgA3AEkATABR 283 | AFMAXQBjAG4AdQCBAI4AnACkAKYAqACqAKwArgC1AMcA0gDfAOUA+gECARYB 284 | GAEaARwBIwEoAS4BMAEyATQNgA2FDZANmQ2mDakNtg2/DcQNzAAAAAAAAAIB 285 | AAAAAAAAADMAAAAAAAAAAAAAAAAAAA3P 286 | 287 | backgroundColorName 288 | systemBlueColor 289 | customImageFileData 290 | 291 | iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c 292 | 6QAABI9JREFUWAnNlnuIlUUYh7dMc71kambe2uMlWUOXMkpjDStsQ1qoJBJK 293 | MUjKcMHIMvonoiAwCoMKukBE/2iEQXfFSxt4KcOkwjYzcVdTy1XTKMu0tuc5 294 | fXOaM37Hdq0/+sGz3zvvO998M++8M2e7VZ2+uvNqNXSDE6c7zBldeHEofadA 295 | PYyGYdAbfoN22AWbYC20wH+m8Yz0AuwBP7ICjsEOmAefQAe8BdvgALwLDfCv 296 | 1Je3H4dDsA5mwSC4C/zIJFBmow0egT4wDV6DH7JnDc8uq8AbzeCq/bD7rcbC 297 | YZhvI9KN2D/D1Mh3FfZHYNauifz/aI6ix1Zw1SOj3tbLG7AaLLxUr+BwO3pG 298 | gV7Ybt8RuD7yVzT7EdkIzdAflB9WrsK0htTrD2BWFWA/3AHKWNASDGOXBkd4 299 | xp30PQ0LYDu4z2eBOgEjYAhshvQ9XFV/QB38AhZjeFe/9mXgllwHP0FR8UAe 300 | r/fgOXC2YQArfDjcA07Q2JmQyn6m/yFYDp9B6Ock1APgGIttxHIib8LbsTOy 301 | 52B/AXl7H3Urmqv4+0TqzNpNPHfD4DRei+MgTEsDWft1nhZTZ7SQTq6+R07n 302 | /vha4e4QCylqwNEOG0IgeprWi2F95DuVaRFbK9ZMKov4HbgFitsfJuCZ/RiO 303 | QqrzcZwLLWmgQnsnfq/nQoX4Svxm3HGLRWKxjQHPcJ683RywLS+Y4/P0/Aim 304 | O09ujwuvMejHe2d4PAZAXGhWrx37wYPg8QlZK6YwaXfQdu/94ZoHEyHcovY3 305 | fg6cl1GcgJNw0NHg/R8Gxiy+4MerYTIcgzhOs0zhI9aSC7kC9EmYOGbV+/CN 306 | hnJGNm6zkaMJ+FqhAF2RqxwFHrk4q06mJGflj8hhyKtaO4Yb0crujGbSaTV8 307 | CmZiM3wIHj23x20oyQn8DtvgkpK33HACMq7cfVLLrVoGL4JX+VywrmbBOngU 308 | PAHD4SQ5O7fB7cjTUpwv5QUyn4XmZfU1eOerRngGbreBLgKPullxsmWyAF3l 309 | 9DLv3407MT0+Fmye5uA8AnVZsImnR9Fic9zFoIbBbnjYRipXsAauhCkR9dh+ 310 | wDqZDXHck2HWNsKToMzG5/CYDWQG9oFHXDm5HeDlViYH+xUsyr3wfYQDGDsO 311 | 30X+XdgzwOdUUFZ5I4wAU+0PkzXWB9RYcIxJNlI9j+NbsCAvhEKGgzlzX5wI 312 | NVAAU+qeH4BaiOUK3XNj3v1BXsGt0Bgc8XMQja2wDFxJLFO9He6LndhjoB0u 313 | T/xO0m27OfG7MDN8deIvNV2R/3S8DD1L3r+MBTwsIicaVI3RAvcGR/YczHMt 314 | jE/8N9F2S81eRdUT2QMrYGTUyyx8BU9FPk3PuIUVCk2ffT2GrjioB8Z6eDU4 315 | TvUcR7AZTJerGwjqBvDIxUVkzK1bDn1BnQ3zwStZ+fFnwTryTuiUetHrfrAw 316 | d8ISaIA1sAniC6WOttW+BW4FU+xHLbrp4Ha4tddCl3UBbzTBB2ANHIQOWASx 317 | /Bn2JLl9TtoJtYGrXgq1UKa00suCFRoeSSvcSZl2CzCVfSw+V38IvgRr5P+n 318 | PwGMsOq1VPo9GQAAAABJRU5ErkJggg== 319 | 320 | customImageFileExtension 321 | png 322 | inputTypeIdentifier 323 | com.apple.Automator.text.url 324 | outputTypeIdentifier 325 | com.apple.Automator.nothing 326 | presentationMode 327 | 11 328 | processesInput 329 | 1 330 | serviceInputTypeIdentifier 331 | com.apple.Automator.text.url 332 | serviceOutputTypeIdentifier 333 | com.apple.Automator.nothing 334 | serviceProcessesInput 335 | 1 336 | useAutomaticInputType 337 | 1 338 | workflowTypeIdentifier 339 | com.apple.Automator.servicesMenu 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### CheckURLs 2 | 3 | PopClip extension to show a popup preview for each URL in selected text. Used for confirming the output of scripts like SearchLink without switching to the browser. 4 | 5 | Links are shown sequentially in the order they're found. If a URL is changed by following links in the preview and pressing "OK", the selected text will be updated with the final URL. Because of this, duplicate links in the text are all previewed so they can be modified individually. 6 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 3 | 4 | unless debug 5 | input = ENV['POPCLIP_TEXT'] 6 | else 7 | input =</dev/null}.strip 29 | if new_url && new_url.length > 0 30 | output.sub!(/#{url}/,new_url) 31 | end 32 | end 33 | } 34 | print output 35 | 36 | -------------------------------------------------------------------------------- /CheckURLs.popclipext/urlcheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CheckURLs.popclipext/urlcheck.png -------------------------------------------------------------------------------- /Code.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | code.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | code.rb 14 | Title 15 | <> 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Convert to Markdown inline code or code block. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.code 35 | Extension Name 36 | Code 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Code.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Code 2 | 3 | Turn selected text into Markdown inline code or a code block. This extension "toggles," so if the selection already contains code syntax (inline code or fenced code block) the syntax is removed. 4 | 5 | Detects whether there are multiple lines: 6 | 7 | * if not, it surrounds the input with single backticks 8 | * if so, it wraps the block in triple backticks (fenced) 9 | 10 | When creating an inline code block, it will also detect whitespace at the beginning and end of the selection and make sure that it's excluded from the surrounding backticks. 11 | -------------------------------------------------------------------------------- /Code.popclipext/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Code.popclipext/code.png -------------------------------------------------------------------------------- /Code.popclipext/code.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | input = ENV['POPCLIP_TEXT'] 4 | 5 | if input =~ /(`+).*?\1/m 6 | print input.gsub(/(`+)\n?(.*?)\n?\1/m, '\2') 7 | else 8 | if input.split("\n").length > 1 9 | # output = "" 10 | # input.split("\n").each {|line| 11 | # output += "\t#{line}\n" 12 | # } 13 | # print output.sub(/\n$/s,'') 14 | ## Switching to using fenced code blocks 15 | print "```\n#{input}\n```\n" 16 | else 17 | head = input =~ /^(\s+)/ ? $1 : '' 18 | tail = input =~ /(\s+)$/ ? $1 : '' 19 | print "#{head}`#{input.strip}`#{tail}" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /Comment.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | comment.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | comment.rb 14 | Title 15 | <!-- 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Turn selected text into an HTML/code comment. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.comment 35 | Extension Name 36 | Comment 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Comment.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Comment 2 | 3 | Turn selected text into an HTML or code comment. 4 | 5 | By default, it surrounds selected text with `` style comment tags. Hold various modifier keys to insert other types of comment markers: 6 | 7 | * **Option**: CSS Comment (`/* block of text */`) 8 | * **Command**: Hash Comment (`# before each line`) 9 | * **Command-Option**: Slash comment (`// before each line`) 10 | -------------------------------------------------------------------------------- /Comment.popclipext/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Comment.popclipext/comment.png -------------------------------------------------------------------------------- /Comment.popclipext/comment.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | input = ENV['POPCLIP_TEXT'] 4 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 5 | when 1048576 # Command (Hash) 6 | print input.split("\n").map {|line| 7 | "# #{line}" 8 | }.join("\n") 9 | when 524288 # Option (CSS) 10 | space = input.match(/^((?:\n\s*)*)\S.*?((?:\n\s*)*)$/m) 11 | print "#{space[1]}/* #{input.strip} */#{space[2]}" 12 | when 1572864 # Option-Command (Slash) 13 | print input.split("\n").map {|line| 14 | "// #{line}" 15 | }.join("\n") 16 | else # none (HTML) 17 | space = input.match(/^([\s\n]*)\S.*?([\s\n]*)$/m) 18 | print "#{space[1]}#{space[2]}" 19 | end 20 | -------------------------------------------------------------------------------- /CopyCleanLinks.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | CopyCleanLinks 16 | Regular Expression 17 | (?si)(.*)?((http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#\(\)_]*[\w\-\@^=%&/~\+#])?(.*)? 18 | After 19 | copy-result 20 | 21 | 22 | Credits 23 | 24 | Name 25 | Brett Terpstra 26 | Link 27 | http://brettterpstra.com 28 | 29 | Extension Description 30 | Copies "cleaned" links from selection. 31 | Extension Identifier 32 | com.brettterpstra.popclip.extension.copycleanlinks 33 | Extension Name 34 | CopyCleanLinks 35 | Version 36 | 2 37 | 38 | 39 | -------------------------------------------------------------------------------- /CopyCleanLinks.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### CopyCleanLinks 2 | 3 | PopClip extension to lengthen and clean URLs. Duplicate of LinkCleaner, but only copies results to the clipboard. 4 | 5 | Option: clean all query strings (default: only clean Google UTM strings) 6 | Command: Output just the resulting URL(s) 7 | Command-Option: Output just URL(s) with query strings stripped 8 | -------------------------------------------------------------------------------- /CopyCleanLinks.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CopyCleanLinks.popclipext/icon.png -------------------------------------------------------------------------------- /CopyCleanLinks.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'cgi' 3 | require 'open-uri' 4 | require 'net/http' 5 | require 'rexml/document' 6 | require 'shellwords' 7 | 8 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 9 | 10 | # 1.0 11 | # 2014-03-06 12 | 13 | 14 | unless debug 15 | orig_input = ENV['POPCLIP_TEXT'].dup 16 | else 17 | orig_input = "Brought to you by http://bit.ly/1hQ92Iz and http://brettterpstra.com" 18 | end 19 | 20 | input = orig_input.dup 21 | 22 | strip_all_queries = false 23 | only_links = false 24 | 25 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 26 | when 524288 # Option 27 | strip_all_queries = true 28 | when 1048576 29 | only_links = true 30 | when 1572864 31 | strip_all_queries = true 32 | only_links = true 33 | end 34 | 35 | class String 36 | def clean_google 37 | return self.gsub(/[?&]utm_[scm].+=[^&?\n\s\r!,.\)\]]++/,'') 38 | end 39 | 40 | def clean_queries 41 | return self.sub(/(.*?)\?\S+/,"\\1") 42 | end 43 | end 44 | 45 | begin 46 | o = [] 47 | input.gsub!(/((?:(?:http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#\(\)_]*[\w\-\@^=%&\/~\+#\(\)])?)/mi) {|url| 48 | if url =~ /https?:\/\/[\da-z]+\.[a-z]{2}\/[A-Za-z0-9]+/ 49 | res = Net::HTTP.get(URI.parse("http://api.longurl.org/v2/expand?format=xml&url=#{CGI.escape(url)}")) 50 | doc = REXML::Document.new(res.strip) 51 | url = doc.elements["response/long-url"].text 52 | end 53 | url = url.clean_google 54 | url = url.clean_queries if strip_all_queries || debug 55 | o.push(url) 56 | url 57 | } 58 | 59 | # urls.each {|url| 60 | # if url.length == 3 && url.join("") !~ /^[\d\.]+$/ 61 | 62 | # url = url[0] 63 | 64 | # if url =~ /\)/ && url !~ /\(/ 65 | # url = url.sub(/\).*?$/,'') 66 | # end 67 | 68 | # target = url =~ /^http/ ? url : "http://#{url}" 69 | # o += target + "\n" 70 | # end 71 | # } 72 | if only_links 73 | puts o.join("\n") 74 | else 75 | print input 76 | end 77 | rescue Exception => e 78 | p e if debug 79 | end 80 | -------------------------------------------------------------------------------- /CopyPlus.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | copyplus.png 10 | Script Interpreter 11 | /bin/bash 12 | Shell Script File 13 | copyplus.sh 14 | Title 15 | CopyPLUS 16 | 17 | 18 | Credits 19 | 20 | Name 21 | Brett Terpstra 22 | Link 23 | http://brettterpstra.com 24 | 25 | Extension Description 26 | Append selection to clipboard. 27 | Extension Identifier 28 | com.brettterpstra.popclip.extension.copyplus 29 | Extension Name 30 | CopyPLUS 31 | Version 32 | 2 33 | 34 | 35 | -------------------------------------------------------------------------------- /CopyPlus.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### CopyPLUS 2 | 3 | PopClip extension to append the selection to the current contents in the clipboard. *This is a duplicate of an existing extension (Append) with just slightly better UTF-8 handling, and modifier key handling for copying with and without linebreaks and whitespace.* 4 | 5 | * Hold Command (⌘) when clicking to add an extra line break between entries. 6 | * Hold Option (⌥) to append with no extra whitespace. 7 | -------------------------------------------------------------------------------- /CopyPlus.popclipext/copyplus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CopyPlus.popclipext/copyplus.png -------------------------------------------------------------------------------- /CopyPlus.popclipext/copyplus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clipboard=`__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste` 4 | 5 | # Check for command key 6 | if [[ $POPCLIP_MODIFIER_FLAGS == 1048576 ]]; then 7 | __CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbcopy < 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | CopyURLS 16 | Regular Expression 17 | (?si)(.*)?((http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#\(\)_]*[\w\-\@^=%&/~\+#])?(.*)? 18 | After 19 | copy-result 20 | 21 | 22 | Credits 23 | 24 | Name 25 | Brett Terpstra 26 | Link 27 | http://brettterpstra.com 28 | 29 | Extension Description 30 | Copies only urls in selection to a list in the clipboard. 31 | Extension Identifier 32 | com.brettterpstra.popclip.extension.copyurls 33 | Extension Name 34 | CopyURLS 35 | Version 36 | 2 37 | 38 | 39 | -------------------------------------------------------------------------------- /CopyURLS.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### CopyURLS 2 | 3 | PopClip extension to copy just the URLS in selection. 4 | 5 | Duplicate of OpenURLS, but copies urls to the clipboard, one link per line, instead of opening in browser. 6 | -------------------------------------------------------------------------------- /CopyURLS.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CopyURLS.popclipext/icon.png -------------------------------------------------------------------------------- /CopyURLS.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 3 | 4 | # 1.0 5 | # 2013-09-30 6 | # 7 | # Duplicate of OpenURLs, but copies a plain, newline-separated list to the clipboard 8 | # Better regex for extracting urls 9 | # Hold down Option to combine lines and fix broken urls 10 | # This can cause issues with full urls on consecutive lines, but is handy for a single broken link. 11 | # Leaves leading space on lines, so urls broken with an indent are still screwed. Ran into too many problems trying to parse around that. 12 | 13 | unless debug 14 | input = ENV['POPCLIP_TEXT'] 15 | else 16 | input =< 24 | 25 | http://www.google.com/support/a/bin/answer.py?answer=37673 26 | http://www.google.com/search?client=safari&rls=en&q=share+multiple+links&ie=UTF-8&oe=UTF-8 27 | 28 | http://en.wikipedia.org/wiki/Ed_Roberts_(computer_engineer) 29 | 30 | www.google.com/support/a/bin/answer.py?answer=37673 31 | 32 | http://postable.weblogzinc.com/?blog=tuaw-we, http://postable.weblogzinc.com/?blog=tuaw-we 33 | (http://postable.weblogzinc.com/?blog=tuaw-we). 34 | 35 | ~@emmaboulton Talk to (http://www.premiumcollections.co.uk). They were good in getting me a result with one wanker who took the piss. 36 | 37 | Blog Post: Allan Haley Interviewed at Web 2.0 Expo SF 2010 About Web Fonts http://blog.fonts.com/?p=563 blog.fonts.com/?p=563 38 | 39 | Today's 9:30 Coffee Break: False Beginnings. More on the Blog - http://minnesota.publicradio.org/collections/special/columns/music_blog/archive/2010/05/monday_coffee_b_31.shtml 40 | 41 | Review: iHome+Sleep for iPhone "http://www.pheedcontent.com/click.phdo?i=24518775cad8deb8f509fd82f53afe9a&utm_source=mactweets&utm_medium=twitter" 42 | ENDINPUT 43 | end 44 | 45 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 46 | when 524288 || debug # Option 47 | input = input.split(/[\n\r]/).map {|line| 48 | line.chomp! 49 | line =~ /^$/ ? "\n" : line 50 | }.join("") 51 | end 52 | 53 | o = "" 54 | urls = input.scan(/((?:(?:http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#\(\)_]*[\w\-\@^=%&\/~\+#\(\)])?)/mi) 55 | 56 | urls.each {|url| 57 | if url.length == 3 && url.join("") !~ /^[\d\.]+$/ 58 | 59 | url = url[0] 60 | 61 | if url =~ /\)/ && url !~ /\(/ 62 | url = url.sub(/\).*?$/,'') 63 | end 64 | 65 | target = url =~ /^http/ ? url : "http://#{url}" 66 | o += target + "\n" 67 | end 68 | } 69 | print o 70 | -------------------------------------------------------------------------------- /CriticMarkup.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | wrap 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Options 25 | 26 | 27 | Option Identifier 28 | criticmarkupcomment 29 | Option Type 30 | string 31 | Option Label 32 | Signature 33 | 34 | 35 | Credits 36 | 37 | Name 38 | Brett Terpstra 39 | Link 40 | http://brettterpstra.com 41 | 42 | Extension Description 43 | Insert CriticMarkup 44 | Extension Identifier 45 | com.brettterpstra.popclip.extension.criticmarkup 46 | Extension Name 47 | CriticMarkup 48 | Version 49 | 2 50 | 51 | 52 | -------------------------------------------------------------------------------- /CriticMarkup.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### CriticMarkup 2 | 3 | Allows the quick insertion of [CriticMarkup][] syntax. Optionally fill in a signature to have a comment included after every insert, deletion or change with your initials or name. 4 | 5 | - No modifier: Highlight 6 | - **Command**: Deletion 7 | - **Control**: Insertion 8 | - **Control-Option**: Change 9 | - **Option**: Comment 10 | 11 | [CriticMarkup]: http://criticmarkup.com/spec.php 12 | 13 | There _is_ a PopClip extension for CriticMarkup in the main download package, which I didn't realize when I whipped this one up. I may defer to that one eventually, but I'll wait until I figure out if mine adds anything worthwhile or not. 14 | -------------------------------------------------------------------------------- /CriticMarkup.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/CriticMarkup.popclipext/icon.png -------------------------------------------------------------------------------- /CriticMarkup.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # no modifier: highlight 4 | # command: delete 5 | # control: insert 6 | # control-command: change 7 | # shift: comment 8 | 9 | comment = ENV['POPCLIP_OPTION_CRITICMARKUPCOMMENT'] 10 | 11 | commentmarkup = comment == '' ? '' : "{>>#{comment} - #{Time.now.strftime('%F %T')}<<}" 12 | 13 | ctrlcmdprefix = '{~~' 14 | ctrlcmdsuffix = '~> ~~}' 15 | ctrlprefix = '{++' 16 | ctrlsuffix = '++}' 17 | cmdprefix = '{--' 18 | cmdsuffix = '--}' 19 | shiftprefix = '{>>' 20 | shiftsuffix = '<<}' 21 | prefix = '{==' 22 | suffix = '==}' 23 | 24 | input = ENV['POPCLIP_TEXT'] 25 | 26 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 27 | when 1048576 # Command 28 | print "#{cmdprefix}#{input}#{cmdsuffix}#{commentmarkup}" 29 | when 131072 # Shift 30 | print "#{shiftprefix}#{comment}: #{input}#{shiftsuffix}" 31 | when 262144 # Control 32 | print "#{ctrlprefix}#{input}#{ctrlsuffix}#{commentmarkup}" 33 | when 1310720 # control-command 34 | print "#{ctrlcmdprefix}#{input}#{ctrlcmdsuffix}#{commentmarkup}" 35 | else # none 36 | print "#{prefix}#{input}#{suffix}#{commentmarkup}" 37 | end 38 | -------------------------------------------------------------------------------- /DefineAbbr.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Script Interpreter 9 | /usr/bin/ruby 10 | Shell Script File 11 | script.rb 12 | Title 13 | LOL 14 | 15 | 16 | 17 | Extension Description 18 | Define Abbr, made with PopMaker by Brett Terpstra 19 | Extension Identifier 20 | com.brettterpstra.popclip.extension.DefineAbbr 21 | Extension Name 22 | Define Abbr 23 | Version 24 | 2 25 | 26 | 27 | -------------------------------------------------------------------------------- /DefineAbbr.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### DefineAbbr 2 | 3 | PopClip extension to search textingabbreviations.ca for the selected string. 4 | -------------------------------------------------------------------------------- /DefineAbbr.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby 2 | 3 | require 'cgi' 4 | 5 | url = "http://www.textingabbreviations.ca/{query}/" 6 | query = ENV['POPCLIP_TEXT'] 7 | url.sub!(/\{query\}/,CGI.escape(query)) 8 | 9 | %x{open "#{url}"} 10 | -------------------------------------------------------------------------------- /Editor.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | edit 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Options 25 | 26 | 27 | Option Identifier 28 | includedatetime 29 | Option Type 30 | boolean 31 | Option Label 32 | Include Datetime 33 | Option Default Value 34 | 35 | 36 | 37 | Credits 38 | 39 | Name 40 | Brett Terpstra 41 | Link 42 | http://brettterpstra.com 43 | 44 | Extension Description 45 | Adds ins, del and mark tags to text 46 | Extension Identifier 47 | com.brettterpstra.popclip.extension.editor 48 | Extension Name 49 | Editor 50 | Version 51 | 2 52 | 53 | 54 | -------------------------------------------------------------------------------- /Editor.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Editor 2 | 3 | Extension for adding HTML editor marks to text. 4 | 5 | - No modifier: `` (highlight) 6 | - **Control**: `` (insertion) 7 | - **Command**: `` (deletion) 8 | - **Option**: `` (comment) 9 | -------------------------------------------------------------------------------- /Editor.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Editor.popclipext/icon.png -------------------------------------------------------------------------------- /Editor.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # no modifier: 4 | # control: 5 | # command: 6 | # option: 7 | 8 | include_datetime = ENV['POPCLIP_OPTION_INCLUDEDATETIME'] 9 | date = include_datetime.to_i == 1 ? Time.now.strftime(' datetime="%FT%T%z"') : "" 10 | prefix = "" 11 | suffix = "" 12 | ctrlprefix = "" 13 | ctrlsuffix = "" 14 | cmdprefix = "" 15 | cmdsuffix = "" 16 | optprefix = "" 18 | 19 | input = ENV['POPCLIP_TEXT'] 20 | 21 | space = input.match(/^([\s\n]*)\S.*?([\s\n]*)$/m) 22 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 23 | when 1048576 # Command 24 | print "#{space[1]}#{cmdprefix}#{input.strip}#{cmdsuffix}#{space[2]}" 25 | when 524288 # Option 26 | print "#{space[1]}#{optprefix}#{input.strip}#{optsuffix}#{space[2]}" 27 | when 262144 # ctrl 28 | print "#{space[1]}#{ctrlprefix}#{input.strip}#{ctrlsuffix}#{space[2]}" 29 | else # none 30 | print "#{space[1]}#{prefix}#{input.strip}#{suffix}#{space[2]}" 31 | end 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /FixPoorlyObscuredEmail.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Version 6 | 2 7 | Extension Description 8 | Fix or open AT DOT obscured email addresses. 9 | Extension Name 10 | FixPoorlyObscuredEmail 11 | Extension Identifier 12 | com.brettterpstra.popclip.extension.fixemail 13 | Actions 14 | 15 | 16 | Shell Script File 17 | script.rb 18 | Script Interpreter 19 | /usr/bin/ruby 20 | Title 21 | DOT 22 | After 23 | paste-result 24 | Regular Expression 25 | (?si)(.*)AT\s+[a-z0-9]+\s+DOT(.*) 26 | 27 | 28 | Credits 29 | 30 | Name 31 | Brett Terpstra 32 | Link 33 | http://brettterpstra.com 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /FixPoorlyObscuredEmail.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### FixPoorlyObscuredEmails 2 | 3 | Fixes emails obscured in a "support AT mydomain DOT com" fashion. 4 | 5 | Hold Option to also open an email window for each matched address. This feature does not require edit capability in the current field. 6 | -------------------------------------------------------------------------------- /FixPoorlyObscuredEmail.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 3 | 4 | # 1.0 5 | # 2013-09-30 6 | # 7 | # Fixes emails obscured like "support AT mydomain DOT com" 8 | # Hold down Option to open also a mailto link for matched addresses 9 | 10 | unless debug 11 | input = ENV['POPCLIP_TEXT'] 12 | else 13 | input =< e 40 | p e 41 | ensure # this way makes it easier to debug. Sue me. 42 | exit 0 43 | end 44 | -------------------------------------------------------------------------------- /HardWrap.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | hardwrap.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | hardwrap.rb 14 | Title 15 | Wrap 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Options 25 | 26 | 27 | Option Identifier 28 | column 29 | Option Type 30 | string 31 | Option Label 32 | Column 33 | Option Default Value 34 | 80 35 | 36 | 37 | Option Identifier 38 | altcolumn 39 | Option Type 40 | string 41 | Option Label 42 | Alternate Column 43 | Option Default Value 44 | 70 45 | 46 | 47 | Credits 48 | 49 | Name 50 | Brett Terpstra 51 | Link 52 | http://brettterpstra.com 53 | 54 | Extension Description 55 | Add and remove hard wrapping of paragraphs. 56 | Extension Identifier 57 | com.brettterpstra.popclip.extension.hardwrap 58 | Extension Name 59 | HardWrap 60 | Version 61 | 2 62 | 63 | 64 | -------------------------------------------------------------------------------- /HardWrap.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### HardWrap 2 | 3 | Add hard wrapping to paragraphs. Default wrap column is 80, hold down Option to wrap at an alternate column (modify both in the extension options). Hold down command to unwrap text, removing line breaks between lines but preserving multiple lines between paragraphs. 4 | 5 | * Clicking wraps at ruler, default 80 characters 6 | * Option-click to wrap to alternate width 7 | * Command-click to unwrap text 8 | 9 | -------------------------------------------------------------------------------- /HardWrap.popclipext/hardwrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/HardWrap.popclipext/hardwrap.png -------------------------------------------------------------------------------- /HardWrap.popclipext/hardwrap.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | if ARGV[0] =~ /\-?d(ebug)?/ 4 | input = STDIN.read 5 | # ENV['POPCLIP_MODIFIER_FLAGS'] = 1048576.to_s # Command 6 | # ENV['POPCLIP_MODIFIER_FLAGS'] = 524288.to_s # Option 7 | column = 80 8 | altcolumn = 60 9 | else 10 | input = ENV['POPCLIP_TEXT'] 11 | column = ENV['POPCLIP_OPTION_COLUMN'].to_i 12 | altcolumn = ENV['POPCLIP_OPTION_ALTCOLUMN'].to_i 13 | end 14 | 15 | 16 | class String 17 | def wrap(col = 80) 18 | self.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/, "\\1\\3\n").strip 19 | end 20 | 21 | def unwrap 22 | self.split(/\n{2,}/).map {|para| para.gsub(/(\S *)\n( *\S)/, '\1 \2')}.join("\n\n").strip 23 | end 24 | end 25 | 26 | trail_match = input.match(/(?i-m)[\s\n\t]++$/) 27 | trailing = trail_match.nil? ? "" : trail_match[0] 28 | 29 | output = [] 30 | 31 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 32 | when 1048576 # Command - Unwrap 33 | print input.unwrap 34 | when 524288 # Option - Wrap at alternate column 35 | print input.wrap(altcolumn) 36 | else # Wrap at default column 37 | print input.wrap(column) 38 | end 39 | 40 | print trailing 41 | -------------------------------------------------------------------------------- /IncrementTemplated.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | increment.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | Increment 16 | Regular Expression 17 | (?mis)^(.*?)##(\d+(\.\.\d+)?\.\.\d+|(.+,)+.+)##(.*)$ 18 | After 19 | paste-result 20 | Requirements 21 | 22 | paste 23 | 24 | 25 | 26 | Credits 27 | 28 | Name 29 | Brett Terpstra 30 | Link 31 | http://brettterpstra.com 32 | 33 | Extension Description 34 | Repeat text by incrementing template values. 35 | Extension Identifier 36 | com.brettterpstra.popclip.extension.incrementtemplated 37 | Extension Name 38 | Increment Templated 39 | Version 40 | 2 41 | 42 | 43 | -------------------------------------------------------------------------------- /IncrementTemplated.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Increment Templated 2 | 3 | PopClip extension to increment and repeat templated text. 4 | 5 | Select and run on the following text: 6 | 7 | ``` 8 | This is a numeric increment ##0..2##. 9 | ``` 10 | 11 | Which will generate: 12 | 13 | ``` 14 | This is a numeric increment 0. 15 | This is a numeric increment 1. 16 | ``` 17 | 18 | Specify a value to increment by with `##START..INCREMENT..END##`, e.g. `##0..2..10##` would insert 0, 2, 4, 6, 8, and 10. 19 | 20 | ![Increment Templated](https://raw.githubusercontent.com/ttscoff/popclipextensions/master/increment.gif) 21 | 22 | #### Placeholders 23 | 24 | You can use placeholders with basic math modification. `##x##` inserts the current element again. `##i##` inserts the 0-based index in the iteration. So if the template is `##5..7##`, on the second iteration `x` would hold `6` and `i` would hold `1`. 25 | 26 | Apply math functions to the placeholders using basic operator symbols (including `%` for mod). To insert the current value times 10, use `##x*10##`. More complex equations are allowed, e.g. `##(i+2)*10##`. Use `%` for modulus. 27 | 28 | You can include leading zeroes on math operations to pad the result. If you want to just pad the number without modifying, you would use `##x*0001##`, which would turn `5` into `0005` and `50` into `0050`. Including a 0 padding on any element of the equation will result in padded output. 29 | 30 | 31 | #### String Arrays 32 | 33 | You can also use arrays of strings or numbers: 34 | 35 | ``` 36 | Hello ##mother,father,sister,brother##. And repeat with ##x##. 37 | ``` 38 | 39 | Yields: 40 | 41 | ``` 42 | Hello mother. And repeat with mother. 43 | Hello father. And repeat with father. 44 | Hello sister. And repeat with sister. 45 | Hello brother. And repeat with brother. 46 | ``` 47 | 48 | The `##i##` placeholder (zero-based index) with math operators is also available in string array replacements. If you want the index to also refer to strings, add `#list,of,strings` after the index or equation, e.g. `##i%2#odd,even##` to insert `odd` and `even` alternately with each iteration. 49 | 50 | Example: 51 | 52 | ``` 53 | .element-##one,two,three## { 54 | text-indent: ##i*10##px; 55 | } 56 | ``` 57 | 58 | ``` 59 | .element-one { 60 | text-indent: 0px; 61 | } 62 | .element-two { 63 | text-indent: 10px; 64 | } 65 | .element-three { 66 | text-indent: 20px; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /IncrementTemplated.popclipext/increment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/IncrementTemplated.popclipext/increment.png -------------------------------------------------------------------------------- /IncrementTemplated.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # frozen_string_literal: true 3 | 4 | input = ENV['POPCLIP_TEXT'] 5 | 6 | NUMERIC_RX = /(\?\:)?##(\d+)(?:\.\.(\d+))?\.\.(\d+)##/.freeze 7 | ARRAY_RX = /##(.*?)##/.freeze 8 | 9 | def get_modifiers(input) 10 | input.scan(%r{##(([ix0-9()+\-/*%]+)*)(#([^#]+))?##}).map do 11 | m = Regexp.last_match 12 | padding = if m[2].nil? 13 | '%d' 14 | else 15 | t = m[2].match(/\b(0+)([1-9]\d*)?/) 16 | t.nil? || m[2] =~ /^0$/ ? '%d' : "%0#{t[0].length}d" 17 | end 18 | 19 | options_array = m[3].nil? ? nil : m[4].split(/,/).map(&:strip) 20 | 21 | base = m[1].nil? ? 'x' : m[1] 22 | inc = m[2].nil? ? '' : m[2].gsub(/\b(0+\d+)/, &:to_i) 23 | 24 | [Regexp.escape(m[0]), inc, padding, base, options_array] 25 | end 26 | end 27 | 28 | def process_array(input) 29 | template = input.match(ARRAY_RX) 30 | replacements = template[1].split(/,/).map(&:strip) 31 | modified = get_modifiers(input) 32 | output = [] 33 | 34 | replacements.each_with_index do |replacement, idx| 35 | out = input.sub(/#{Regexp.escape(template[0])}/, replacement) 36 | out.gsub!(/##[0x]##/, replacement) 37 | modified.each do |mod| 38 | next if mod.nil? 39 | 40 | equat = mod[3].gsub(/\b0+/, '').gsub(/x/, (idx + 1).to_s).gsub(/i/, idx.to_s) 41 | if mod[4] 42 | out.sub!(/#{mod[0]}/, mod[4][(mod[2] % (eval equat)).to_i] || '') 43 | else 44 | out.sub!(/#{mod[0]}/, (mod[2] % (eval equat).to_s)) 45 | end 46 | end 47 | 48 | output.push(out) 49 | end 50 | 51 | output.join("\n") 52 | end 53 | 54 | def process_numeric(input) 55 | template = input.match(NUMERIC_RX) 56 | disp = template[1].nil? ? true : false 57 | inc = template[3].nil? ? 1 : template[3].to_i 58 | 59 | modified = get_modifiers(input) 60 | 61 | padding = template[2].match(/^(0+)([1-9](\d+)?)?/) 62 | 63 | padding = if padding.nil? || template[2] =~ /^0$/ 64 | '%d' 65 | else 66 | "%0#{padding[0].length}d" 67 | end 68 | 69 | output = [] 70 | idx = 0 71 | count_start = template[2].to_i 72 | count_end = template[4].to_i 73 | 74 | while (count_start <= count_end) do 75 | replacement = disp ? padding % count_start.to_i : '' 76 | out = input.sub(/#{Regexp.escape(template[0])}/, replacement) 77 | modified.each do |mod| 78 | next if mod.nil? 79 | 80 | equat = mod[3].gsub(/\b0+/, '').gsub(/x/, (idx + 1).to_s).gsub(/i/, idx.to_s) 81 | 82 | if mod[4] 83 | out.sub!(/#{mod[0]}/, mod[4][(mod[2] % (eval equat)).to_i] || '') 84 | else 85 | out.sub!(/#{mod[0]}/, (mod[2] % (eval equat).to_s)) 86 | end 87 | end 88 | output << out 89 | count_start += inc 90 | idx += 1 91 | end 92 | 93 | output.join("\n") 94 | end 95 | 96 | if input =~ NUMERIC_RX 97 | input = process_numeric(input) 98 | elsif input =~ ARRAY_RX 99 | input = process_array(input) 100 | end 101 | print input 102 | -------------------------------------------------------------------------------- /LinkCleaner.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | LinkCleaner 16 | Regular Expression 17 | (?si)(.*)?((http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#\(\)_]*[\w\-\@^=%&/~\+#])?(.*)? 18 | After 19 | paste-result 20 | 21 | 22 | Options 23 | 24 | 25 | Option Identifier 26 | gaonly 27 | Option Type 28 | boolean 29 | Option Default Value 30 | 31 | Option Label 32 | GA Only 33 | 34 | 35 | Credits 36 | 37 | Name 38 | Brett Terpstra 39 | Link 40 | http://brettterpstra.com 41 | 42 | Extension Description 43 | Lengthens and cleans urls in selection. 44 | Extension Identifier 45 | com.brettterpstra.popclip.extension.linkcleaner 46 | Extension Name 47 | LinkCleaner 48 | Version 49 | 2 50 | 51 | 52 | -------------------------------------------------------------------------------- /LinkCleaner.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### LinkCleaner 2 | 3 | PopClip extension to lengthen and clean URLs. 4 | 5 | Use extension settings to determine whether it strips Google Analytics strings only, or _all_ query strings. 6 | 7 | - Option: force clean all query strings, ignore settings 8 | - Command: Output just the resulting URL(s) 9 | - Command-Option: Output just URL(s) with all query strings stripped 10 | -------------------------------------------------------------------------------- /LinkCleaner.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/LinkCleaner.popclipext/icon.png -------------------------------------------------------------------------------- /LinkCleaner.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'cgi' 3 | require 'open-uri' 4 | require 'net/http' 5 | require 'rexml/document' 6 | require 'shellwords' 7 | 8 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 9 | 10 | # 1.0 11 | # 2014-03-06 12 | 13 | 14 | unless debug 15 | strip_all_queries = ENV['POPCLIP_OPTION_GAONLY'].to_i == 0 16 | orig_input = ENV['POPCLIP_TEXT'].dup 17 | else 18 | strip_all_queries = true 19 | orig_input = "Brought to you by http://bit.ly/1hQ92Iz and http://brettterpstra.com, https://clutchpoints.com/clippers-news-rajon-rondo-speaks-out-after-clippers-debut-vs-lakers/?fbclid=IwAR3epED82RKaRTrmL4X_uBCoVjU6mmFxFhZcAXshKwMzm17RuAT_oxxteiE" 20 | end 21 | 22 | input = orig_input.dup 23 | 24 | only_links = false 25 | 26 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 27 | when 524288 # Option 28 | strip_all_queries = true 29 | when 1048576 30 | only_links = true 31 | when 1572864 32 | strip_all_queries = true 33 | only_links = true 34 | end 35 | 36 | class String 37 | def clean_google 38 | return self.gsub(/[?&]utm_[scm].+=[^&?\n\s\r!,.\)\]]++/,'') 39 | end 40 | 41 | def clean_queries 42 | return self.sub(/(.*?)\?\S+/,"\\1") 43 | end 44 | end 45 | 46 | begin 47 | o = [] 48 | input.gsub!(/((?:(?:http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#\(\)_]*[\w\-\@^=%&\/~\+#\(\)])?)/mi) {|url| 49 | url = url.clean_google 50 | url = url.clean_queries if strip_all_queries || debug 51 | o.push(url) 52 | url 53 | } 54 | 55 | if only_links 56 | puts o.join("\n") 57 | else 58 | print input 59 | end 60 | rescue Exception => e 61 | print orig_input 62 | end 63 | -------------------------------------------------------------------------------- /Markdown2Mindmap.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | md2mm.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | md2mm.rb 14 | Title 15 | md2mm 16 | After 17 | copy-result 18 | 19 | 20 | Credits 21 | 22 | Name 23 | Brett Terpstra 24 | Link 25 | http://brettterpstra.com 26 | 27 | Extension Description 28 | Convert text/outlines to tab-indented outlines for pasting into mind maps. 29 | Extension Identifier 30 | com.brettterpstra.popclip.extension.md2mm 31 | Extension Name 32 | md2mm 33 | Version 34 | 2 35 | 36 | 37 | -------------------------------------------------------------------------------- /Markdown2Mindmap.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Markdown to Mindmap 2 | 3 | Takes a selection of plain text containing markdown headlines, list items and paragraphs and converts it into a format ready for pasting into a mind mapping application (such as MindNode, MindManager or MindMeister) as separate nodes/topics. 4 | -------------------------------------------------------------------------------- /Markdown2Mindmap.popclipext/md2mm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Markdown2Mindmap.popclipext/md2mm.png -------------------------------------------------------------------------------- /Markdown2Mindmap.popclipext/md2mm.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'shellwords' 3 | 4 | input = ENV['POPCLIP_TEXT'] 5 | 6 | def outdent(input) 7 | shortest = false 8 | input.scan(/^\s*/m).each do |leader| 9 | if shortest == false || leader.length < shortest.length 10 | shortest = leader 11 | end 12 | end 13 | input.gsub(/^#{shortest}/m,'').strip 14 | end 15 | 16 | # initial outdent and create array 17 | lines = outdent(input).split("\n") 18 | 19 | 20 | # Remove blank lines 21 | lines.delete_if {|line| line =~ /^\s*$/} 22 | 23 | 24 | # Handle converting headlines and lists to indented outline 25 | last_level = 0 26 | lines.map! {|line| 27 | if line =~ /^#\s/ 28 | line.gsub!(/^# /,"") 29 | last_level = 1 30 | elsif line =~ /^## / 31 | line.gsub!(/^## /,"\t") 32 | last_level = 2 33 | elsif line =~ /^### / 34 | line.gsub!(/^### /,"\t\t") 35 | last_level = 3 36 | elsif line =~ /^#### / 37 | line.gsub!(/^#### /,"\t\t\t") 38 | last_level = 4 39 | elsif line =~ /^##### / 40 | line.gsub!(/^##### /,"\t\t\t\t") 41 | last_level = 5 42 | elsif line =~ /^###### / 43 | line.gsub!(/^###### /,"\t\t\t\t\t") 44 | last_level = 6 45 | else 46 | line.gsub!(/(\s*)(\d\.|[\-\*\+])\s/,"\\1") 47 | line.gsub!(/\s{4}/,"\t") unless line.nil? 48 | last_level.times do 49 | line = "\t" + line 50 | end 51 | end 52 | line.chomp 53 | } 54 | 55 | # Copy to cliipboard 56 | # %x{printf #{Shellwords.escape(outdent(lines.join("\n")).strip)}|pbcopy} 57 | 58 | print outdent(lines.join("\n")).strip 59 | -------------------------------------------------------------------------------- /NumberedList.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | numberlist.png 10 | Script Interpreter 11 | /usr/bin/perl 12 | Shell Script File 13 | numberlist.pl 14 | Title 15 | Numbered List 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Turn lines into a Markdown numbered list. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.numberedlist 35 | Extension Name 36 | NumberedList 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /NumberedList.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### NumberedList 2 | 3 | PopClip extension to turn lines of text into Markdown numbered items. Will sort and update an existing numbered list as well, and convert bullets on list items to numbers. 4 | 5 | This is only here if you want a separate button for numbered lists. Otherwise you can just use BulletList and hold down option to create an ordered list instead. 6 | -------------------------------------------------------------------------------- /NumberedList.popclipext/numberlist.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # ThisService Perl service script example 4 | # Service type: Filter. 5 | # Revision 1. 6 | 7 | # Perl practices: 8 | # Enables strict mode, requiring that variables are first declared with 'my'. 9 | # This, along with specifying '-w' in the magic first line, is widely 10 | # considered good Perl practice. 11 | use strict; 12 | 13 | # Unicode considerations: 14 | # '-CIO' in the magic first line enables Perl to consider STDIN to always 15 | # contain UTF-8, and to always output to STDOUT in UTF-8. 16 | 17 | my $result = ""; 18 | my %last_marker = (); # Store last marker used for each list depth 19 | $last_marker{0} = ""; 20 | 21 | my $last_leading_space = ""; 22 | my $g_tab_width = 4; 23 | my $g_list_level = 0; 24 | 25 | my $line; 26 | my $marker; 27 | my $item; 28 | my $leading_space; 29 | 30 | my @resultLines = split /\n/, $ENV{"POPCLIP_TEXT"}; 31 | foreach my $line (@resultLines) { 32 | next if $line =~ /^[\s\t]*$/; 33 | $line =~ s/^([ \t]*)(\d+\. |[\*\+\-] )?/${1}1. /; 34 | $line =~ /^([ \t]*)([\*\+\-]|\d+\.)(\.?\s*)(.*)/; 35 | $leading_space = $1; 36 | $marker = $2; 37 | $item = " " . $4; 38 | 39 | $leading_space =~ s/\t/ /g; # Convert tabs to spaces 40 | 41 | if ( $line !~ /^([ \t]*)([\*\+\-]|\d+\.)/) { 42 | #$result .= "a"; 43 | # not a list line 44 | $result .= $line; 45 | $marker = $last_marker{$g_list_level}; 46 | } elsif (length($leading_space) > length($last_leading_space)+3) { 47 | # New list level 48 | #$result .= "b"; 49 | $g_list_level++; 50 | 51 | $marker =~ s{ 52 | (\d+) 53 | }{ 54 | # Reset count 55 | "1"; 56 | }ex; 57 | 58 | $last_leading_space = $leading_space; 59 | 60 | $result .= "\t" x $g_list_level; 61 | $result .= $marker . $item . "\n"; 62 | } elsif (length($leading_space)+3 < length($last_leading_space)) { 63 | #$result .= "c"; 64 | # back to prior list level 65 | $g_list_level = length($leading_space) / 4; 66 | 67 | # update marker 68 | $marker = $last_marker{$g_list_level}; 69 | $marker =~ s{ 70 | (\d+) 71 | }{ 72 | $1+1; 73 | }ex; 74 | 75 | $last_leading_space = $leading_space; 76 | 77 | $result .= "\t" x $g_list_level; 78 | $result .= $marker . $item . "\n"; 79 | } else { 80 | # No change in level 81 | #$result .= "d"; 82 | 83 | # update marker if it exists 84 | if ($last_marker{$g_list_level} ne "") { 85 | $marker = $last_marker{$g_list_level}; 86 | $marker =~ s{ 87 | (\d+) 88 | }{ 89 | $1+1; 90 | }ex; 91 | } 92 | 93 | 94 | $last_leading_space = $leading_space; 95 | 96 | $result .= "\t" x $g_list_level; 97 | $result .= $marker . $item . "\n"; 98 | } 99 | 100 | $last_marker{$g_list_level} = $marker; 101 | } 102 | 103 | $result =~ s/\n$//; 104 | print $result; 105 | -------------------------------------------------------------------------------- /NumberedList.popclipext/numberlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/NumberedList.popclipext/numberlist.png -------------------------------------------------------------------------------- /OpenURLS.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | openurls.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | openurls.rb 14 | Title 15 | OpenURLS 16 | Regular Expression 17 | (?si)(.*)?((http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#\(\)_]*[\w\-\@^=%&/~\+#])?(.*)? 18 | After 19 | show-status 20 | 21 | 22 | Credits 23 | 24 | Name 25 | Brett Terpstra 26 | Link 27 | http://brettterpstra.com 28 | 29 | Extension Description 30 | Open all urls in selection. 31 | Extension Identifier 32 | com.brettterpstra.popclip.extension.openurls 33 | Extension Name 34 | OpenURLS 35 | Version 36 | 2 37 | 38 | 39 | -------------------------------------------------------------------------------- /OpenURLS.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### OpenURLS 2 | 3 | PopClip extension to open all URLS in selection. 4 | -------------------------------------------------------------------------------- /OpenURLS.popclipext/openurls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/OpenURLS.popclipext/openurls.png -------------------------------------------------------------------------------- /OpenURLS.popclipext/openurls.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 3 | 4 | # 1.1 5 | # 2013-09-30 6 | # 7 | # Better regex for extracting urls 8 | # Hold down Option to combine lines and fix broken urls 9 | # This can cause issues with full urls on consecutive lines, but is handy for a single broken link. 10 | # Leaves leading space on lines, so urls broken with an indent are still screwed. Ran into too many problems trying to parse around that. 11 | 12 | unless debug 13 | input = ENV['POPCLIP_TEXT'] 14 | else 15 | input =< 21 | 22 | http://www.google.com/support/a/bin/answer.py?answer=37673 23 | http://www.google.com/search?client=safari&rls=en&q=share+multiple+links&ie=UTF-8&oe=UTF-8 24 | 25 | http://en.wikipedia.org/wiki/Ed_Roberts_(computer_engineer) 26 | 27 | www.google.com/support/a/bin/answer.py?answer=37673 28 | 29 | http://postable.weblogzinc.com/?blog=tuaw-we, http://postable.weblogzinc.com/?blog=tuaw-we 30 | (http://postable.weblogzinc.com/?blog=tuaw-we). 31 | 32 | ~@emmaboulton Talk to (http://www.premiumcollections.co.uk). They were good in getting me a result with one wanker who took the piss. 33 | 34 | Blog Post: Allan Haley Interviewed at Web 2.0 Expo SF 2010 About Web Fonts http://blog.fonts.com/?p=563 blog.fonts.com/?p=563 35 | 36 | Today's 9:30 Coffee Break: False Beginnings. More on the Blog - http://minnesota.publicradio.org/collections/special/columns/music_blog/archive/2010/05/monday_coffee_b_31.shtml 37 | 38 | Review: iHome+Sleep for iPhone "http://www.pheedcontent.com/click.phdo?i=24518775cad8deb8f509fd82f53afe9a&utm_source=mactweets&utm_medium=twitter" 39 | ENDINPUT 40 | end 41 | 42 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 43 | when 524288 || debug # Option 44 | input = input.split(/[\n\r]/).map {|line| 45 | line.chomp! 46 | line =~ /^$/ ? "\n" : line 47 | }.join("") 48 | end 49 | 50 | o = "" 51 | urls = input.scan(/((?:(?:http|https):\/\/)?[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#\(\)_]*[\w\-\@^=%&\/~\+#\(\)])?)/mi) 52 | 53 | urls.each {|url| 54 | if url.length == 3 55 | 56 | url = url[0] 57 | 58 | if url =~ /\)/ && url !~ /\(/ 59 | url = url.sub(/\).*?$/,'') 60 | end 61 | 62 | target = url =~ /^http/ ? url : "http://#{url}" 63 | 64 | unless debug 65 | %x{open '#{target}'} 66 | sleep 1 67 | else 68 | o += target + "\n" 69 | end 70 | end 71 | } 72 | print o if debug 73 | -------------------------------------------------------------------------------- /Outdent.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | outdent.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | outdent.rb 14 | Title 15 | |< 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Outdent the selection. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.outdent 35 | Extension Name 36 | Outdent 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Outdent.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Outdent 2 | 3 | Fully outdents the selection, maintaining nested indentation. 4 | -------------------------------------------------------------------------------- /Outdent.popclipext/outdent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Outdent.popclipext/outdent.png -------------------------------------------------------------------------------- /Outdent.popclipext/outdent.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | input = ENV['POPCLIP_TEXT'] 4 | # input =< 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /bin/bash 12 | Shell Script File 13 | script.sh 14 | Title 15 | PoorText 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Strip rich text formatting 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.poortext 35 | Extension Name 36 | PoorText 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /PoorText.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### PoorText 2 | 3 | Make rich text go broke. 4 | 5 | Strips rich text formatting from selection. There are probably multiple others that do this, but it's so easy I just made it myself. 6 | -------------------------------------------------------------------------------- /PoorText.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/PoorText.popclipext/icon.png -------------------------------------------------------------------------------- /PoorText.popclipext/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | logger "$POPCLIP_TEXT" 4 | 5 | echo -n "$POPCLIP_TEXT"|pbcopy|pbpaste 6 | 7 | logger $? 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Brett's PopClip Extensions 2 | ================= 3 | 4 | My growing collection of [PopClip][popclip] extensions. 5 | 6 | ## Installation 7 | 8 | This repository only includes these as source bundles 9 | (`.popclipext`), not packaged `.popclipextz` versions. To 10 | install, just make sure the extension of a folder is 11 | `.popclipext` and double click it in Finder. An up-to-date 12 | package of the bundled versions is [available on my 13 | site](http://brettterpstra.com/projects/bretts-popclip-extensions). 14 | 15 | 16 | 17 | _Current release version: **1.45.4** 18 | ([source 19 | code](https://github.com/ttscoff/popclipextensions/releases/tag/1.44.8))_ 21 | 22 | > Many of these extensions have alternate behaviors when 23 | > holding modifier keys. Recent versions of PopClip override 24 | > these variations and provide specific actions when holding 25 | > modifiers, such as Shift to copy result and Option to 26 | > display the result in the bar. This means that the 27 | > variations in the plugins no longer function. A better 28 | > system may be available in the future, but for now, to 29 | > restore the modifier key functionality, you need to 30 | > disable the global interpretation of them. Open Terminal 31 | > and run this command: 32 | > 33 | > defaults write com.pilotmoon.popclip DisableAlternateActions -bool YES 34 | {:alert} 35 | 36 | ## Extensions 37 | 38 | The extensions currently included in the bundle. Some are 39 | available elsewhere as well, but this collection will always 40 | be the most up-to-date versions. 41 | 42 | 43 | ### Blockquote 44 | 45 | Turn indented text (or any text) into nested Markdown blockquotes. 46 | 47 | * Clicking adds a ">" for each indentation level in the selected text 48 | * Command-click to decrease quote level 49 | * Command-Option-click key to remove all quoting 50 | 51 | When adding quote levels, multiple line breaks between lines creates separate block quotes (by design). If there's a single blank line between to paragraphs, they'll be joined together as paragraphs within a blockquote. More than one starts a new quote. 52 | 53 | 54 | ### BulletList 55 | 56 | PopClip extension to turn lines of text into Markdown bullet items. Indentation is handled as nested lists and existing markers are overwritten (numbered list becomes bullet list). 57 | 58 | #### Numbered lists 59 | 60 | Holding Option (⌥) while clicking the button for the extension in the PopClip bar will create/update a numbered list instead. When the list is already a numbered list, it will be re-numbered to fix any gaps or out-of-order numbering within nest levels. 61 | 62 | #### Clear list formatting 63 | 64 | Holding Command (⌘) while clicking will remove all list prefixes. 65 | 66 | #### Bullet format 67 | 68 | When you install this extension, you'll get an options page where you can select the type of bullet you prefer for unordered lists. This can be accessed again later by clicking the pencil button at the bottom of the list, then clicking the gear button next to the BulletList extension. 69 | 70 | 71 | ### CheckURLs 72 | 73 | PopClip extension to show a popup preview for each URL in selected text. Used for confirming the output of scripts like SearchLink without switching to the browser. 74 | 75 | Links are shown sequentially in the order they're found. If a URL is changed by following links in the preview and pressing "OK", the selected text will be updated with the final URL. Because of this, duplicate links in the text are all previewed so they can be modified individually. 76 | 77 | 78 | ### Code 79 | 80 | Turn selected text into Markdown inline code or a code block. This extension "toggles," so if the selection already contains code syntax (inline code or fenced code block) the syntax is removed. 81 | 82 | Detects whether there are multiple lines: 83 | 84 | * if not, it surrounds the input with single backticks 85 | * if so, it wraps the block in triple backticks (fenced) 86 | 87 | When creating an inline code block, it will also detect whitespace at the beginning and end of the selection and make sure that it's excluded from the surrounding backticks. 88 | 89 | 90 | ### Comment 91 | 92 | Turn selected text into an HTML or code comment. 93 | 94 | By default, it surrounds selected text with `` style comment tags. Hold various modifier keys to insert other types of comment markers: 95 | 96 | * **Option**: CSS Comment (`/* block of text */`) 97 | * **Command**: Hash Comment (`# before each line`) 98 | * **Command-Option**: Slash comment (`// before each line`) 99 | 100 | 101 | ### CopyCleanLinks 102 | 103 | PopClip extension to lengthen and clean URLs. Duplicate of LinkCleaner, but only copies results to the clipboard. 104 | 105 | Option: clean all query strings (default: only clean Google UTM strings) 106 | Command: Output just the resulting URL(s) 107 | Command-Option: Output just URL(s) with query strings stripped 108 | 109 | 110 | ### CopyPLUS 111 | 112 | PopClip extension to append the selection to the current contents in the clipboard. *This is a duplicate of an existing extension (Append) with just slightly better UTF-8 handling, and modifier key handling for copying with and without linebreaks and whitespace.* 113 | 114 | * Hold Command (⌘) when clicking to add an extra line break between entries. 115 | * Hold Option (⌥) to append with no extra whitespace. 116 | 117 | 118 | ### CopyURLS 119 | 120 | PopClip extension to copy just the URLS in selection. 121 | 122 | Duplicate of OpenURLS, but copies urls to the clipboard, one link per line, instead of opening in browser. 123 | 124 | 125 | ### CriticMarkup 126 | 127 | Allows the quick insertion of [CriticMarkup][] syntax. Optionally fill in a signature to have a comment included after every insert, deletion or change with your initials or name. 128 | 129 | - No modifier: Highlight 130 | - **Command**: Deletion 131 | - **Control**: Insertion 132 | - **Control-Option**: Change 133 | - **Option**: Comment 134 | 135 | [CriticMarkup]: http://criticmarkup.com/spec.php 136 | 137 | There _is_ a PopClip extension for CriticMarkup in the main download package, which I didn't realize when I whipped this one up. I may defer to that one eventually, but I'll wait until I figure out if mine adds anything worthwhile or not. 138 | 139 | 140 | ### DefineAbbr 141 | 142 | PopClip extension to search textingabbreviations.ca for the selected string. 143 | 144 | 145 | ### Editor 146 | 147 | Extension for adding HTML editor marks to text. 148 | 149 | - No modifier: `` (highlight) 150 | - **Control**: `` (insertion) 151 | - **Command**: `` (deletion) 152 | - **Option**: `` (comment) 153 | 154 | 155 | ### FixPoorlyObscuredEmails 156 | 157 | Fixes emails obscured in a "support AT mydomain DOT com" fashion. 158 | 159 | Hold Option to also open an email window for each matched address. This feature does not require edit capability in the current field. 160 | 161 | 162 | ### HardWrap 163 | 164 | Add hard wrapping to paragraphs. Default wrap column is 80, hold down Option to wrap at an alternate column (modify both in the extension options). Hold down command to unwrap text, removing line breaks between lines but preserving multiple lines between paragraphs. 165 | 166 | * Clicking wraps at ruler, default 80 characters 167 | * Option-click to wrap to alternate width 168 | * Command-click to unwrap text 169 | 170 | 171 | 172 | ### Increment Templated 173 | 174 | PopClip extension to increment and repeat templated text. 175 | 176 | Select and run on the following text: 177 | 178 | ``` 179 | This is a numeric increment ##0..2##. 180 | ``` 181 | 182 | Which will generate: 183 | 184 | ``` 185 | This is a numeric increment 0. 186 | This is a numeric increment 1. 187 | ``` 188 | 189 | Specify a value to increment by with `##START..INCREMENT..END##`, e.g. `##0..2..10##` would insert 0, 2, 4, 6, 8, and 10. 190 | 191 | ![Increment Templated](https://raw.githubusercontent.com/ttscoff/popclipextensions/master/increment.gif) 192 | 193 | #### Placeholders 194 | 195 | You can use placeholders with basic math modification. `##x##` inserts the current element again. `##i##` inserts the 0-based index in the iteration. So if the template is `##5..7##`, on the second iteration `x` would hold `6` and `i` would hold `1`. 196 | 197 | Apply math functions to the placeholders using basic operator symbols (including `%` for mod). To insert the current value times 10, use `##x*10##`. More complex equations are allowed, e.g. `##(i+2)*10##`. Use `%` for modulus. 198 | 199 | You can include leading zeroes on math operations to pad the result. If you want to just pad the number without modifying, you would use `##x*0001##`, which would turn `5` into `0005` and `50` into `0050`. Including a 0 padding on any element of the equation will result in padded output. 200 | 201 | 202 | #### String Arrays 203 | 204 | You can also use arrays of strings or numbers: 205 | 206 | ``` 207 | Hello ##mother,father,sister,brother##. And repeat with ##x##. 208 | ``` 209 | 210 | Yields: 211 | 212 | ``` 213 | Hello mother. And repeat with mother. 214 | Hello father. And repeat with father. 215 | Hello sister. And repeat with sister. 216 | Hello brother. And repeat with brother. 217 | ``` 218 | 219 | The `##i##` placeholder (zero-based index) with math operators is also available in string array replacements. If you want the index to also refer to strings, add `#list,of,strings` after the index or equation, e.g. `##i%2#odd,even##` to insert `odd` and `even` alternately with each iteration. 220 | 221 | Example: 222 | 223 | ``` 224 | .element-##one,two,three## { 225 | text-indent: ##i*10##px; 226 | } 227 | ``` 228 | 229 | ``` 230 | .element-one { 231 | text-indent: 0px; 232 | } 233 | .element-two { 234 | text-indent: 10px; 235 | } 236 | .element-three { 237 | text-indent: 20px; 238 | } 239 | ``` 240 | 241 | 242 | ### LinkCleaner 243 | 244 | PopClip extension to lengthen and clean URLs. 245 | 246 | Use extension settings to determine whether it strips Google Analytics strings only, or _all_ query strings. 247 | 248 | - Option: force clean all query strings, ignore settings 249 | - Command: Output just the resulting URL(s) 250 | - Command-Option: Output just URL(s) with all query strings stripped 251 | 252 | 253 | ### Markdown to Mindmap 254 | 255 | Takes a selection of plain text containing markdown headlines, list items and paragraphs and converts it into a format ready for pasting into a mind mapping application (such as MindNode, MindManager or MindMeister) as separate nodes/topics. 256 | 257 | 258 | ### Markdownify 259 | 260 | Turn HTML text into Markdown using html2text. 261 | 262 | 263 | ### NumberedList 264 | 265 | PopClip extension to turn lines of text into Markdown numbered items. Will sort and update an existing numbered list as well, and convert bullets on list items to numbers. 266 | 267 | This is only here if you want a separate button for numbered lists. Otherwise you can just use BulletList and hold down option to create an ordered list instead. 268 | 269 | 270 | ### nvUltra 271 | 272 | [nvUltra](https://nvultra.com) extension for PopClip. Add text as new note to frontmost notebook, or define a notebook in settings. 273 | 274 | #### Credits 275 | 276 | Originally created by Marc Abramowitz - see [https://github.com/msabramo/nvALT.popclipext](https://github.com/msabramo/nvALT.popclipext). Icon and minor modifications by Nick Moore. 277 | 278 | 279 | ### OpenURLS 280 | 281 | PopClip extension to open all URLS in selection. 282 | 283 | 284 | ### Outdent 285 | 286 | Fully outdents the selection, maintaining nested indentation. 287 | 288 | 289 | ### PoorText 290 | 291 | Make rich text go broke. 292 | 293 | Strips rich text formatting from selection. There are probably multiple others that do this, but it's so easy I just made it myself. 294 | 295 | 296 | ### BulletList 297 | 298 | PopClip extension to turn lines of text into Markdown bullet items. Indentation is handled as nested lists and existing markers are overwritten (numbered list becomes bullet list). 299 | 300 | #### Numbered lists 301 | 302 | Holding Option (⌥) while clicking the button for the extension in the PopClip bar will create/update a numbered list instead. When the list is already a numbered list, it will be re-numbered to fix any gaps or out-of-order numbering within nest levels. 303 | 304 | #### Clear list formatting 305 | 306 | Holding Command (⌘) while clicking will remove all list prefixes. 307 | 308 | #### Bullet format 309 | 310 | When you install this extension, you'll get an options page where you can select the type of bullet you prefer for unordered lists. This can be accessed again later by clicking the pencil button at the bottom of the list, then clicking the gear button next to the BulletList extension. 311 | 312 | 313 | ### SkypeCall 314 | 315 | PopClip extension to call a number with Skype. 316 | 317 | 318 | ### Slugify 319 | 320 | Turn selected text into a valid post slug, lowercasing, deleting non-alphanumeric characters, and replacing spaces with hyphens. 321 | 322 | ### Sum 323 | 324 | Detect all numbers in selection and total them. Allows decimal places (using `.` or `,` as separator) and negative numbers. Result is copied to clipboard. 325 | 326 | Use the options "Separator" and "Decimal Delimiter" to define characters used in your locale for separating thousands and decimal places, respectively. 327 | 328 | 329 | ### Twitterify 330 | 331 | Convert all @names and #tags to Markdown or HTML links. You can set the default link type in the extension's options, and manually switch to the other type by holding down Option when running it. 332 | 333 | 334 | ### URLEncode 335 | 336 | Just URL encodes (percent encoding) the selected text using the Ruby URI gem. 337 | 338 | *Also available at [Pilot Moon](http://pilotmoon.com/popclip/extensions/page/URLEncode), same extension.* 339 | 340 | 341 | ### WebMarkdown 342 | 343 | Also known as WebMD, this extension shows up when you select text on a web page. Clicking it will convert the selected headlines, text and links (including image links) to Markdown in your clipboard. 344 | 345 | This extension uses [Gather](https://brettterpstra.com/projects/gather-cli) to markdownify the selection. If you don't have the `gather` CLI installed, WebMarkdown will offer to download and install it for you the first time you run it. 346 | 347 | 348 | ### Too Many Wrappers 349 | 350 | [Get it?](https://www.youtube.com/watch?v=HNB8pNqwrKw) 351 | 352 | Allows the definition of three custom "wrappers," prefixes and suffixes that will surround selected text. They're triggered, respectively, by clicking with the Option key, Command key or no modifier key held down. 353 | 354 | Think of it as a custom version of the comments plugin. I find it quite handy for adding ``, `` and `` tags to text when editing for others. 355 | 356 | When installing the extension, the options will appear. They can be accessed again by going into edit mode in the plugins dropdown and clicking the gear icon next to "Wrappers." 357 | 358 | 359 | ## Download 360 | 361 | 362 | 363 | The GitHub repository for all of my extensions is 364 | [here][github]. 365 | 366 | ## Changelog 367 | 368 | 369 | 370 | 371 | See [the changelog on 372 | GitHub](https://github.com/ttscoff/popclipextensions/blob/master/CHANGELOG.md) 373 | 374 | 375 | [popclip]: http://pilotmoon.com/popclip/ 376 | [github]: https://github.com/ttscoff/popclipextensions 377 | 378 | -------------------------------------------------------------------------------- /SearchLink.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | searchlink.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | searchlink.rb 14 | Title 15 | SearchLink 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com/projects/searchlink 30 | 31 | Extension Description 32 | Run SearchLink on selected text for inline searching while writing. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.searchlink 35 | Extension Name 36 | SearchLink 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /SearchLink.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### BulletList 2 | 3 | PopClip extension to turn lines of text into Markdown bullet items. Indentation is handled as nested lists and existing markers are overwritten (numbered list becomes bullet list). 4 | 5 | #### Numbered lists 6 | 7 | Holding Option (⌥) while clicking the button for the extension in the PopClip bar will create/update a numbered list instead. When the list is already a numbered list, it will be re-numbered to fix any gaps or out-of-order numbering within nest levels. 8 | 9 | #### Clear list formatting 10 | 11 | Holding Command (⌘) while clicking will remove all list prefixes. 12 | 13 | #### Bullet format 14 | 15 | When you install this extension, you'll get an options page where you can select the type of bullet you prefer for unordered lists. This can be accessed again later by clicking the pencil button at the bottom of the list, then clicking the gear button next to the BulletList extension. 16 | -------------------------------------------------------------------------------- /SearchLink.popclipext/searchlink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/SearchLink.popclipext/searchlink.png -------------------------------------------------------------------------------- /SearchLink.popclipext/searchlink.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'shellwords' 5 | 6 | input = ENV['POPCLIP_TEXT'] 7 | 8 | def install_searchlink 9 | user = `whoami`.strip 10 | unless File.exist?(File.expand_path("/Users/#{user}/Library/Services/SearchLink.workflow")) 11 | folder = File.expand_path("/Users/#{user}/Downloads") 12 | services = File.expand_path("/Users/#{user}/Library/Services") 13 | dl = File.join(folder, 'SearchLink.zip') 14 | `curl -SsL -o "#{dl}" https://github.com/ttscoff/searchlink/releases/latest/download/SearchLink.zip` 15 | Dir.chdir(folder) 16 | `unzip -qo #{dl} -d #{folder}` 17 | FileUtils.rm(dl) 18 | 19 | ['SearchLink.workflow', 'SearchLink File.workflow', 'Jump to SearchLink Error.workflow'].each do |wflow| 20 | src = File.join(folder, 'SearchLink Services', wflow) 21 | dest = File.join(services, wflow) 22 | FileUtils.rm_rf(dest) if File.exist?(dest) 23 | FileUtils.mv(src, dest, force: true) 24 | end 25 | FileUtils.rm_rf('SearchLink Services') 26 | end 27 | end 28 | 29 | install_searchlink 30 | user = `whoami`.strip 31 | res = `echo #{Shellwords.escape(input)} | automator -i - /Users/#{user}/Library/Services/SearchLink.workflow`.strip 32 | 33 | res.gsub!(/'/, "\\\\'") 34 | res.gsub!(/^\(/, '[') 35 | res.gsub!(/\)$/, ']') 36 | res.gsub!(/^ "/, "'") 37 | res.gsub!(/",? *$/, "',") 38 | 39 | data = eval(res) 40 | 41 | print data.join("\n") 42 | -------------------------------------------------------------------------------- /SkypeCall.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | skypecall.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | skypecall.rb 14 | Title 15 | SkypeCall 16 | Regular Expression 17 | (?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))? 18 | 19 | 20 | Credits 21 | 22 | Name 23 | Brett Terpstra 24 | Link 25 | http://brettterpstra.com 26 | 27 | Extension Description 28 | Call the first phone number in selection with Skype. 29 | Extension Identifier 30 | com.brettterpstra.popclip.extension.skypecall 31 | Extension Name 32 | SkypeCall 33 | Version 34 | 2 35 | 36 | 37 | -------------------------------------------------------------------------------- /SkypeCall.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### SkypeCall 2 | 3 | PopClip extension to call a number with Skype. 4 | -------------------------------------------------------------------------------- /SkypeCall.popclipext/skypecall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/SkypeCall.popclipext/skypecall.png -------------------------------------------------------------------------------- /SkypeCall.popclipext/skypecall.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | input = ENV['POPCLIP_TEXT'] 4 | # input = "This is a phone number 8075555486 and this 1 (807) 555-5487 and this 555-5488" 5 | 6 | phone_numbers = input.scan(/(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?/) 7 | %x{/usr/bin/osascript -e 'set _cmd to "CALL #{phone_numbers[0].join("")}"' -e 'tell application "Skype" to send command _cmd script name "PCDIALER"'} 8 | -------------------------------------------------------------------------------- /Slugify.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | hyphen.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | slugger.rb 14 | Title 15 | - 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Turn selected text into a valid post slug. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.slugify 35 | Extension Name 36 | Slugify 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /Slugify.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Slugify 2 | 3 | Turn selected text into a valid post slug, lowercasing, deleting non-alphanumeric characters, and replacing spaces with hyphens. -------------------------------------------------------------------------------- /Slugify.popclipext/hyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Slugify.popclipext/hyphen.png -------------------------------------------------------------------------------- /Slugify.popclipext/slugger.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | clip = ENV['POPCLIP_TEXT'] 4 | 5 | print clip.downcase 6 | .gsub(/\./, '-dot-') 7 | .gsub(/\+/, '-plus-') 8 | .gsub(/[^a-z0-9 \-.]/i, '') 9 | .gsub(/\s+/, '-') 10 | .gsub(/-+/, '-') 11 | .gsub(/^-/, '') 12 | .gsub(/(^-|-$)/, '') 13 | -------------------------------------------------------------------------------- /Sum.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | Sum 16 | Regular Expression 17 | (?s)(.*)?\d+(.*)? 18 | After 19 | preview-result 20 | 21 | 22 | Options 23 | 24 | 25 | Option Identifier 26 | separator 27 | Option Type 28 | string 29 | Option Label 30 | Separator 31 | Option Default Value 32 | , 33 | 34 | 35 | Option Identifier 36 | delimiter 37 | Option Type 38 | string 39 | Option Label 40 | Decimal Delimiter 41 | Option Default Value 42 | . 43 | 44 | 45 | Option Identifier 46 | formatoutput 47 | Option Type 48 | boolean 49 | Option Label 50 | Format Output 51 | Option Default Value 52 | 53 | 54 | 55 | Credits 56 | 57 | Name 58 | Brett Terpstra 59 | Link 60 | http://brettterpstra.com 61 | 62 | Extension Description 63 | Totals all numbers found in selection. 64 | Extension Identifier 65 | com.brettterpstra.popclip.extension.sum 66 | Extension Name 67 | Sum 68 | Version 69 | 2 70 | 71 | 72 | -------------------------------------------------------------------------------- /Sum.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Sum 2 | 3 | Detect all numbers in selection and total them. Allows decimal places (using `.` or `,` as separator) and negative numbers. Result is copied to clipboard. 4 | 5 | Use the options "Separator" and "Decimal Delimiter" to define characters used in your locale for separating thousands and decimal places, respectively. 6 | -------------------------------------------------------------------------------- /Sum.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Sum.popclipext/icon.png -------------------------------------------------------------------------------- /Sum.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'shellwords' 3 | 4 | # 1.0 5 | # 2014-04-09 6 | # 7 | # Sums all numbers found in selection 8 | 9 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 10 | decimal = ENV['POPCLIP_OPTION_DELIMITER'] 11 | separator = ENV['POPCLIP_OPTION_SEPARATOR'] 12 | 13 | def esc(char) 14 | return "\\#{char}" 15 | end 16 | 17 | def fmt( st, decimal, separator ) 18 | mynum = st.to_s.reverse.scan(/(?:\d*#{esc(decimal)})?\d{1,3}-?/).join(separator).reverse 19 | dec = mynum.split(decimal) 20 | mynum = dec[0].to_s + decimal + dec[1].to_s if dec[1] 21 | mynum 22 | end 23 | 24 | begin 25 | unless debug 26 | if RUBY_VERSION.to_f > 1.9 27 | Encoding.default_external = Encoding::UTF_8 28 | Encoding.default_internal = Encoding::UTF_8 29 | input = ENV['POPCLIP_TEXT'].dup.force_encoding('utf-8') 30 | else 31 | input = ENV['POPCLIP_TEXT'].dup 32 | end 33 | else 34 | input = STDIN.read 35 | end 36 | 37 | total = 0 38 | places = 0 39 | 40 | input.scan(/(\-?[\d#{esc(separator)}]+(#{esc(decimal)}\d+)?)\b/).each {|x| 41 | total += x[0].gsub(/#{esc(separator)}/,'').sub(/#{esc(decimal)}/,'.').to_f 42 | places = x[1].length - 1 if x[1] && x[1].length.to_i > places + 1 43 | } 44 | 45 | # minimum 2 decimal places if any 46 | places = 2 if places == 1 47 | 48 | out = "%.#{places.to_i}f" % total 49 | do_format = ENV['POPCLIP_OPTION_FORMATOUTPUT'].to_i == 1 ? true : false 50 | print do_format ? fmt(out.sub(/\./,decimal), decimal, separator) : out.sub(/\./,decimal) 51 | rescue Exception => e 52 | %x{logger #{Shellwords.escape(e.to_s)}} 53 | STDERR.puts e 54 | end 55 | -------------------------------------------------------------------------------- /Twitterify.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | icon.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | Twitterify 16 | Regular Expression 17 | (?si)(.*)?(?:\s|^)[@#]\w+(.*)? 18 | After 19 | paste-result 20 | Requirements 21 | 22 | paste 23 | 24 | 25 | 26 | Options 27 | 28 | 29 | Option Identifier 30 | usemarkdown 31 | Option Type 32 | boolean 33 | Option Label 34 | Markdown Links 35 | Option Default Value 36 | 37 | 38 | 39 | Credits 40 | 41 | Name 42 | Brett Terpstra 43 | Link 44 | http://brettterpstra.com 45 | 46 | Extension Description 47 | Converts @names and #hashtags to Twitter urls. 48 | Extension Identifier 49 | com.brettterpstra.popclip.extension.twitterify 50 | Extension Name 51 | Twitterify 52 | Version 53 | 2 54 | 55 | 56 | -------------------------------------------------------------------------------- /Twitterify.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Twitterify 2 | 3 | Convert all @names and #tags to Markdown or HTML links. You can set the default link type in the extension's options, and manually switch to the other type by holding down Option when running it. 4 | -------------------------------------------------------------------------------- /Twitterify.popclipext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Twitterify.popclipext/icon.png -------------------------------------------------------------------------------- /Twitterify.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'shellwords' 3 | 4 | debug = ARGV[0] =~ /(debug|-?d)/ ? true : false 5 | 6 | # Convert @ttscoff to 7 | # [@ttscoff](https://twitter.com/ttscoff) 8 | # Convert #hashtag to 9 | # [#hashtag](https://twitter.com/search?q=%23hashtag&src=hash) 10 | 11 | unless debug 12 | input = ENV['POPCLIP_TEXT'].dup 13 | else 14 | input =<#{match}" 32 | elsif match[0] == "#" 33 | markdown ? "#{$1}[\\#{match}](https://twitter.com/search?q=%23#{match[1..-1]}&src=hash)" : "#{$1}#{match}" 34 | else 35 | "#{$1}#{match}" 36 | end 37 | } 38 | print input 39 | rescue Exception => e 40 | %x{logger #{Shellwords.escape(e.to_s)}} 41 | STDERR.puts e 42 | end 43 | -------------------------------------------------------------------------------- /URLEncode.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Version 6 | 2 7 | Extension Description 8 | Percent encode selected text. 9 | Extension Name 10 | URLEncode 11 | Extension Identifier 12 | com.brettterpstra.popclip.extension.urlencode 13 | Actions 14 | 15 | 16 | Shell Script File 17 | urlencode.rb 18 | Script Interpreter 19 | /usr/bin/env ruby 20 | Title 21 | % 22 | After 23 | paste-result 24 | Requirements 25 | 26 | paste 27 | 28 | 29 | 30 | Credits 31 | 32 | Name 33 | Brett Terpstra 34 | Link 35 | http://brettterpstra.com 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /URLEncode.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### URLEncode 2 | 3 | Just URL encodes (percent encoding) the selected text using the Ruby URI gem. 4 | 5 | *Also available at [Pilot Moon](http://pilotmoon.com/popclip/extensions/page/URLEncode), same extension.* 6 | -------------------------------------------------------------------------------- /URLEncode.popclipext/urlencode.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'uri' 4 | 5 | print URI.encode(ENV['POPCLIP_TEXT']) 6 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.44 2 | -------------------------------------------------------------------------------- /WebMarkdown.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Script Interpreter 9 | /bin/bash 10 | Shell Script File 11 | process.sh 12 | Title 13 | WebMD 14 | Pass HTML 15 | 16 | After 17 | copy-result 18 | 19 | 20 | Requirements 21 | 22 | html 23 | 24 | Credits 25 | 26 | Name 27 | Brett Terpstra 28 | Link 29 | http://brettterpstra.com 30 | 31 | Extension Description 32 | Converts text selected in a browser to Markdown in the clipboard. 33 | Extension Identifier 34 | com.brettterpstra.popclip.extension.webmarkdown 35 | Extension Name 36 | WebMarkdown 37 | Version 38 | 2 39 | 40 | 41 | -------------------------------------------------------------------------------- /WebMarkdown.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### WebMarkdown 2 | 3 | Also known as WebMD, this extension shows up when you select text on a web page. Clicking it will convert the selected headlines, text and links (including image links) to Markdown in your clipboard. 4 | 5 | This extension uses [Gather](https://brettterpstra.com/projects/gather-cli) to markdownify the selection. If you don't have the `gather` CLI installed, WebMarkdown will offer to download and install it for you the first time you run it. 6 | -------------------------------------------------------------------------------- /WebMarkdown.popclipext/download.applescript: -------------------------------------------------------------------------------- 1 | tell application "PopClip" 2 | activate 3 | set _res to display dialog "This extension requires gather-cli, would you like to install it now?" buttons {"Later", "Manual Install", "Automatic Install"} default button "Automatic Install" 4 | if button returned of _res is "Automatic Install" then 5 | set _res to display dialog "A package will be downloaded and you'll be presented an install dialog in a moment." buttons {"Cancel", "OK"} default button "OK" 6 | if button returned of _res is "OK" then 7 | do shell script "curl -SsL --output-dir /tmp -O https://cdn3.brettterpstra.com/downloads/gather-cli-latest.pkg && open -W /tmp/gather-cli-latest.pkg" 8 | display dialog "If all went well, you can now use WebMarkdown. If you ran into any trouble, run WebMarkdown again and choose Manual Install." buttons {"OK"} default button 1 9 | end if 10 | else if button returned of _res is "Manual Install" then 11 | display dialog "Your browser will now be directed to the download page. Please follow the install instructions there" buttons {"OK"} default button 1 12 | open location "https://brettterpstra.com/projects/gather-cli/" 13 | else 14 | display dialog "You won't be able to use WebMarkdown until you install the CLI." buttons {"Got it"} default button 1 15 | end if 16 | end tell 17 | -------------------------------------------------------------------------------- /WebMarkdown.popclipext/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | GATHER=/usr/local/bin/gather 4 | if [[ ! -e $GATHER ]]; then 5 | GATHER=/opt/homebrew/bin/gather 6 | if [[ ! -e $GATHER ]]; then 7 | osascript download.applescript 8 | exit 1 9 | fi 10 | fi 11 | 12 | $GATHER --env POPCLIP_HTML --no-readability --html 13 | -------------------------------------------------------------------------------- /Wrappers.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | wrapped.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | script.rb 14 | Title 15 | wrap 16 | After 17 | paste-result 18 | Requirements 19 | 20 | paste 21 | 22 | 23 | 24 | Options 25 | 26 | 27 | Option Identifier 28 | popmakerprefix 29 | Option Type 30 | string 31 | Option Label 32 | Prefix 33 | 34 | 35 | Option Identifier 36 | popmakersuffix 37 | Option Type 38 | string 39 | Option Label 40 | Suffix 41 | 42 | 43 | Option Identifier 44 | popmakeroptprefix 45 | Option Type 46 | string 47 | Option Label 48 | ⌥ Prefix 49 | 50 | 51 | Option Identifier 52 | popmakeroptsuffix 53 | Option Type 54 | string 55 | Option Label 56 | ⌥ Suffix 57 | 58 | 59 | Option Identifier 60 | popmakercmdprefix 61 | Option Type 62 | string 63 | Option Label 64 | ⌘ Prefix 65 | 66 | 67 | Option Identifier 68 | popmakercmdsuffix 69 | Option Type 70 | string 71 | Option Label 72 | ⌘ Suffix 73 | 74 | 75 | Credits 76 | 77 | Name 78 | Brett Terpstra 79 | Link 80 | http://brettterpstra.com 81 | 82 | Extension Description 83 | Too many wrappers 84 | Extension Identifier 85 | com.brettterpstra.popclip.extension.wrapper 86 | Extension Name 87 | Wrappers 88 | Version 89 | 2 90 | 91 | 92 | -------------------------------------------------------------------------------- /Wrappers.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Too Many Wrappers 2 | 3 | [Get it?](https://www.youtube.com/watch?v=HNB8pNqwrKw) 4 | 5 | Allows the definition of three custom "wrappers," prefixes and suffixes that will surround selected text. They're triggered, respectively, by clicking with the Option key, Command key or no modifier key held down. 6 | 7 | Think of it as a custom version of the comments plugin. I find it quite handy for adding ``, `` and `` tags to text when editing for others. 8 | 9 | When installing the extension, the options will appear. They can be accessed again by going into edit mode in the plugins dropdown and clicking the gear icon next to "Wrappers." 10 | -------------------------------------------------------------------------------- /Wrappers.popclipext/script.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | prefix = ENV['POPCLIP_OPTION_POPMAKERPREFIX'] 4 | suffix = ENV['POPCLIP_OPTION_POPMAKERSUFFIX'] 5 | optprefix = ENV['POPCLIP_OPTION_POPMAKEROPTPREFIX']# == "" ? prefix : ENV['POPCLIP_OPTION_POPMAKEROPTPREFIX'] 6 | optsuffix = ENV['POPCLIP_OPTION_POPMAKEROPTSUFFIX']# == "" ? suffix : ENV['POPCLIP_OPTION_POPMAKEROPTSUFFIX'] 7 | cmdprefix = ENV['POPCLIP_OPTION_POPMAKERCMDPREFIX']# == "" ? prefix : ENV['POPCLIP_OPTION_POPMAKERCMDPREFIX'] 8 | cmdsuffix = ENV['POPCLIP_OPTION_POPMAKERCMDSUFFIX']# == "" ? suffix : ENV['POPCLIP_OPTION_POPMAKERCMDSUFFIX'] 9 | ## Shift key is causing weirdness 10 | # shiftprefix = ENV['POPCLIP_OPTION_POPMAKERSHIFTPREFIX'] == "" ? prefix : ENV['POPCLIP_OPTION_POPMAKERSHIFTPREFIX'] 11 | # shiftsuffix = ENV['POPCLIP_OPTION_POPMAKERSHIFTSUFFIX'] == "" ? suffix : ENV['POPCLIP_OPTION_POPMAKERSHIFTSUFFIX'] 12 | input = ENV['POPCLIP_TEXT'] 13 | 14 | # fixes = %w{prefix suffix optprefix optsuffix cmdprefix cmdsuffix shiftprefix shiftsuffix} 15 | 16 | # fixes.each {|var| 17 | # eval("#{var} ||= #{var} =~ /prefix/ ? prefix : suffix" 18 | # } 19 | 20 | space = input.match(/^([\s\n]*)\S.*?([\s\n]*)$/m) 21 | case ENV['POPCLIP_MODIFIER_FLAGS'].to_i 22 | when 1048576 # Command 23 | print "#{space[1]}#{cmdprefix}#{input.strip}#{cmdsuffix}#{space[2]}" 24 | when 524288 # Option 25 | print "#{space[1]}#{optprefix}#{input.strip}#{optsuffix}#{space[2]}" 26 | # when 131072 # Shift 27 | # print "#{space[1]}#{shiftprefix}#{input.strip}#{shiftsuffix}#{space[2]}" 28 | else # none 29 | print "#{space[1]}#{prefix}#{input.strip}#{suffix}#{space[2]}" 30 | end 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Wrappers.popclipext/wrapped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/Wrappers.popclipext/wrapped.png -------------------------------------------------------------------------------- /increment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/increment.gif -------------------------------------------------------------------------------- /markdownify.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Version 6 | 2 7 | Extension Name 8 | Markdownify 9 | Extension Identifier 10 | com.brettterpstra.popclip.extension.markdownify 11 | Actions 12 | 13 | 14 | Shell Script File 15 | markdownify.py 16 | Script Interpreter 17 | /usr/bin/python 18 | Title 19 | 2MD 20 | After 21 | paste-result 22 | Requirements 23 | 24 | paste 25 | 26 | 27 | 28 | Credits 29 | 30 | Name 31 | Brett Terpstra 32 | Link 33 | http://brettterpstra.com 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /markdownify.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### Markdownify 2 | 3 | Turn HTML text into Markdown using html2text. 4 | -------------------------------------------------------------------------------- /markdownify.popclipext/markdownify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """html2text: Turn HTML into equivalent Markdown-structured text.""" 3 | __version__ = "3.200.3" 4 | __author__ = "Aaron Swartz (me@aaronsw.com)" 5 | __copyright__ = "(C) 2004-2008 Aaron Swartz. GNU GPL 3." 6 | __contributors__ = ["Martin 'Joey' Schulze", "Ricardo Reyes", "Kevin Jay North"] 7 | 8 | # TODO: 9 | # Support decoded entities with unifiable. 10 | import os 11 | 12 | try: 13 | True 14 | except NameError: 15 | setattr(__builtins__, 'True', 1) 16 | setattr(__builtins__, 'False', 0) 17 | 18 | def has_key(x, y): 19 | if hasattr(x, 'has_key'): return x.has_key(y) 20 | else: return y in x 21 | 22 | try: 23 | import htmlentitydefs 24 | import urlparse 25 | import HTMLParser 26 | except ImportError: #Python3 27 | import html.entities as htmlentitydefs 28 | import urllib.parse as urlparse 29 | import html.parser as HTMLParser 30 | try: #Python3 31 | import urllib.request as urllib 32 | except: 33 | import urllib 34 | import optparse, re, sys, codecs, types 35 | 36 | try: from textwrap import wrap 37 | except: pass 38 | 39 | # Use Unicode characters instead of their ascii psuedo-replacements 40 | UNICODE_SNOB = 0 41 | 42 | # Put the links after each paragraph instead of at the end. 43 | LINKS_EACH_PARAGRAPH = 0 44 | 45 | # Wrap long lines at position. 0 for no wrapping. (Requires Python 2.3.) 46 | BODY_WIDTH = 0 47 | 48 | # Don't show internal links (href="#local-anchor") -- corresponding link targets 49 | # won't be visible in the plain text file anyway. 50 | SKIP_INTERNAL_LINKS = True 51 | 52 | # Use inline, rather than reference, formatting for images and links 53 | INLINE_LINKS = False 54 | 55 | # Number of pixels Google indents nested lists 56 | GOOGLE_LIST_INDENT = 36 57 | 58 | IGNORE_ANCHORS = False 59 | IGNORE_IMAGES = False 60 | IGNORE_EMPHASIS = False 61 | 62 | ### Entity Nonsense ### 63 | 64 | def name2cp(k): 65 | if k == 'apos': return ord("'") 66 | if hasattr(htmlentitydefs, "name2codepoint"): # requires Python 2.3 67 | return htmlentitydefs.name2codepoint[k] 68 | else: 69 | k = htmlentitydefs.entitydefs[k] 70 | if k.startswith("&#") and k.endswith(";"): return int(k[2:-1]) # not in latin-1 71 | return ord(codecs.latin_1_decode(k)[0]) 72 | 73 | unifiable = {'rsquo':"'", 'lsquo':"'", 'rdquo':'"', 'ldquo':'"', 74 | 'copy':'(C)', 'mdash':'--', 'nbsp':' ', 'rarr':'->', 'larr':'<-', 'middot':'*', 75 | 'ndash':'-', 'oelig':'oe', 'aelig':'ae', 76 | 'agrave':'a', 'aacute':'a', 'acirc':'a', 'atilde':'a', 'auml':'a', 'aring':'a', 77 | 'egrave':'e', 'eacute':'e', 'ecirc':'e', 'euml':'e', 78 | 'igrave':'i', 'iacute':'i', 'icirc':'i', 'iuml':'i', 79 | 'ograve':'o', 'oacute':'o', 'ocirc':'o', 'otilde':'o', 'ouml':'o', 80 | 'ugrave':'u', 'uacute':'u', 'ucirc':'u', 'uuml':'u', 81 | 'lrm':'', 'rlm':''} 82 | 83 | unifiable_n = {} 84 | 85 | for k in unifiable.keys(): 86 | unifiable_n[name2cp(k)] = unifiable[k] 87 | 88 | ### End Entity Nonsense ### 89 | 90 | def onlywhite(line): 91 | """Return true if the line does only consist of whitespace characters.""" 92 | for c in line: 93 | if c is not ' ' and c is not ' ': 94 | return c is ' ' 95 | return line 96 | 97 | def hn(tag): 98 | if tag[0] == 'h' and len(tag) == 2: 99 | try: 100 | n = int(tag[1]) 101 | if n in range(1, 10): return n 102 | except ValueError: return 0 103 | 104 | def dumb_property_dict(style): 105 | """returns a hash of css attributes""" 106 | return dict([(x.strip(), y.strip()) for x, y in [z.split(':', 1) for z in style.split(';') if ':' in z]]); 107 | 108 | def dumb_css_parser(data): 109 | """returns a hash of css selectors, each of which contains a hash of css attributes""" 110 | # remove @import sentences 111 | importIndex = data.find('@import') 112 | while importIndex != -1: 113 | data = data[0:importIndex] + data[data.find(';', importIndex) + 1:] 114 | importIndex = data.find('@import') 115 | 116 | # parse the css. reverted from dictionary compehension in order to support older pythons 117 | elements = [x.split('{') for x in data.split('}') if '{' in x.strip()] 118 | try: 119 | elements = dict([(a.strip(), dumb_property_dict(b)) for a, b in elements]) 120 | except ValueError: 121 | elements = {} # not that important 122 | 123 | return elements 124 | 125 | def element_style(attrs, style_def, parent_style): 126 | """returns a hash of the 'final' style attributes of the element""" 127 | style = parent_style.copy() 128 | if 'class' in attrs: 129 | for css_class in attrs['class'].split(): 130 | css_style = style_def['.' + css_class] 131 | style.update(css_style) 132 | if 'style' in attrs: 133 | immediate_style = dumb_property_dict(attrs['style']) 134 | style.update(immediate_style) 135 | return style 136 | 137 | def google_list_style(style): 138 | """finds out whether this is an ordered or unordered list""" 139 | if 'list-style-type' in style: 140 | list_style = style['list-style-type'] 141 | if list_style in ['disc', 'circle', 'square', 'none']: 142 | return 'ul' 143 | return 'ol' 144 | 145 | def google_has_height(style): 146 | """check if the style of the element has the 'height' attribute explicitly defined""" 147 | if 'height' in style: 148 | return True 149 | return False 150 | 151 | def google_text_emphasis(style): 152 | """return a list of all emphasis modifiers of the element""" 153 | emphasis = [] 154 | if 'text-decoration' in style: 155 | emphasis.append(style['text-decoration']) 156 | if 'font-style' in style: 157 | emphasis.append(style['font-style']) 158 | if 'font-weight' in style: 159 | emphasis.append(style['font-weight']) 160 | return emphasis 161 | 162 | def google_fixed_width_font(style): 163 | """check if the css of the current element defines a fixed width font""" 164 | font_family = '' 165 | if 'font-family' in style: 166 | font_family = style['font-family'] 167 | if 'Courier New' == font_family or 'Consolas' == font_family: 168 | return True 169 | return False 170 | 171 | def list_numbering_start(attrs): 172 | """extract numbering from list element attributes""" 173 | if 'start' in attrs: 174 | return int(attrs['start']) - 1 175 | else: 176 | return 0 177 | 178 | class HTML2Text(HTMLParser.HTMLParser): 179 | def __init__(self, out=None, baseurl=''): 180 | HTMLParser.HTMLParser.__init__(self) 181 | 182 | # Config options 183 | self.unicode_snob = UNICODE_SNOB 184 | self.links_each_paragraph = LINKS_EACH_PARAGRAPH 185 | self.body_width = BODY_WIDTH 186 | self.skip_internal_links = SKIP_INTERNAL_LINKS 187 | self.inline_links = INLINE_LINKS 188 | self.google_list_indent = GOOGLE_LIST_INDENT 189 | self.ignore_links = IGNORE_ANCHORS 190 | self.ignore_images = IGNORE_IMAGES 191 | self.ignore_emphasis = IGNORE_EMPHASIS 192 | self.google_doc = False 193 | self.ul_item_mark = '*' 194 | 195 | if out is None: self.out = self.outtextf 196 | else: self.out = out 197 | self.outtextlist = [] # empty list to store output characters before they are "joined" 198 | try: 199 | self.outtext = unicode() 200 | except NameError: # Python3 201 | self.outtext = str() 202 | self.quiet = 0 203 | self.p_p = 0 # number of newline character to print before next output 204 | self.outcount = 0 205 | self.start = 1 206 | self.space = 0 207 | self.a = [] 208 | self.astack = [] 209 | self.acount = 0 210 | self.list = [] 211 | self.blockquote = 0 212 | self.pre = 0 213 | self.startpre = 0 214 | self.code = False 215 | self.br_toggle = '' 216 | self.lastWasNL = 0 217 | self.lastWasList = False 218 | self.style = 0 219 | self.style_def = {} 220 | self.tag_stack = [] 221 | self.emphasis = 0 222 | self.drop_white_space = 0 223 | self.inheader = False 224 | self.abbr_title = None # current abbreviation definition 225 | self.abbr_data = None # last inner HTML (for abbr being defined) 226 | self.abbr_list = {} # stack of abbreviations to write later 227 | self.baseurl = baseurl 228 | 229 | try: del unifiable_n[name2cp('nbsp')] 230 | except KeyError: pass 231 | unifiable['nbsp'] = ' _place_holder;' 232 | 233 | 234 | def feed(self, data): 235 | data = data.replace("", "") 236 | HTMLParser.HTMLParser.feed(self, data) 237 | 238 | def handle(self, data): 239 | self.feed(data) 240 | self.feed("") 241 | return self.optwrap(self.close()) 242 | 243 | def outtextf(self, s): 244 | self.outtextlist.append(s) 245 | if s: self.lastWasNL = s[-1] == '\n' 246 | 247 | def close(self): 248 | HTMLParser.HTMLParser.close(self) 249 | 250 | self.pbr() 251 | self.o('', 0, 'end') 252 | 253 | self.outtext = self.outtext.join(self.outtextlist) 254 | 255 | if self.google_doc: 256 | self.outtext = self.outtext.replace(' _place_holder;', ' '); 257 | 258 | return self.outtext 259 | 260 | def handle_charref(self, c): 261 | self.o(self.charref(c), 1) 262 | 263 | def handle_entityref(self, c): 264 | self.o(self.entityref(c), 1) 265 | 266 | def handle_starttag(self, tag, attrs): 267 | self.handle_tag(tag, attrs, 1) 268 | 269 | def handle_endtag(self, tag): 270 | self.handle_tag(tag, None, 0) 271 | 272 | def previousIndex(self, attrs): 273 | """ returns the index of certain set of attributes (of a link) in the 274 | self.a list 275 | 276 | If the set of attributes is not found, returns None 277 | """ 278 | if not has_key(attrs, 'href'): return None 279 | 280 | i = -1 281 | for a in self.a: 282 | i += 1 283 | match = 0 284 | 285 | if has_key(a, 'href') and a['href'] == attrs['href']: 286 | if has_key(a, 'title') or has_key(attrs, 'title'): 287 | if (has_key(a, 'title') and has_key(attrs, 'title') and 288 | a['title'] == attrs['title']): 289 | match = True 290 | else: 291 | match = True 292 | 293 | if match: return i 294 | 295 | def drop_last(self, nLetters): 296 | if not self.quiet: 297 | self.outtext = self.outtext[:-nLetters] 298 | 299 | def handle_emphasis(self, start, tag_style, parent_style): 300 | """handles various text emphases""" 301 | tag_emphasis = google_text_emphasis(tag_style) 302 | parent_emphasis = google_text_emphasis(parent_style) 303 | 304 | # handle Google's text emphasis 305 | strikethrough = 'line-through' in tag_emphasis and self.hide_strikethrough 306 | bold = 'bold' in tag_emphasis and not 'bold' in parent_emphasis 307 | italic = 'italic' in tag_emphasis and not 'italic' in parent_emphasis 308 | fixed = google_fixed_width_font(tag_style) and not \ 309 | google_fixed_width_font(parent_style) and not self.pre 310 | 311 | if start: 312 | # crossed-out text must be handled before other attributes 313 | # in order not to output qualifiers unnecessarily 314 | if bold or italic or fixed: 315 | self.emphasis += 1 316 | if strikethrough: 317 | self.quiet += 1 318 | if italic: 319 | self.o("_") 320 | self.drop_white_space += 1 321 | if bold: 322 | self.o("**") 323 | self.drop_white_space += 1 324 | if fixed: 325 | self.o('`') 326 | self.drop_white_space += 1 327 | self.code = True 328 | else: 329 | if bold or italic or fixed: 330 | # there must not be whitespace before closing emphasis mark 331 | self.emphasis -= 1 332 | self.space = 0 333 | self.outtext = self.outtext.rstrip() 334 | if fixed: 335 | if self.drop_white_space: 336 | # empty emphasis, drop it 337 | self.drop_last(1) 338 | self.drop_white_space -= 1 339 | else: 340 | self.o('`') 341 | self.code = False 342 | if bold: 343 | if self.drop_white_space: 344 | # empty emphasis, drop it 345 | self.drop_last(2) 346 | self.drop_white_space -= 1 347 | else: 348 | self.o("**") 349 | if italic: 350 | if self.drop_white_space: 351 | # empty emphasis, drop it 352 | self.drop_last(1) 353 | self.drop_white_space -= 1 354 | else: 355 | self.o("_") 356 | # space is only allowed after *all* emphasis marks 357 | if (bold or italic) and not self.emphasis: 358 | self.o(" ") 359 | if strikethrough: 360 | self.quiet -= 1 361 | 362 | def handle_tag(self, tag, attrs, start): 363 | #attrs = fixattrs(attrs) 364 | if attrs is None: 365 | attrs = {} 366 | else: 367 | attrs = dict(attrs) 368 | 369 | if self.google_doc: 370 | # the attrs parameter is empty for a closing tag. in addition, we 371 | # need the attributes of the parent nodes in order to get a 372 | # complete style description for the current element. we assume 373 | # that google docs export well formed html. 374 | parent_style = {} 375 | if start: 376 | if self.tag_stack: 377 | parent_style = self.tag_stack[-1][2] 378 | tag_style = element_style(attrs, self.style_def, parent_style) 379 | self.tag_stack.append((tag, attrs, tag_style)) 380 | else: 381 | dummy, attrs, tag_style = self.tag_stack.pop() 382 | if self.tag_stack: 383 | parent_style = self.tag_stack[-1][2] 384 | 385 | if hn(tag): 386 | self.p() 387 | if start: 388 | self.inheader = True 389 | self.o(hn(tag)*"#" + ' ') 390 | else: 391 | self.inheader = False 392 | return # prevent redundant emphasis marks on headers 393 | 394 | if tag in ['p', 'div']: 395 | if self.google_doc: 396 | if start and google_has_height(tag_style): 397 | self.p() 398 | else: 399 | self.soft_br() 400 | else: 401 | self.p() 402 | 403 | if tag == "br" and start: self.o(" \n") 404 | 405 | if tag == "hr" and start: 406 | self.p() 407 | self.o("* * *") 408 | self.p() 409 | 410 | if tag in ["head", "style", 'script']: 411 | if start: self.quiet += 1 412 | else: self.quiet -= 1 413 | 414 | if tag == "style": 415 | if start: self.style += 1 416 | else: self.style -= 1 417 | 418 | if tag in ["body"]: 419 | self.quiet = 0 # sites like 9rules.com never close 420 | 421 | if tag == "blockquote": 422 | if start: 423 | self.p(); self.o('> ', 0, 1); self.start = 1 424 | self.blockquote += 1 425 | else: 426 | self.blockquote -= 1 427 | self.p() 428 | 429 | if tag in ['em', 'i', 'u'] and not self.ignore_emphasis: self.o("_") 430 | if tag in ['strong', 'b'] and not self.ignore_emphasis: self.o("**") 431 | if tag in ['del', 'strike']: 432 | if start: 433 | self.o("<"+tag+">") 434 | else: 435 | self.o("") 436 | 437 | if self.google_doc: 438 | if not self.inheader: 439 | # handle some font attributes, but leave headers clean 440 | self.handle_emphasis(start, tag_style, parent_style) 441 | 442 | if tag in ["code", "tt"] and not self.pre: self.o('`') #TODO: `` `this` `` 443 | if tag == "abbr": 444 | if start: 445 | self.abbr_title = None 446 | self.abbr_data = '' 447 | if has_key(attrs, 'title'): 448 | self.abbr_title = attrs['title'] 449 | else: 450 | if self.abbr_title != None: 451 | self.abbr_list[self.abbr_data] = self.abbr_title 452 | self.abbr_title = None 453 | self.abbr_data = '' 454 | 455 | if tag == "a" and not self.ignore_links: 456 | if start: 457 | if has_key(attrs, 'href') and not (self.skip_internal_links and attrs['href'].startswith('#')): 458 | self.astack.append(attrs) 459 | self.o("[") 460 | else: 461 | self.astack.append(None) 462 | else: 463 | if self.astack: 464 | a = self.astack.pop() 465 | if a: 466 | if self.inline_links: 467 | self.o("](" + a['href'] + ")") 468 | else: 469 | i = self.previousIndex(a) 470 | if i is not None: 471 | a = self.a[i] 472 | else: 473 | self.acount += 1 474 | a['count'] = self.acount 475 | a['outcount'] = self.outcount 476 | self.a.append(a) 477 | self.o("][" + str(a['count']) + "]") 478 | 479 | if tag == "img" and start and not self.ignore_images: 480 | if has_key(attrs, 'src'): 481 | attrs['href'] = attrs['src'] 482 | alt = attrs.get('alt', '') 483 | if self.inline_links: 484 | self.o("![") 485 | self.o(alt) 486 | self.o("]("+ attrs['href'] +")") 487 | else: 488 | i = self.previousIndex(attrs) 489 | if i is not None: 490 | attrs = self.a[i] 491 | else: 492 | self.acount += 1 493 | attrs['count'] = self.acount 494 | attrs['outcount'] = self.outcount 495 | self.a.append(attrs) 496 | self.o("![") 497 | self.o(alt) 498 | self.o("]["+ str(attrs['count']) +"]") 499 | 500 | if tag == 'dl' and start: self.p() 501 | if tag == 'dt' and not start: self.pbr() 502 | if tag == 'dd' and start: self.o(' ') 503 | if tag == 'dd' and not start: self.pbr() 504 | 505 | if tag in ["ol", "ul"]: 506 | # Google Docs create sub lists as top level lists 507 | if (not self.list) and (not self.lastWasList): 508 | self.p() 509 | if start: 510 | if self.google_doc: 511 | list_style = google_list_style(tag_style) 512 | else: 513 | list_style = tag 514 | numbering_start = list_numbering_start(attrs) 515 | self.list.append({'name':list_style, 'num':numbering_start}) 516 | else: 517 | if self.list: self.list.pop() 518 | self.lastWasList = True 519 | else: 520 | self.lastWasList = False 521 | 522 | if tag == 'li': 523 | self.pbr() 524 | if start: 525 | if self.list: li = self.list[-1] 526 | else: li = {'name':'ul', 'num':0} 527 | if self.google_doc: 528 | nest_count = self.google_nest_count(tag_style) 529 | else: 530 | nest_count = len(self.list) 531 | self.o(" " * nest_count) #TODO: line up
  1. s > 9 correctly. 532 | if li['name'] == "ul": self.o(self.ul_item_mark + " ") 533 | elif li['name'] == "ol": 534 | li['num'] += 1 535 | self.o(str(li['num'])+". ") 536 | self.start = 1 537 | 538 | if tag in ["table", "tr"] and start: self.p() 539 | if tag == 'td': self.pbr() 540 | 541 | if tag == "pre": 542 | if start: 543 | self.startpre = 1 544 | self.pre = 1 545 | else: 546 | self.pre = 0 547 | self.p() 548 | 549 | def pbr(self): 550 | if self.p_p == 0: self.p_p = 1 551 | 552 | def p(self): self.p_p = 2 553 | 554 | def soft_br(self): 555 | self.pbr() 556 | self.br_toggle = ' ' 557 | 558 | def o(self, data, puredata=0, force=0): 559 | if self.abbr_data is not None: self.abbr_data += data 560 | 561 | if not self.quiet: 562 | if self.google_doc: 563 | # prevent white space immediately after 'begin emphasis' marks ('**' and '_') 564 | lstripped_data = data.lstrip() 565 | if self.drop_white_space and not (self.pre or self.code): 566 | data = lstripped_data 567 | if lstripped_data != '': 568 | self.drop_white_space = 0 569 | 570 | if puredata and not self.pre: 571 | data = re.sub('\s+', ' ', data) 572 | if data and data[0] == ' ': 573 | self.space = 1 574 | data = data[1:] 575 | if not data and not force: return 576 | 577 | if self.startpre: 578 | #self.out(" :") #TODO: not output when already one there 579 | self.startpre = 0 580 | 581 | bq = (">" * self.blockquote) 582 | if not (force and data and data[0] == ">") and self.blockquote: bq += " " 583 | 584 | if self.pre: 585 | bq += " " 586 | data = data.replace("\n", "\n"+bq) 587 | 588 | if self.start: 589 | self.space = 0 590 | self.p_p = 0 591 | self.start = 0 592 | 593 | if force == 'end': 594 | # It's the end. 595 | self.p_p = 0 596 | self.out("\n") 597 | self.space = 0 598 | 599 | if self.p_p: 600 | self.out((self.br_toggle+'\n'+bq)*self.p_p) 601 | self.space = 0 602 | self.br_toggle = '' 603 | 604 | if self.space: 605 | if not self.lastWasNL: self.out(' ') 606 | self.space = 0 607 | 608 | if self.a and ((self.p_p == 2 and self.links_each_paragraph) or force == "end"): 609 | if force == "end": self.out("\n") 610 | 611 | newa = [] 612 | for link in self.a: 613 | if self.outcount > link['outcount']: 614 | self.out(" ["+ str(link['count']) +"]: " + urlparse.urljoin(self.baseurl, link['href'])) 615 | if has_key(link, 'title'): self.out(" ("+link['title']+")") 616 | self.out("\n") 617 | else: 618 | newa.append(link) 619 | 620 | if self.a != newa: self.out("\n") # Don't need an extra line when nothing was done. 621 | 622 | self.a = newa 623 | 624 | if self.abbr_list and force == "end": 625 | for abbr, definition in self.abbr_list.items(): 626 | self.out(" *[" + abbr + "]: " + definition + "\n") 627 | 628 | self.p_p = 0 629 | self.out(data) 630 | self.outcount += 1 631 | 632 | def handle_data(self, data): 633 | if r'\/script>' in data: self.quiet -= 1 634 | 635 | if self.style: 636 | self.style_def.update(dumb_css_parser(data)) 637 | 638 | self.o(data, 1) 639 | 640 | def unknown_decl(self, data): pass 641 | 642 | def charref(self, name): 643 | if name[0] in ['x','X']: 644 | c = int(name[1:], 16) 645 | else: 646 | c = int(name) 647 | 648 | if not self.unicode_snob and c in unifiable_n.keys(): 649 | return unifiable_n[c] 650 | else: 651 | try: 652 | return unichr(c) 653 | except NameError: #Python3 654 | return chr(c) 655 | 656 | def entityref(self, c): 657 | if not self.unicode_snob and c in unifiable.keys(): 658 | return unifiable[c] 659 | else: 660 | try: name2cp(c) 661 | except KeyError: return "&" + c + ';' 662 | else: 663 | try: 664 | return unichr(name2cp(c)) 665 | except NameError: #Python3 666 | return chr(name2cp(c)) 667 | 668 | def replaceEntities(self, s): 669 | s = s.group(1) 670 | if s[0] == "#": 671 | return self.charref(s[1:]) 672 | else: return self.entityref(s) 673 | 674 | r_unescape = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));") 675 | def unescape(self, s): 676 | return self.r_unescape.sub(self.replaceEntities, s) 677 | 678 | def google_nest_count(self, style): 679 | """calculate the nesting count of google doc lists""" 680 | nest_count = 0 681 | if 'margin-left' in style: 682 | nest_count = int(style['margin-left'][:-2]) / self.google_list_indent 683 | return nest_count 684 | 685 | 686 | def optwrap(self, text): 687 | """Wrap all paragraphs in the provided text.""" 688 | if not self.body_width: 689 | return text 690 | 691 | assert wrap, "Requires Python 2.3." 692 | result = '' 693 | newlines = 0 694 | for para in text.split("\n"): 695 | if len(para) > 0: 696 | if not skipwrap(para): 697 | for line in wrap(para, self.body_width): 698 | result += line + "\n" 699 | result += "\n" 700 | newlines = 2 701 | else: 702 | if not onlywhite(para): 703 | result += para + "\n" 704 | newlines = 1 705 | else: 706 | if newlines < 2: 707 | result += "\n" 708 | newlines += 1 709 | return result 710 | 711 | ordered_list_matcher = re.compile(r'\d+\.\s') 712 | unordered_list_matcher = re.compile(r'[-\*\+]\s') 713 | 714 | def skipwrap(para): 715 | # If the text begins with four spaces or one tab, it's a code block; don't wrap 716 | if para[0:4] == ' ' or para[0] == '\t': 717 | return True 718 | # If the text begins with only two "--", possibly preceded by whitespace, that's 719 | # an emdash; so wrap. 720 | stripped = para.lstrip() 721 | if stripped[0:2] == "--" and stripped[2] != "-": 722 | return False 723 | # I'm not sure what this is for; I thought it was to detect lists, but there's 724 | # a
    -inside- case in one of the tests that also depends upon it. 725 | if stripped[0] == '-' or stripped[0] == '*': 726 | return True 727 | # If the text begins with a single -, *, or +, followed by a space, or an integer, 728 | # followed by a ., followed by a space (in either case optionally preceeded by 729 | # whitespace), it's a list; don't wrap. 730 | if ordered_list_matcher.match(stripped) or unordered_list_matcher.match(stripped): 731 | return True 732 | return False 733 | 734 | def wrapwrite(text): 735 | text = text.encode('utf-8') 736 | try: #Python3 737 | sys.stdout.buffer.write(text) 738 | except AttributeError: 739 | sys.stdout.write(text) 740 | 741 | def html2text(html, baseurl=''): 742 | h = HTML2Text(baseurl=baseurl) 743 | return h.handle(html) 744 | 745 | def unescape(s, unicode_snob=False): 746 | h = HTML2Text() 747 | h.unicode_snob = unicode_snob 748 | return h.unescape(s) 749 | 750 | def main(): 751 | baseurl = '' 752 | 753 | p = optparse.OptionParser('%prog [(filename|url) [encoding]]', 754 | version='%prog ' + __version__) 755 | p.add_option("--ignore-emphasis", dest="ignore_emphasis", action="store_true", 756 | default=IGNORE_EMPHASIS, help="don't include any formatting for emphasis") 757 | p.add_option("--ignore-links", dest="ignore_links", action="store_true", 758 | default=IGNORE_ANCHORS, help="don't include any formatting for links") 759 | p.add_option("--ignore-images", dest="ignore_images", action="store_true", 760 | default=IGNORE_IMAGES, help="don't include any formatting for images") 761 | p.add_option("-g", "--google-doc", action="store_true", dest="google_doc", 762 | default=False, help="convert an html-exported Google Document") 763 | p.add_option("-d", "--dash-unordered-list", action="store_true", dest="ul_style_dash", 764 | default=False, help="use a dash rather than a star for unordered list items") 765 | p.add_option("-b", "--body-width", dest="body_width", action="store", type="int", 766 | default=BODY_WIDTH, help="number of characters per output line, 0 for no wrap") 767 | p.add_option("-i", "--google-list-indent", dest="list_indent", action="store", type="int", 768 | default=GOOGLE_LIST_INDENT, help="number of pixels Google indents nested lists") 769 | p.add_option("-s", "--hide-strikethrough", action="store_true", dest="hide_strikethrough", 770 | default=False, help="hide strike-through text. only relevent when -g is specified as well") 771 | (options, args) = p.parse_args() 772 | 773 | # process input 774 | encoding = "utf-8" 775 | 776 | data = os.environ['POPCLIP_TEXT'] 777 | 778 | data = data.decode(encoding) 779 | h = HTML2Text(baseurl=baseurl) 780 | # handle options 781 | if options.ul_style_dash: h.ul_item_mark = '-' 782 | 783 | h.body_width = options.body_width 784 | h.list_indent = options.list_indent 785 | h.ignore_emphasis = options.ignore_emphasis 786 | h.ignore_links = options.ignore_links 787 | h.ignore_images = options.ignore_images 788 | h.google_doc = options.google_doc 789 | h.hide_strikethrough = options.hide_strikethrough 790 | 791 | print h.handle(data) 792 | 793 | main() 794 | 795 | 796 | # Markdown Mark by [Dustin Curtis](https://github.com/dcurtis/markdown-mark) 797 | -------------------------------------------------------------------------------- /mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | ruby = "3.3.0" 3 | -------------------------------------------------------------------------------- /nvUltra.popclipext/Config.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Actions 6 | 7 | 8 | Image File 9 | rocket.png 10 | Script Interpreter 11 | /usr/bin/ruby 12 | Shell Script File 13 | nvUltra.rb 14 | 15 | 16 | Apps 17 | 18 | 19 | Bundle Identifier 20 | com.multimarkdown.nvultra 21 | Check Installed 22 | 23 | Link 24 | https://nvultra.com 25 | Name 26 | nvUltra 27 | 28 | 29 | Options 30 | 31 | 32 | Option Identifier 33 | nvnotebook 34 | Option Type 35 | string 36 | Option Label 37 | Folder 38 | 39 | 40 | Credits 41 | 42 | 43 | Name 44 | Brett Terpstra 45 | 46 | 47 | Extension Description 48 | Create a note in nvUltra. 49 | Extension Identifier 50 | com.brettterpstra.popclip.extension.nvultra 51 | Extension Name 52 | nvUltra 53 | Required Software Version 54 | 701 55 | 56 | 57 | -------------------------------------------------------------------------------- /nvUltra.popclipext/README.md: -------------------------------------------------------------------------------- 1 | ### nvUltra 2 | 3 | [nvUltra](https://nvultra.com) extension for PopClip. Add text as new note to frontmost notebook, or define a notebook in settings. 4 | 5 | #### Credits 6 | 7 | Originally created by Marc Abramowitz - see [https://github.com/msabramo/nvALT.popclipext](https://github.com/msabramo/nvALT.popclipext). Icon and minor modifications by Nick Moore. 8 | -------------------------------------------------------------------------------- /nvUltra.popclipext/_Signature.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Signature 6 | 7 | PyaeNniM4p3m4gA91mI8gA7ws3017cImL1rcLJuh6HpclyTUj5R9msgoHdA6at6gT1qs 8 | jgodXdKrH497/qKnfbKj4gxlhCZ1QiyU8yNHhtXwIOAuyqAprN6zV4JspU3E33om3jc7 9 | 06a7Lzx+8hDDM4ltTr+2ooSDddRCqx+6X00= 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /nvUltra.popclipext/nvUltra.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'erb' 5 | 6 | nb = ENV['POPCLIP_OPTION_NVNOTEBOOK'] 7 | text = ENV['POPCLIP_TEXT'] 8 | 9 | notebook = nb && !nb.empty? ? %(¬ebook="#{ERB::Util.url_encode(nb)}") : '' 10 | 11 | url = "x-nvultra://make/?txt=#{ERB::Util.url_encode(text)}#{notebook}" 12 | 13 | `open "#{url}"` 14 | -------------------------------------------------------------------------------- /nvUltra.popclipext/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ttscoff/popclipextensions/81a97925c317a804ad731e348c57b3cf7a635b22/nvUltra.popclipext/rocket.png --------------------------------------------------------------------------------