diff options
author | hut <hut@lavabit.com> | 2009-05-09 00:00:00 +0200 |
---|---|---|
committer | hut <hut@lavabit.com> | 2009-05-09 00:00:00 +0200 |
commit | a0de7f95bc7525b99b2c2e16f566e0ee367e9c3c (patch) | |
tree | 62d1cdf9523f4e8fad28ca7df0e1d696c991d2db | |
parent | 34bfb32ecf2cea5e5de95980beedb681139d9c01 (diff) |
lots of changes. version 0.2.1v0.2.1
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | Readme | 0 | ||||
-rw-r--r-- | code/action.rb | 69 | ||||
-rw-r--r-- | code/bars.rb | 134 | ||||
-rw-r--r-- | code/debug.rb | 24 | ||||
-rw-r--r-- | code/directory.rb (renamed from code/extensions.rb) | 381 | ||||
-rw-r--r-- | code/draw.rb | 194 | ||||
-rw-r--r-- | code/extensions/basic.rb | 149 | ||||
-rw-r--r-- | code/extensions/fileutils.rb | 1726 | ||||
-rw-r--r-- | code/fm.rb | 57 | ||||
-rw-r--r-- | code/keys.rb | 238 | ||||
-rw-r--r-- | code/screensaver/clock.rb | 10 | ||||
-rw-r--r-- | code/types.rb | 106 | ||||
-rwxr-xr-x | data/generate.rb | 21 | ||||
-rw-r--r-- | data/mime.dat | bin | 0 -> 10452 bytes | |||
-rw-r--r-- | data/mime.types | 769 | ||||
-rwxr-xr-x | fm | 35 | ||||
-rw-r--r-- | interface/ncurses.rb | 110 |
18 files changed, 3562 insertions, 507 deletions
@@ -1,14 +1,54 @@ +Version 0.2.1 + +2009-05-09 hut + Oh no. I neglegted to write change logs... in a nutshell, i changed: + New Hotkey: [r]...flags...[r] which runs the selected file with flags + like [d] to detach the process or [t] to run it in a seperate terminal + For that I also changed Action.run() + +2009-04-27 hut + Minor changes to the way directories and file infos are read + entries are not instantly scheduled upon encounter + Rewritten "ascend" method, which uses Action::run() now (still theres a lot + to be done) + Directory::entry#mimetype() instead of Fm.MIMETYPES[Directory::entry#ext()] + +2009-04-18 hut + Found reproducable bug which leaves it (after closing) running and using up + 99% CPU. It happens when the window managers way of closing windows by + pressing the X button or pressing Alt+F4 is used to quit. + New Hotkeys: [S-TAB] is a shortcut for [`][`] and [TAB] for [`][9] + Better distinguishable columns + MIME support, allowing sorting by MIME-filetype + TODO: fall back to sorting by name for two files of identical filetype + Sorting by extension + Minor bugs fixed + +2009-04-16 hut + New Combination [c][u][t] to mark files for moving + Replaced system() calls with cp or mv with the use of FileUtils + Modified FileUtils for showing its progress the progressbar + Fixed threading problem which made it impossible to stop copying/moving + Fixed priority problems, fluent UI while copying. + + TODO: enqueue file operations for better performance + +2009-04-15 hut + + Added possibility to run fm with a filename in argument which runs the + file, like an enter-press inside fm would run it. + Version 0.2 2009-04-10 hut Generating Previews in the background - Help screen - Tooltips for (S) and (t) + Help screen with [?] + Tooltips for [S] and [t] Added more filetype associations Split up fm.rb into several files 2009-04-09 hut - New Hotkey (S) to change sorting order + New Hotkey [S] to change sorting order Generalized file-modifying tasks in the Action module 2009-04-08 hut diff --git a/code/action.rb b/code/action.rb new file mode 100644 index 00000000..e463e852 --- /dev/null +++ b/code/action.rb @@ -0,0 +1,69 @@ +module Action + def self.copy(files, path) + files = [files] unless files.is_a? Array + unless files.empty? + CopyBar2.new(files, path) + end + end + + def self.move(files, path) + files = [files] unless files.is_a? Array + unless files.empty? + MoveBar2.new(files, path) + end + end + + def self.run(hash = {}) + unless OpenStruct === hash + hash = OpenStruct.new(hash) + end + + cf = Fm.currentfile + + all = hash.all.or true + files = hash.files.or(all ? Fm.selection : [cf]) + mode = hash.mode.or 0 + newway = hash.newway.or false + + return false if files.nil? + + if newway + hash = Fm.filehandler(files, hash) + handler = hash.exec + else + handler, wait = Fm.getfilehandler(*files) + end + + return false unless handler + + wait = hash.wait.or wait + new_term = hash.new_term.or false + detach = hash.detach.or false + + log handler + if detach + run_detached(handler, new_term) + else + run_inside(handler, wait) + end + return true + end + + def self.run_detached(what, new_term) + if new_term + p = fork { exec('x-terminal-emulator', '-e', 'bash', '-c', what) } +# Process.detach(p) + else + p = fork { exec "#{what} 2>> /dev/null >> /dev/null" } + Process.detach(p) + end + end + + def self.run_inside(what, wait) + closei + system(*what) + gets if wait + starti + end +end + diff --git a/code/bars.rb b/code/bars.rb new file mode 100644 index 00000000..61d14572 --- /dev/null +++ b/code/bars.rb @@ -0,0 +1,134 @@ +class Bar + def initialize( text = '' ) + @text = text + @text_prefix = nil + @max = 0 + @done = 0 + @counter = 0 + @thread = nil + @update_proc = nil + Fm.bar_add(self) + end + + def kill(evil = true) + Fm.bar_del(self) + Fm.force_update + + @thread.kill + end + + def update(&block) + if block + @update_proc = block + elsif @update_proc + @update_proc.call(self) + end + end + + def set_text_prefix(text) + @text_prefix = text + end + def set_text(text) + @text_prefix = nil + @text = text + end + alias text= set_text + + attr_accessor :thread, :counter, :max +end + +class CopyBar < Bar + def initialize( text = '' ) + super + + @update_proc = proc do |b| + begin + b.done = File.size(fname).to_f / finished + rescue + b.done = 0 + end + end + end +end + +class Bar2 + def kill(evil = true) + Fm.bar_del(self) + Fm.force_update + + @thread.kill + end + + def set_text_prefix(text) + @text_prefix = text + end + def set_text(text) + @text_prefix = nil + @text = text + end + alias text= set_text + + attr_accessor :thread, :counter, :max + def done + if @counter.is_a? MutableNumber + @counter.value.to_f / @max + else + 0 + end + end + + def update() end + + def text + if @text_prefix + "#{@text_prefix} #{(@counter.value.to_f * 10000/ @max).round.to_f/100}%" + elsif @text + @text + else + "" + end + end +end + +class CopyOrMoveBar < Bar2 + def initialize(files, path) + path = path.path unless path.is_a? String + Fm.bar_add(self) + log([files, path]) + + + @thread = Thread.new do + begin + for file in files + file = file.path unless file.is_a? String + if File.exists?(file) + run_operation(file, path) + end + end + rescue + log $! + log $!.backtrace + ensure + kill(false) + end + end + @thread.priority = Fm::COPY_PRIORITY + end +end + +class CopyBar2 < CopyOrMoveBar + def run_operation(file, path) + if File.directory?(file) + FileUtils.cp_r_in_bar(self, file, path) + else + FileUtils.cp_in_bar(self, file, path) + end + end +end + +class MoveBar2 < CopyOrMoveBar + def run_operation(file, path) + FileUtils.mv_in_bar(self, file, path) + end +end + diff --git a/code/debug.rb b/code/debug.rb index 6261ed0e..d3a97190 100644 --- a/code/debug.rb +++ b/code/debug.rb @@ -1,4 +1,3 @@ - require 'pp' module Debug @@ -25,6 +24,28 @@ module Debug end if LOG_LEVEL > 0 + def bm(descr="benchmark", &block) + # Benchmark + t1 = Time.now + yield + dur = Time.now-t1 + + # substract the durtation of a "bm(..) do end" + dur -= bm_dummy(descr) do end + + # Format the duration + dur *= 1000 + dur = dur > 0 ? dur : 0 + dur = '%0.3f' % dur + logerr("#{descr}: #{dur}ms") + end + + def bm_dummy(descr="benchmark", &block) + t1 = Time.now + yield + return (Time.now-t1) + end + def __log__(obj, level) if level <= LOG_LEVEL obj = obj.nil? ? "checkpoint at #{Time.now}" : obj @@ -63,5 +84,6 @@ module Debug def log(a=nil) end def logpp(a=nil) end def trace() end + def bm(*args, &block) yield end end end diff --git a/code/extensions.rb b/code/directory.rb index a15fc952..c42392aa 100644 --- a/code/extensions.rb +++ b/code/directory.rb @@ -1,184 +1,6 @@ -class Bar - def initialize( text = '' ) - @text = text - @done = 0 - @thread = nil - @update_proc = nil - Fm.bar_add(self) - end - - def kill(evil = true) - Fm.bar_del(self) - Fm.force_update - - @thread.kill - end - - def update(&block) - if block - @update_proc = block - elsif @update_proc - @update_proc.call(self) - end - end - - attr_accessor :text, :done, :thread -end - -class CopyBar < Bar - def initialize( text = '' ) - super - - @update_proc = proc do |b| - begin - b.done = File.size(fname).to_f / finished - rescue - b.done = 0 - end - end - end -end - -module Action -# def self.get_all_files(path) -# glob = Dir.new(path).to_a -# end - - def self.make_a_bar_for_one(text, command) - bar = CopyBar.new(test) - - finished = File.size(from[0]).to_f - fname = File.join(to, File.basename(from[0])) - - bar.thread = Thread.new do - begin - system('ionice', '-c3', command, *(from + [to])) - ensure - bar.kill(false) - end - end - end - - def self.copy(from, to) -# log [from, to] - -# if String === from[0] -# from[0] = Directory::Entry.new(from[0]) -# end - - if from.size == 1 and from[0].file? - from = from[0] - bar = Bar.new("Copying...") - finished = from.size.to_f - fname = File.join(to, from.basename) - - bar.update do |b| - begin - b.done = File.size(fname).to_f / finished - rescue - b.done = 0 - end - end - - bar.thread = Thread.new do - begin - system('cp', from.to_s, to) - ensure - bar.kill(false) - end - end - - else - bar = Bar.new("Copying...") - from = from.dup - from = [from] unless Array === from - finished = Dir.number_of_files(*from.map{|x| x.to_s}) - count = 0 - - bar.update do |b| - begin - b.done = count / finished - rescue - b.done = 0 - end - end - - from.map!{|x| x.to_s} - bar.thread = Thread.new do - begin - system('cp', '-r', *(from + [to.to_s])) -# IO.popen("cp -vr #{from.join(' ')} #{to.sh}") do |f| -# IO.popen(['cp', '-vr', *(from + [to])]) do |f| -# count += 1 while f.gets =~ /' -> `/ -# end - ensure - bar.kill(false) - end - end - end - end - - def self.move(from, to) -# log [from, to] - -# if String === from[0] -# from[0] = Directory::Entry.new(from[0]) -# end - - if from.size == 1 and from[0].file? - from = from[0] - bar = Bar.new("Moving...") - finished = from.size.to_f - fname = File.join(to, from.basename) - - bar.update do |b| - begin - b.done = File.size(fname).to_f / finished - rescue - b.done = 0 - end - end - - bar.thread = Thread.new do - begin - system('mv', from.to_s, to) - ensure - bar.kill(false) - end - end - - else - bar = Bar.new("Moving...") - from = from.dup - from = [from] unless Array === from - finished = Dir.number_of_files(*from.map{|x| x.to_s}) - count = 0 - - bar.update do |b| - begin - b.done = count / finished - rescue - b.done = 0 - end - end - - from.map!{|x| x.to_s} - bar.thread = Thread.new do - begin - system('mv', *(from + [to.to_s])) -# IO.popen("mv -v #{from.join(' ')} #{to.sh}") do |f| -# count += 1 while f.gets =~ /' -> `/ -# end - ensure - bar.kill(false) - end - end - end - end -end - class Directory BAD_TIME = Time.at(0) + MOVIE_EXTENSIONS = %w(avi mpg mpeg mp4 mp5 ogv ogm wmv mkv flv fid vob div divx) class Entry #{{{ # Let's just cache every shit, because i don't want # to call File methods all the time @@ -194,6 +16,9 @@ class Directory @dirname = File.dirname(dirname) @basename = File.basename(dirname) end + @name, @ext = @basename.split_at_last_dot +# @ext = @basename.from_last('.') || '' + @movie = MOVIE_EXTENSIONS.include?(@ext) @size = 0 @exists = false @rights = '----------' @@ -208,8 +33,10 @@ class Directory @marked = false end - attr_reader(:basename, :mtime, :rights, :type, :path, - :infostring, :readlink, :basename, :size, :ctime) + attr_reader *%w( + basename mtime rights type path ext + infostring readlink basename size ctime name + ) attr_accessor(:marked) @@ -217,11 +44,19 @@ class Directory def exists?() @exists end def marked?() @marked end def symlink?() @symlink end + def movie?() @movie end def broken_symlink?() @symlink and !@exists end def dir?() @type == :dir end def file?() @type == :file end def writable?() @writable end def executable?() @executable end + def mimetype() + if @type == :dir + nil + else + Fm::MIMETYPES[@ext] + end + end def delete! if @type == :dir @@ -242,17 +77,7 @@ class Directory end def sh - res = @path.dup - res.gsub!('\\\\', "\000") - res.gsub!(' ', '\\ ') - res.gsub!('(', '\\(') - res.gsub!('&', '\\&') - res.gsub!(')', '\\)') - res.gsub!('*', '\\*') - res.gsub!('\'', '\\\'') - res.gsub!('"', '\\"') - res.gsub!("\000", '\\\\') - return res + @path.sh end def in? path @@ -322,6 +147,9 @@ class Directory @file_size = 0 @pointed_file = nil @width = 1000 + @read = false + @empty = true + @scheduled = false refresh end @@ -334,6 +162,7 @@ class Directory else @files.reject!{|x| x[0] == ?. or x == 'lost+found'} end + if @files.empty? @files = ['.'] end @@ -342,14 +171,60 @@ class Directory @files.map!{|basename| Entry.new(@path, basename)} end - attr_reader(:path, :files, :pos, :width, :files_raw, :file_size) + attr_reader(:path, :files, :pos, :width, :files_raw, + :file_size, :read) + attr_accessor(:scheduled) + + def scheduled?() @scheduled end + def read?() @read end def pos=(x) +# if @files.size <= 1 or x < 0 +# x = 0 +# elsif x > @files.size +# x = @files.size - 1 +# end @pos = x + make_sure_cursor_is_in_range() @pointed_file = @files[x] resize end + def recheck_stuff() +# log "pointed file: #@pointed_file" +# log @files_raw +# log "" + if test = @files_raw.index(@pointed_file) +# log("if") + @pos = test + else +# log("else") + make_sure_cursor_is_in_range() + end + end + + def make_sure_cursor_is_in_range() + if @files.size <= 1 or @pos < 0 + @pos = 0 + elsif @pos > @files.size + @pos = @files.size - 1 + end + end + + def find_file(x) + x = File.basename(x) + + files.each_with_index do |file, i| + if file.basename == x + self.pos = i + end + end + end + + def empty?() + Dir.entries(@path).size <= 2 + end + def restore() for f in @files f.marked = false @@ -389,6 +264,7 @@ class Directory f.refresh @file_size += f.size if f.file? end + @read = true end # def refresh() @@ -421,19 +297,29 @@ class Directory end def schedule() + @scheduled = true Fm.schedule(self) end def refresh!() + oldfile = @pointed_file read_dir get_file_info sort + + if @files.include? oldfile + self.pointed_file = oldfile + end end def sort_sub(x, y) case OPTIONS['sort'] when :name x.basename <=> y.basename + when :ext + x.ext <=> y.ext + when :type + x.ext.filetype <=> y.ext.filetype when :size x.size <=> y.size when :ctime @@ -462,112 +348,3 @@ class Directory end end - -class File - MODES_HASH = { - '0' => '---', - '1' => '--x', - '2' => '-w-', - '3' => '-wx', - '4' => 'r--', - '5' => 'r-x', - '6' => 'rw-', - '7' => 'rwx' - } - def self.modestr(f) - unless exists?(f) - return '----------' - end - - if symlink?(f) - result = 'l' - elsif directory?(f) - result = 'd' - else - result = '-' - end - - s = ("%o" % File.stat(f).mode)[-3..-1] - for m in s.each_char - result << MODES_HASH[m] - end - - result - end -end - -class Dir - def self.number_of_files(*dirs) - n = 0 - dirs.each do |entry| - if File.directory?(entry) - n += 1 + number_of_files(*(Dir.new(entry).to_a - ['.', '..']).map\ - {|x| File.join entry, x } ) - else - n += 1 - end - end - return n - end -end - -class Numeric - def limit(max, min = 0) - self < min ? min : (self > max ? max : self) - end - - def bytes space = true, n_round = 2 - n = 1024 - a = %w(B K M G T Y) - - i = 0 - flt = self.to_f - - while flt > n and i < a.length - 1 - flt /= n - i += 1 - end - -# flt = flt.round(n_round) - r = 10 ** n_round - flt *= r - flt = flt.round.to_f / r - int = flt.to_i - flt = int if int == flt - - return flt.to_s + (space ? ' ' + a[i] : a[i]) - end -end - -class Array - def wrap(n) - n.times { push shift } - end -end - -class String - def clear - replace String.new - end - if RUBY_VERSION < '1.9' - def ord - self[0] - end - end - - def sh - res = self.dup - res.gsub!('\\\\', "\000") - res.gsub!(' ', '\\ ') - res.gsub!('(', '\\(') - res.gsub!('&', '\\&') - res.gsub!(')', '\\)') - res.gsub!('*', '\\*') - res.gsub!('\'', '\\\'') - res.gsub!('"', '\\"') - res.gsub!("\000", '\\\\') - return res - end - -end - diff --git a/code/draw.rb b/code/draw.rb index 1a2236cc..dac6c25c 100644 --- a/code/draw.rb +++ b/code/draw.rb @@ -1,5 +1,5 @@ module Fm - DONT_PREVIEW_THESE_FILES = /\.(avi|[mj]pe?g|iso|mp\d|og[gmv]|wm[av]|mkv|torrent|so|class|flv|png|bmp|zip|rar|7z|tar|gz|vob|divx?)$/i + DONT_PREVIEW_THESE_FILES = /\.(avi|[mj]pe?g|iso|mp\d|og[gmv]|wm[av]|mkv|torrent|so|class|flv|png|bmp|vob|divx?)$/i def self.column_put_file(n, file) i = 0 @@ -7,85 +7,140 @@ module Fm m = lines - 2 color 7 bold false - File.open(file.path, 'r') do |f| - check = true - left, wid = get_boundaries(n) - f.lines.each do |l| - if check - check = false - break unless l.each_char.all? {|x| x[0] > 0 and x[0] < 128} - end - puti i+1, left, l.gsub("\t"," ")[0, wid-1].ljust(wid) + left, wid = get_boundaries(n) + if file.ext =~ /(?:rar|zip|7z|tar|gz)$/ and file.size < 10485760 + text = `aunpack -l #{file.sh} 2>> /dev/null` + text.each_line do |l| + puti i+1, left, l[0, wid-1].ljust(wid) i += 1 break if i == m end + else + File.open(file.path, 'r') do |f| + check = true + left, wid = get_boundaries(n) + f.lines.each do |l| + if check + check = false + break unless l.each_char.all? {|x| x[0] > 0 and x[0] < 128} + end + puti i+1, left, l.gsub("\t"," ")[0, wid-1].ljust(wid) + i += 1 + break if i == m + end + end end end column_clear(n, i) end def self.put_directory(c, d) - l = 0 + l = 1 if d infos = (c == COLUMNS - 2) left, wid = get_boundaries(c) - offset = get_offset(d, lines) - (lines - 1).times do |l| - lpo = l + offset - bg = -1 - break if (f = d.files[lpo]) == nil - - dir = false - if f.symlink? - bld = true - if f.broken_symlink? - clr = [1, bg] + if d.read? and not d.empty? + + offset = get_offset(d, lines) + (lines - 1).times do |l| + lpo = l + offset + bg = -1 + break if (f = d.files[lpo]) == nil +# log f + + dir = false + if f.symlink? + bld = true + if f.broken_symlink? + clr = [1, bg] + else + clr = [6, bg] + end + dir = f.dir? + elsif f.dir? + bld = true + dir = true + clr = [4, bg] + elsif f.movie? + bld = true + clr = [5, bg] + elsif f.executable? + bld = true + clr = [2, bg] else - clr = [6, bg] + bld = false + clr = [7, bg] end - dir = f.dir? - elsif f.dir? - bld = true - dir = true - clr = [4, bg] - elsif f.executable? - bld = true - clr = [2, bg] - else - bld = false - clr = [7, bg] - end - fn = f.basename - if f.marked? - fn = "*#{fn}" - end - if infos - myinfo = " #{f.infostring} " - str = fn[0, wid-1].ljust(wid+1) - if str.size > myinfo.size - str[-myinfo.size..-1] = myinfo - yes = true + fn = f.basename + if f.marked? + fn = "* #{fn}" + end + if infos + myinfo = " #{f.infostring} " + str = fn[0, wid-1].ljust(wid+1) + if str.size > myinfo.size + str[-myinfo.size..-1] = myinfo + yes = true + else + yes = false + end + puti l+1, left, str + if dir and yes + args = l+1, left+wid-myinfo.size, myinfo.size, *clr + color_bold_at(*args) + end else - yes = false + puti l+1, left, fn[0, wid-1].ljust(wid+1) end - puti l+1, left, str - if dir and yes - args = l+1, left+wid-myinfo.size, myinfo.size, *clr - color_bold_at(*args) + + args = l+1, left, fn.size.limit(wid-1), *clr + + if d.pos == lpo + if c == COLUMNS - 2 +# puti l+1, left-1, '^' +# puti l+1, left+args[2], '$' + + args[4] = 0 +# args[1] -= 1 +# if args[2] < 5 +# args[2] = 7 +# else +# args[2] += 1 +# end +# color_bold_at(l+1, left-1, 1, 0, 0) +# color_bold_at(l+1, left+args[2], 1, 0, 0) + color_reverse_bold_at(*args) + + # ... + args[1] -= 1; args[2] += 2 + color_bold_at(*args) + args[1] += 1; args[2] -= 2 + color_reverse_bold_at(*args) + else + color_reverse_at(*args) + end +# if f.marked? +# args[1] += 1 +# args[2] = 1 +# args[3] = 1 +# color_reverse_at(*args) +# end + else + if bld then color_at(*args) else color_at(*args) end +# if bld then color_bold_at(*args) else color_at(*args) end end - else - puti l+1, left, fn[0, wid-1].ljust(wid+1) end + elsif d.read? and d.empty? + puti l, left, 'empty'.ljust(wid+1) - args = l+1, left, fn.size.limit(wid), *clr + elsif not d.read? + puti l, left, 'reading...'.ljust(wid+1) + d.schedule unless d.scheduled? + else + puti l, left, 'ERROR'.ljust(wid+1) - if d.pos == lpo - color_reverse_at(*args) - else - if bld then color_bold_at(*args) else color_at(*args) end - end end end @@ -140,7 +195,9 @@ module Fm bold false @cur_y = get_boundaries(COLUMNS-2)[0] - if @buffer == '?' + if @buffer =~ /^block/ + screensaver + elsif @buffer == '?' cleari puti 0, " - - - Help - - -" puti 2, " h/j/k/l: Movement J/K: fast Movement" @@ -177,12 +234,22 @@ module Fm puti 8, " gh: go to ~/" puti 9, " gt: go to ~/.trash/" else + @pwd.recheck_stuff() + cf = currentfile + + if cf and s0 = cf.mimetype + puti 0, cols-s0.size, s0 + end + s1 = " " s2 = "#{@path.last.path}#{"/" unless @path.size == 1}" - cf = currentfile s3 = "#{cf ? cf.basename : ''}" - puti 0, (s1 + s2 + s3).ljust(cols) + if s0 + puti 0, (s1 + s2 + s3).ljust(cols-s0.size) + else + puti 0, (s1 + s2 + s3).ljust(cols) + end bg = -1 color_at 0, 0, -1, 7, bg @@ -227,6 +294,7 @@ module Fm puti btm, "Toggle (h)idden_files (d)irs_first (c)olor (f)ilepreview" else # log(@pwd) +# log "Buffer: #{@buffer}" puti btm, "#@buffer #{@pwd.file_size.bytes(false)},#{@pwd.size},#{@pwd.pos+1} ".rjust(cols) more = '' if cf.symlink? @@ -255,10 +323,10 @@ module Fm done = bar.done c = (done * cols).to_i unless done == 0 - color_at l, 0, c, 0, 2 + color_at l, 0, c, 0, 4 end unless done == cols - color_at l, c, -1, 0, 3 + color_at l, c, -1, 0, 6 end end end diff --git a/code/extensions/basic.rb b/code/extensions/basic.rb new file mode 100644 index 00000000..c822e9f6 --- /dev/null +++ b/code/extensions/basic.rb @@ -0,0 +1,149 @@ +# Generic extensions of the language + +class MutableNumber + attr_accessor :value + + def initialize(n=0) + @value = n + end + def add(n=1) @value += n end + def sub(n=1) @value -= n end +end + +class Array + def wrap(n) + # TODO: this can be done better... + n.times { push shift } + end +end + +class String + def clear + self.replace("") + end + + if RUBY_VERSION < '1.9' + def ord + self[0] + end + end + + def from_first(str) + self.include?(str) ? self [ self.index(str) + str.size .. -1 ] : nil + end + + def from_last(str) + self.include?(str) ? self [ self.rindex(str) + str.size .. -1 ] : nil + end + + def split_at_last_dot() + if ix = self.rindex('.') + return self[0...ix], self[ix+1..-1] + else + return self, '' + end + end + + def before_last(str) + self.include?(str) ? self [ 0 .. rindex(str) - str.size ] : self + end + + def filetype() + Fm::MIMETYPES[self] || 'unknown' + end + + def sh + res = self.dup + res.gsub!('\\\\', "\000") + res.gsub!(' ', '\\ ') + res.gsub!('(', '\\(') + res.gsub!('&', '\\\&') + res.gsub!(')', '\\)') + res.gsub!('*', '\\*') + res.gsub!('\'', "\\\\'") + res.gsub!('"', '\\"') + res.gsub!("\000", '\\\\') + return res + end +end + +class Numeric + def limit(max, min = 0) + self < min ? min : (self > max ? max : self) + end + + def bytes space = true, n_round = 2 + n = 1024 + a = %w(B K M G T Y) + + i = 0 + flt = self.to_f + + while flt > n and i < a.length - 1 + flt /= n + i += 1 + end + +# flt = flt.round(n_round) + r = 10 ** n_round + flt *= r + flt = flt.round.to_f / r + int = flt.to_i + flt = int if int == flt + + return flt.to_s + (space ? ' ' + a[i] : a[i]) + end +end + +class Dir + def self.number_of_files(*dirs) + n = 0 + dirs.each do |entry| + if File.directory?(entry) + n += 1 + number_of_files(*(Dir.new(entry).to_a - ['.', '..']).map\ + {|x| File.join entry, x } ) + else + n += 1 + end + end + return n + end +end + |