#!/usr/bin/perl -w =pod =head1 NAME xcleanpaste - join multi-line copy/paste into one long line =head1 SYNOPSIS B [-n] [-u] [-e] [-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> 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 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;