Skip to content

Instantly share code, notes, and snippets.

@jcsjcs
Last active August 29, 2015 14:22
Show Gist options
  • Save jcsjcs/e56dff5137d48578bfc0 to your computer and use it in GitHub Desktop.
Save jcsjcs/e56dff5137d48578bfc0 to your computer and use it in GitHub Desktop.
Format code in syntax-highlighted html for clipboard using xclip and rouge.
#!/usr/bin/env ruby
# Format code with syntax highlighting for pasting in emails.
# To use:
# 1) Highlight the code.
# 2) fmail ruby/sql/java_script etc...
# 3) Middle-click in email to paste html code.
#
# CLI program xclip must be installed. http://sourceforge.net/projects/xclip/
require_relative 'trollop'
require 'rouge'
require 'open3'
begin
str = `xclip -o`
rescue Errno::ENOENT # Requires xclip
puts "\"xclip\" is not installed."
exit 1
end
global_opts = Trollop::options do
banner <<-EOS
fmail - Format code on the middle-mouse clipboard for pasting as HTML
Usage:
<<Select (highlight) code>>
fmail [-ib] <format>
<<Middle-click mouse button to paste HTML>>
Use one of the following formats (e.g. fmail -i sql):
\t#{Rouge::Lexer.all.map {|l| [l.tag, l.aliases] }.sort.map {|l| [l.first, l.last].flatten.sort.uniq.map {|a| a.ljust(20)} }.flatten.each_slice(5).map {|a| a.join(" ") }.join("\n\t")}
Options:
EOS
opt :inline, "Wrap the output in <code> instead of <pre>.", :short => "-i"
opt :base16, "Use the base16 colour theme instead of the github theme.", :short => "-b"
opt :lineno, "Print line numbers. Not compatible with --inline.", :short => "-l"
end
cmd = ARGV.shift # get the subcommand
Trollop::die "please provide a format" if cmd.nil?
Trollop::die "unknown format #{cmd.inspect}" unless Rouge::Lexer.find(cmd)
inline = global_opts[:inline]
is_irb = 'irb' == cmd
cmd = 'ruby' if is_irb
opts = {:css_class => nil, :inline_theme => global_opts[:base16] ? 'base16' : 'github', :line_numbers => global_opts[:lineno]}
if is_irb
opts[:wrap] = false
formatter = Rouge::Formatters::HTML.new(opts)
new = []
lexer = Rouge::Lexers::Ruby.new
arb4 = str.split("\n")
arb4.each do |a|
m = a.match(/^.+?>/)
b = m.nil? ? '' : m[0]
c = b =~ /.*=>/ ? '<span style="background-color:#ffff00;color:#00f">=></span>' : ''
new << (c << formatter.format(lexer.lex(a.sub(b, ''))))
end
output = "<#{pre}>#{new.join("\n")}</#{pre}>"
else
opts[:wrap] = false if inline
formatter = Rouge::Formatters::HTML.new(opts)
if inline
tag_start = '<code>'
tag_end = '</code>'
else
tag_start = ''
tag_end = ''
end
lexer = Rouge::Lexer.find(cmd)
output = "#{tag_start}#{formatter.format(lexer.lex(str))}#{tag_end}"
end
# Pipe output to xclip...
Open3.popen2e("xclip") {|i,o,t|
i << output
i.close
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment