119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env ruby
 | 
						|
 | 
						|
# Wrag stands for writeable-ag; a hacky script that allows you to search with ag
 | 
						|
# <https://github.com/ggreer/the_silver_searcher> and edit the results in
 | 
						|
# $EDITOR. The changes are propagated to all listed files, if any.
 | 
						|
#
 | 
						|
# Usage: wrag [pattern]
 | 
						|
#
 | 
						|
# TODO Also rename changed filenames
 | 
						|
# TODO Assemble sed string to make this atomic
 | 
						|
 | 
						|
require 'optparse'
 | 
						|
require 'tempfile'
 | 
						|
require 'shellwords'
 | 
						|
 | 
						|
def usage
 | 
						|
  puts "Usage: #{File.basename($0)} [-f|--rename-files] [-b|--backup] search_string"
 | 
						|
  puts "\nAny of ag's flags will work with wrag"
 | 
						|
  exit
 | 
						|
end
 | 
						|
 | 
						|
usage if ARGV.empty?
 | 
						|
 | 
						|
## Parsing options ################################
 | 
						|
options = {:rename => false,
 | 
						|
           :backup => false}
 | 
						|
 | 
						|
opt = OptionParser.new
 | 
						|
opt.on('-f', '--rename-files') { options[:rename] = true }
 | 
						|
opt.on('-b', '--backup')       { options[:backup] = true }
 | 
						|
 | 
						|
begin
 | 
						|
  opt.parse
 | 
						|
  # Get rid of misc args to pass the rest to ag
 | 
						|
  args = ARGV - ["-f", "--rename-files", "-b", "--backup"]
 | 
						|
rescue OptionParser::InvalidOption => e
 | 
						|
  puts "Invalid option: #{e}"
 | 
						|
  usage
 | 
						|
end
 | 
						|
 | 
						|
## Perform search #################################
 | 
						|
t = Tempfile.new('.ag-results')
 | 
						|
out = system("ag #{args.join(' ')} --group --nocolor > #{t.path}")
 | 
						|
puts "No matches" if out === false
 | 
						|
if out == nil
 | 
						|
  t.unlink
 | 
						|
  exit 2
 | 
						|
end
 | 
						|
 | 
						|
old_lines = File.open(t.path).readlines
 | 
						|
system("#{ENV['EDITOR']} #{t.path}")
 | 
						|
lines = File.open(t.path).readlines
 | 
						|
t.unlink
 | 
						|
 | 
						|
if old_lines.length != lines.length
 | 
						|
  puts "There was a line-number mismatch. Abort! Abort! Abort!"
 | 
						|
  exit 3
 | 
						|
end
 | 
						|
 | 
						|
## Parse edited output ############################
 | 
						|
i = nil
 | 
						|
current_filename = nil
 | 
						|
lines.each_with_index do |line, i|
 | 
						|
  line.strip!
 | 
						|
 | 
						|
  next if line.empty?
 | 
						|
 | 
						|
  if line =~ /^([0-9]+):(.+)/ # make sure it isn't actually a file
 | 
						|
    filename = current_filename
 | 
						|
    lineno = $1
 | 
						|
    content = $2
 | 
						|
  elsif line =~ /^(.+):([0-9]+):(.+)/
 | 
						|
    if current_file
 | 
						|
      puts "Mixing and matching groups and non-groups! Aborting."
 | 
						|
      exit 3
 | 
						|
    end
 | 
						|
 | 
						|
    filename = $1
 | 
						|
    lineno = $2
 | 
						|
    content = $3
 | 
						|
  elsif File.exists?(line)
 | 
						|
    if File.readable?(line)
 | 
						|
      current_filename = line
 | 
						|
    else
 | 
						|
      puts "#{line} isn't readable. Skipping."
 | 
						|
    end
 | 
						|
    next
 | 
						|
  else
 | 
						|
    puts "Malformed line: #{line}"
 | 
						|
    exit 3
 | 
						|
  end
 | 
						|
 | 
						|
  next if line.eql?(old_lines[i].strip)
 | 
						|
 | 
						|
  filename = Shellwords.escape(filename)
 | 
						|
  lineno = Shellwords.escape(lineno)
 | 
						|
  content = content.gsub("'", "\\'")
 | 
						|
 | 
						|
  puts "#{filename}:#{lineno}:#{content}"
 | 
						|
 | 
						|
  if system("sed -i .bak '#{lineno}c\\
 | 
						|
#{content}
 | 
						|
  ' #{filename}")
 | 
						|
    puts "Replaced: line #{lineno} in #{filename}"
 | 
						|
  else
 | 
						|
    puts "Failed to replace line #{lineno} in #{filename}"
 | 
						|
  end
 | 
						|
 | 
						|
  unless options[:backup]
 | 
						|
    system("rm -f #{filename}.bak") if File.exists?("#{filename}.bak")
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
if i === nil
 | 
						|
  puts "Didn't do nuthin'"
 | 
						|
else
 | 
						|
  puts "Done!"
 | 
						|
end
 |