#!/usr/bin/env ruby require 'coderay' $options, args = ARGV.partition { |arg| arg[/^-[hv]$|--\w+/] } subcommand = args.first if /^\w/ === args.first subcommand = nil if subcommand && File.exist?(subcommand) args.delete subcommand def option? *options !($options & options).empty? end def tty? $stdout.tty? || option?('--tty') end def version puts <<-USAGE CodeRay #{CodeRay::VERSION} USAGE end def help puts <<-HELP This is CodeRay #{CodeRay::VERSION}, a syntax highlighting tool for selected languages. usage: coderay [-language] [input] [-format] [output] defaults: language detect from input file name or shebang; fall back to plain text input STDIN format detect from output file name or use terminal; fall back to HTML output STDOUT common: coderay file.rb # highlight file to terminal coderay file.rb -page > file.html # highlight file to HTML page coderay file.rb -div > file.html # highlight file to HTML snippet configure output: coderay file.py output.json # output tokens as JSON coderay file.py -loc # count lines of code in Python file configure input: coderay -python file # specify the input language coderay -ruby # take input from STDIN more: coderay stylesheet [style] # print CSS stylesheet HELP end def commands puts <<-COMMANDS general: highlight code highlighting (default command, optional) stylesheet print the CSS stylesheet with the given name (aliases: style, css) about: list [of] list all available plugins (or just the scanners|encoders|styles|filetypes) commands print this list help show some help version print CodeRay version COMMANDS end def print_list_of plugin_host plugins = plugin_host.all_plugins.map do |plugin| info = " #{plugin.plugin_id}: #{plugin.title}" aliases = (plugin.aliases - [:default]).map { |key| "-#{key}" }.sort_by { |key| key.size } if plugin.respond_to?(:file_extension) || !aliases.empty? additional_info = [] additional_info << aliases.join(', ') unless aliases.empty? info << " (#{additional_info.join('; ')})" end info << ' <-- default' if plugin.aliases.include? :default info end puts plugins.sort end if option? '-v', '--version' version end if option? '-h', '--help' help end case subcommand when 'highlight', nil if ARGV.empty? version help else signature = args.map { |arg| arg[/^-/] ? '-' : 'f' }.join names = args.map { |arg| arg.sub(/^-/, '') } case signature when /^$/ exit when /^ff?$/ input_file, output_file, = *names when /^f-f?$/ input_file, output_format, output_file, = *names when /^-ff?$/ input_lang, input_file, output_file, = *names when /^-f-f?$/ input_lang, input_file, output_format, output_file, = *names when /^--?f?$/ input_lang, output_format, output_file, = *names else $stdout = $stderr help puts puts "Unknown parameter order: #{args.join ' '}, expected: [-language] [input] [-format] [output]" exit 1 end if input_file input_lang ||= CodeRay::FileType.fetch input_file, :text, true end if output_file output_format ||= CodeRay::FileType[output_file] || :plain else output_format ||= :terminal_256 end output_format = :page if output_format.to_s == 'html' if input_file input = File.read input_file else input = $stdin.read end begin file = if output_file File.open output_file, 'w' else $stdout end CodeRay.encode(input, input_lang, output_format, :out => file) file.puts rescue CodeRay::PluginHost::PluginNotFound => boom $stdout = $stderr if boom.message[/CodeRay::(\w+)s could not load plugin :?(.*?): /] puts "I don't know the #$1 \"#$2\"." else puts boom.message end # puts "I don't know this plugin: #{boom.message[/Could not load plugin (.*?): /, 1]}." rescue CodeRay::Scanners::Scanner::ScanError # this is sometimes raised by pagers; ignore # FIXME: rescue Errno::EPIPE ensure file.close if output_file end end when 'li', 'list' arg = args.first && args.first.downcase if [nil, 's', 'sc', 'scanner', 'scanners'].include? arg puts 'input languages (Scanners):' print_list_of CodeRay::Scanners end if [nil, 'e', 'en', 'enc', 'encoder', 'encoders'].include? arg puts 'output formats (Encoders):' print_list_of CodeRay::Encoders end if [nil, 'st', 'style', 'styles'].include? arg puts 'CSS themes for HTML output (Styles):' print_list_of CodeRay::Styles end if [nil, 'f', 'ft', 'file', 'filetype', 'filetypes'].include? arg puts 'recognized file types:' filetypes = Hash.new { |h, k| h[k] = [] } CodeRay::FileType::TypeFromExt.inject filetypes do |types, (ext, type)| types[type.to_s] << ".#{ext}" types end CodeRay::FileType::TypeFromName.inject filetypes do |types, (name, type)| types[type.to_s] << name types end filetypes.sort.each do |type, exts| puts " #{type}: #{exts.sort_by { |ext| ext.size }.join(', ')}" end end when 'stylesheet', 'style', 'css' puts CodeRay::Encoders[:html]::CSS.new(args.first || :default).stylesheet when 'commands' commands when 'help' help else $stdout = $stderr help puts if subcommand[/\A\w+\z/] puts "Unknown command: #{subcommand}" else puts "File not found: #{subcommand}" end exit 1 end