Class: Ruvi::EditorApp::DiffLogger::DifferenceLog
- Inherits:
-
Object
- Object
- Ruvi::EditorApp::DiffLogger::DifferenceLog
- Defined in:
- lib/timemachine.rb
Instance Attribute Summary collapse
-
#partial_flush_mode ⇒ Object
Returns the value of attribute partial_flush_mode.
Instance Method Summary collapse
- #<<(diff) ⇒ Object
- #branch_id(id) ⇒ Object
- #difflog_fname ⇒ Object
- #do_flush(mods) ⇒ Object
- #finalize ⇒ Object
- #flush ⇒ Object
- #inc_id(id) ⇒ Object
-
#initialize(app, buffer) ⇒ DifferenceLog
constructor
A new instance of DifferenceLog.
- #invalidated? ⇒ Boolean
- #load_difflog ⇒ Object
-
#load_or_create_difflog ⇒ Object
log file must always be appended to.
- #logline(line) ⇒ Object
- #partial_flush ⇒ Object
-
#prev_id(id) ⇒ Object
goes up branches!.
-
#redo ⇒ Object
not really redo…
- #revert_to_save_point ⇒ Object
- #saved ⇒ Object
- #undo ⇒ Object
Constructor Details
#initialize(app, buffer) ⇒ DifferenceLog
Returns a new instance of DifferenceLog.
11 12 13 14 15 16 17 18 |
# File 'lib/timemachine.rb', line 11 def initialize app, buffer # history_buffer used from here via indirection, as maybe history_buffer can change? @app, @buffer = app, buffer @last_save_point, @current_patch_num = nil, nil @diffs = [] @ids2changesets = {} @partial_flush_mode = false end |
Instance Attribute Details
#partial_flush_mode ⇒ Object
Returns the value of attribute partial_flush_mode.
10 11 12 |
# File 'lib/timemachine.rb', line 10 def partial_flush_mode @partial_flush_mode end |
Instance Method Details
#<<(diff) ⇒ Object
268 269 270 |
# File 'lib/timemachine.rb', line 268 def << diff @diffs << diff end |
#branch_id(id) ⇒ Object
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/timemachine.rb', line 44 def branch_id id id = (id || "") num = 1 while true new_id = "#{id}##{num}" num += 1 break unless @ids2changesets.keys.detect { |_id| _id.index(new_id) == 0 } end "#{new_id}.1" end |
#difflog_fname ⇒ Object
19 20 21 22 23 24 25 26 |
# File 'lib/timemachine.rb', line 19 def difflog_fname if !@buffer.fname.nil? fname = "#{File.dirname @buffer.fname}#{File::SEPARATOR}+#{File.basename @buffer.fname}.edlog" return fname if File.writable? fname end dir = $win32 ? "#{ENV["TEMP"]}" : "/tmp/" "#{dir}#{$$}.#{(0..8).collect{rand 10}.join ""}.edlog" end |
#do_flush(mods) ⇒ Object
105 106 107 108 109 110 |
# File 'lib/timemachine.rb', line 105 def do_flush mods mods.each { |diff| logline diff.to_s } end |
#finalize ⇒ Object
35 36 37 38 |
# File 'lib/timemachine.rb', line 35 def finalize @file.close unless @file.nil? or @file_closed @file_closed = true end |
#flush ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/timemachine.rb', line 111 def flush return partial_flush if @partial_flush_mode start_val = 0 if !@partial_flush_last_count.nil? start_val = @partial_flush_last_count @partial_flush_last_count = nil end return if @diffs.empty? do_flush @diffs.slice(start_val..-1) if @ids2changesets.has_key? inc_id(@current_patch_num) @current_patch_num = branch_id @current_patch_num else @current_patch_num = inc_id @current_patch_num end @last_followed_branch = @current_patch_num logline "FLUSHED_CHANGESET #{@current_patch_num}" @ids2changesets[@current_patch_num] = @diffs @diffs = [] end |
#inc_id(id) ⇒ Object
54 55 56 57 58 59 |
# File 'lib/timemachine.rb', line 54 def inc_id id return "#1.1" if id.nil? raise "invalid id" if id == "1" or id.empty? id =~ /^(.*?)([0-9]+)$/ "#{$1}#{$2.to_i + 1}" end |
#invalidated? ⇒ Boolean
136 137 138 139 140 141 142 143 144 |
# File 'lib/timemachine.rb', line 136 def invalidated? # note - patch numbers can never be 0!, nil is used to indicate this! # p "(#{@current_patch_num.inspect}) > (#{@last_save_point.inspect}) -> #{(@current_patch_num || "0") > (@last_save_point || "0")}" if @current_patch_num == "#1.1" and @last_save_point.nil? return true else return ((@current_patch_num || "#1.1") != (@last_save_point || "#1.1")) end end |
#load_difflog ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/timemachine.rb', line 155 def load_difflog @ids2changesets = {} toreplay = [] @last_followed_branch = nil @file = File.open difflog_fname, "r+" @file.each_line { |l| matched_type = nil DifferenceTypes::instance.registered_change_types.each { |difftype| matched_type = difftype if difftype.it_was_me l } if matched_type.nil? case l when /^SAVE_POINT$/ @last_save_point = @current_patch_num || "1" toreplay = [] when /^FLUSHED_CHANGESET (.*?)$/ @last_followed_branch = $1 @current_patch_num = $1 @ids2changesets[$1] = @diffs @diffs = [] toreplay << [:patch, $1] when /^UNDO_CHANGESET (.*?)$/ @current_patch_num = prev_id $1 toreplay << [:undo, $1] when /^REDO_CHANGESET (.*?)$/ @current_patch_num = $1 toreplay << [:redo, $1] when /^REVERTED$/ ; # pass else raise "line unparseable! - #{l}" end else matched_type.from_s(@buffer, l) # auto adds via << end } dbg(:ufw) { "position count == #{@current_patch_num.inspect} - can be nil if we undo the first patch" } dbg(:ufw) { "save point == #{@last_save_point}" } # in order to flush partial changesets with a missing boundry we force one extra final flush if !@diffs.empty? flush toreplay << [:patch, @current_patch_num] end sets_to_remove = @ids2changesets.index(@last_save_point) # test - save once, then close file without a save point and force a replay?? if !@diffs.empty? @change_sets.push @diffs @diffs = [] end dbg(:ufw) { toreplay.inspect } needs_patch = false toreplay.each_with_index { |tuple, idx| cmd, id = *tuple dbg(:ufw) { "working on command :: #{cmd} :: #{id}" } case cmd when :undo dbg(:ufw) { "undoing previous change set" } change_set = @ids2changesets[id] change_set.reverse.each { |change| change.undo } @current_patch_num = prev_id id when :redo dbg(:ufw) { "redoing previous change set" } # TODO - test change_set = @ids2changesets[id] change_set.each { |change| change.redo } @current_patch_num = id when :patch dbg(:ufw) { "replaying current change set (calls :redo)" } # duplication from below, which in turn is ... dbg(:ufw) { "redoing previous change set" } # duplication from .redo change_set = @ids2changesets[id] change_set.each { |change| change.redo dbg(:ufw) { "\nPLAYING!!! <<<" } dbg(:ufw) { change.to_s } dbg(:ufw) { ">>>\n" } } @current_patch_num = id end } dbg(:ufw) { "current_patch_num state at end of the log replay is #{@current_patch_num.inspect}" } end |
#load_or_create_difflog ⇒ Object
log file must always be appended to. all writes are thusly as good as atomic truncate is not available on windows platform afaik is file move atomic on windows platform?
148 149 150 151 152 153 |
# File 'lib/timemachine.rb', line 148 def load_or_create_difflog @filename = difflog_fname return load_difflog if File.exists? difflog_fname and $load_difflogs @current_patch_num = nil @file = nil end |
#logline(line) ⇒ Object
27 28 29 30 31 32 33 34 |
# File 'lib/timemachine.rb', line 27 def logline line dbg(:ufw) { line } @app.history_buffer.lines << line @file = File.open @filename, "w+" if @file.nil? @file.puts line @file.flush @file.fsync end |
#partial_flush ⇒ Object
130 131 132 133 134 135 |
# File 'lib/timemachine.rb', line 130 def partial_flush new_count = @diffs.length mods = @diffs.slice(@partial_flush_last_count..new_count) @partial_flush_last_count = new_count do_flush mods end |
#prev_id(id) ⇒ Object
goes up branches!
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/timemachine.rb', line 61 def prev_id id raise "invalid id" if id == "1" or id.empty? id =~ /^(.*?)([0-9]+)$/ if $2 == "1" id = id.gsub(/#\d+\.\d+$/, '') id = nil if id.empty? else id = "#{$1}#{$2.to_i - 1}" end id end |
#redo ⇒ Object
not really redo… but go forward
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/timemachine.rb', line 82 def redo # not really redo... but go forward if !@ids2changesets.has_key? inc_id(@current_patch_num) return end if @ids2changesets.keys.find_all { |id| @current_patch_num.nil? || (id.index(@current_patch_num) == 0) } last_id = nil id = @last_followed_branch while true last_id = id id = prev_id id break if id == @current_patch_num or id.nil? end @current_patch_num = last_id else @current_patch_num = inc_id @current_patch_num end logline "REDO_CHANGESET #{@current_patch_num}" change_set = @ids2changesets[@current_patch_num] change_set.each { |change| change.redo } end |
#revert_to_save_point ⇒ Object
254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/timemachine.rb', line 254 def revert_to_save_point catch(:waza) { while true dbg(:ufw) { "revert_to_save_point - last save point == #{@last_save_point.inspect} : section count == #{@current_patch_num.inspect}" } self.undo # TODO - test - the above happens when there is a edlog, but no file... throw(:waza) if (@current_patch_num == @last_save_point) or (@last_save_point == "1" and @current_patch_num.nil?) end } # maybe this should be distinct from undo??? logline "REVERTED" saved end |
#saved ⇒ Object
39 40 41 42 43 |
# File 'lib/timemachine.rb', line 39 def saved flush # not sure about this... logline "SAVE_POINT" @last_save_point = @current_patch_num end |
#undo ⇒ Object
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/timemachine.rb', line 72 def undo return if @current_patch_num.nil? change_set = @ids2changesets[@current_patch_num] change_set.reverse.each { |change| change.undo } logline "UNDO_CHANGESET #{@current_patch_num}" @current_patch_num = prev_id @current_patch_num end |