Created
December 31, 2012 14:24
-
-
Save aeris/4420087 to your computer and use it in GitHub Desktop.
Fast cd with learning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
#encoding: utf-8 | |
require 'sqlite3' | |
SEPARATOR = '' | |
class Stats | |
DB_FILE=File.join Dir.home, ".xd.sqlite3" | |
def initialize | |
exist = File.exist? DB_FILE | |
@db = SQLite3::Database.new DB_FILE | |
self.create unless exist | |
self.purge | |
end | |
def create | |
@db.execute "CREATE TABLE stats (path TEXT NOT NULL, occurrence INTEGER NOT NULL, last_used TEXT NOT NULL)" | |
end | |
def purge | |
date = DateTime.now.prev_month.to_s | |
@db.execute "DELETE FROM stats WHERE last_used < ?", date | |
end | |
def close | |
@db.close | |
end | |
def get(paths) | |
paths.uniq! | |
result = {} | |
@db.execute "SELECT path, occurrence FROM stats WHERE path in ( ? )", paths.join(", ") do |row| | |
path = row[0] | |
occurrence = row[1] | |
result[path] = occurrence | |
paths.delete path | |
end | |
paths.each { |path| result[path] = 0 } | |
result.sort { |a, b| a[1] <=> b[1]}.reverse | |
end | |
def add(path) | |
@db.execute "UPDATE stats SET occurrence = occurrence + 1, last_used = datetime('now') WHERE path = ?", path | |
if @db.changes == 0 | |
@db.execute "INSERT INTO stats (path, occurrence, last_used) VALUES (?, 0, datetime('now'))", path | |
end | |
end | |
def get_target(path) | |
result = [] | |
l = path.split(SEPARATOR).length | |
@db.execute "SELECT path FROM stats" do |row| | |
file = row[0] | |
expected = file.split File::SEPARATOR | |
next if expected.length < l | |
expected = expected.collect { |p| p[0] }[-l, l] .join SEPARATOR | |
result << file if expected == path | |
end | |
result | |
end | |
end | |
class DirectoryChanger | |
def initialize stats | |
@stats = stats | |
end | |
def get_target(path) | |
path = path.downcase | |
if path.start_with?('/') | |
start = '/' | |
path = path.sub /^#{Regexp.escape('/')}/, "" | |
elsif path.start_with?('-') | |
start = Dir.home | |
path = path.sub /^#{Regexp.escape('-')}/, "" | |
else | |
start = Dir.pwd | |
end | |
path = path.split SEPARATOR | |
target = self.find_target start, path | |
end | |
def find_target(directory, path) | |
return [] unless File.readable? directory | |
if path.length <= 0 | |
return [directory] | |
end | |
result = [] | |
Dir.entries(directory).each do |entry| | |
subdirectory = File.join(directory, entry) | |
if File.directory?(subdirectory) && entry.downcase.start_with?(path[0]) | |
result.concat self.find_target subdirectory, path[1..-1] | |
end | |
end | |
result | |
end | |
def perform(path) | |
if path.start_with? '+' | |
force = true | |
path = path.sub /^#{Regexp.escape('+')}/, "" | |
else | |
force = false | |
end | |
target = self.get_target path | |
target.concat @stats.get_target path | |
target = @stats.get target | |
if force && target.length > 1 | |
target = target[0, 1] | |
end | |
if target.length == 0 | |
return 1 | |
elsif target.length == 1 | |
target = target[0] | |
else | |
begin | |
i = 1 | |
target.each do |t| | |
STDERR.puts "#{i} → #{t[0]}" | |
i+=1 | |
end | |
STDERR.print "? > " | |
value = STDIN.gets.chomp | |
if value == "" | |
value = 0 | |
else | |
value = value.to_i - 1 | |
end | |
end while 0 > value || value >= target.length | |
target = target[value] | |
end | |
target = target[0] | |
@stats.add target | |
print target | |
return 0 | |
end | |
end | |
stats = Stats.new | |
changer = DirectoryChanger.new stats | |
code = changer.perform ARGV[0] | |
stats.close | |
exit code |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment