aboutsummaryrefslogtreecommitdiff
path: root/xcleanpaste
diff options
context:
space:
mode:
Diffstat (limited to 'xcleanpaste')
-rwxr-xr-xxcleanpaste153
1 files changed, 153 insertions, 0 deletions
diff --git a/xcleanpaste b/xcleanpaste
new file mode 100755
index 0000000..c122002
--- /dev/null
+++ b/xcleanpaste
@@ -0,0 +1,153 @@
+#!/usr/bin/perl -w
+
+=pod
+
+=head1 NAME
+
+xcleanpaste - join multi-line copy/paste into one long line
+
+=head1 SYNOPSIS
+
+B<xcleanpaste> [-n] [-u] [-e<line-ending>] [-v] [xsel-options]
+
+=head1 DESCRIPTION
+
+"Cleans" the X selection buffer: trims whitespace from the start
+and end of every line, replaces all newlines with spaces, replaces
+all tabs with 3 spaces each. Result is written back to the selection
+buffer, where you can paste it into whatever application you want.
+
+This is useful even for single-line pastes: it removes tabs and any
+newline at the end, so e.g. copying a command from a browser into the
+shell won't trigger tab-completion or execute the command immediately.
+
+The selection buffer is read/written using xsel, which must be
+installed and available on your PATH.
+
+xcleanpaste is best used by binding to a key using xbindkeys or
+similar, though you can run it from the shell too.
+
+If you're using keybinding, you probably want at least separate keys
+for xcleanpaste with no options and xcleanpaste with the -u option
+(URL cleaner; see below).
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-e><line-ending>
+
+Replace line endings with the given string rather than a space. Don't
+use a space between the -e and the ending. Beware of shell quoting
+rules.
+
+=item B<-n>
+
+Replace line endings with the string " \n " rather than a space. This is
+space, backslash, lowercase n, space. Equivalent to B<-e ' \n '>.
+
+=item B<-u>
+
+Remove CGI arguments from any URLs found in the buffer. Some sites
+including tracking info, e.g. https://site.blah/stuff?sessionID=12345,
+which you shouldn't be pasting into anything others can see (e.g. IRC
+or emails).
+
+=item B<-v>
+
+Verbose mode. Shows lines read and written from the xsel instances on
+stderr. Not much use with xbindkeys though.
+
+=back
+
+Any other arguments are passed to xsel. This is probably only useful
+for xsel's -p/-s/-b options (see xsel man page).
+
+=head1 EXAMPLE
+
+In B<~/.xbindkeys>:
+
+ "xcleanpaste &"
+ Control+Alt + period
+
+ "xcleanpaste -u &"
+ Control+Alt + slash
+
+If you copy these three lines:
+
+ This is
+ a long URL:
+ https://long.url?with=lots&of=arguments
+
+Then press Ctrl+Alt+Period, then paste into some window, you will get:
+
+ This is a long URL: https://long.url?with=lots&of=arguments
+
+If you instead press Ctrl+Alt+Slash, you'll get:
+
+ This is a long URL: https://long.url
+
+=head1 AUTHOR
+
+xcleanpaste was written by B. Watson <yalhcru@gmail.com> and released
+under the WTFPL: Do WTF you want with this.
+
+=cut
+
+( $SELF = $0 ) =~ s,.*/,,;
+
+@xselargs = ();
+$line_ends = " ";
+$url_clean = $verbose = 0;
+
+for(@ARGV) {
+ if(/^-?-h(?:elp)/) {
+ exec "perldoc $0";
+ exit 1; # if the exec failed
+ } elsif(/^-v/) {
+ $verbose++;
+ } elsif(/^-n/) {
+ $line_ends = " \\n ";
+ } elsif(/^-u/) {
+ $url_clean = 1;
+ } elsif(/^-e(.*)$/) {
+ if(!defined($1) || $1 eq "") {
+ die("$SELF: no space allowed between -e option and its argument\n");
+ }
+ $line_ends = $1;
+ } else {
+ push @xselargs, $_;
+ }
+}
+
+$xsel_extra_args = join(" ", @xselargs);
+warn "$SELF: xsel arguments: \"$xsel_extra_args\"\n" if $verbose;
+
+# We have to read the entire output of xsel -o into memory before
+# spawning the xsel -i, because otherwise the 2nd xsel will obliterate
+# the selection buffer the first one's still trying to read from.
+open my $in, "xsel -o $xsel_extra_args|" or die $!;
+while(<$in>) {
+ chomp;
+ warn "$SELF: read line $.: $_\n" if $verbose;
+ s,\s+$,,; # remove any trailing whitespace
+ s,^\s+,,; # remove any leading whitespace
+ s,[\r\n], ,g; # replace all CR or LF with a single space
+ s,\t, ,g; # replace all tabs with 3 spaces
+ if($url_clean) {
+ # get rid of ? and anything after it, in anything that looks like a URL
+ s,(https?:\/\/[^?\s]*)\?\S+,$1,g;
+ }
+ s/\S$/$&$line_ends/; # our ending LF became a space above; make it
+ # whatever the line ending is supposed to be
+ push @lines, $_;
+}
+close $in;
+
+$output = join("", @lines);
+$output =~ s/\s+$//; # trim trailing whitespace from last line only
+warn "$SELF: writing: $output\n" if $verbose;
+
+open my $out, "|xsel -i $xsel_extra_args" or die $!;
+print $out $output;
+close $out;