Class: Rnote::Edit

Inherits:
Object
  • Object
show all
Defined in:
lib/rnote/noun/note/edit.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(auth) ⇒ Edit

Returns a new instance of Edit.



79
80
81
82
83
84
# File 'lib/rnote/noun/note/edit.rb', line 79

def initialize(auth)
  @auth = auth
  @note = Evernote::EDAM::Type::Note.new
  @note.content = @note.class.format_to_enml('txt','') # for creating new notes.
  @last_saved_note = Evernote::EDAM::Type::Note.new
end

Class Method Details

.has_set_options(options) ⇒ Object



105
106
107
# File 'lib/rnote/noun/note/edit.rb', line 105

def Edit.has_set_options(options)
  options[:'set-title']
end

.include_editor_options(noun) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rnote/noun/note/edit.rb', line 91

def Edit.include_editor_options(noun)
  noun.desc 'watch the file while editing and upload changes (you must save the file)'
  noun.default_value true
  noun.switch :watch
  
  noun.desc 'open an interactive editor to modify the note'
  noun.default_value true
  noun.switch :editor
  
  noun.desc 'which format do you want to edit the note in? default is "txt", other option is "enml"'
  noun.default_value 'txt'
  noun.flag :format
end

.include_set_options(noun) ⇒ Object



86
87
88
89
# File 'lib/rnote/noun/note/edit.rb', line 86

def Edit.include_set_options(noun)
  noun.desc 'set the title of the note'
  noun.flag :'set-title'
end

Instance Method Details

#apply_set_optionsObject



145
146
147
148
149
# File 'lib/rnote/noun/note/edit.rb', line 145

def apply_set_options
  if @options[:'set-title']
    @note.title = @options[:'set-title']
  end
end

#check_for_lost_contentObject

check if we lose content/formating when converting the note and if so ask the user if they want to continue.



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
# File 'lib/rnote/noun/note/edit.rb', line 199

def check_for_lost_content
  
  converted_content = @note.class.enml_to_format(@format, @note.content)
  unconverted_content = @note.class.format_to_enml(@format, converted_content)
  
  if @note.content != unconverted_content
    puts "Some content or formatting may be lost in the note due to editing format conversion."
    reply_continue = ask("Continue editing the note? (yes/no/diff) ") { |q|
      q.validate = /\A(y|n|d|q|e|c|yes|no|cancel|quit|exit|diff)\Z/i
      q.responses[:not_valid] = 'Please enter "yes", "no", "diff", or "cancel".'
      q.responses[:ask_on_error] = :question
    }
    
    case reply_continue.downcase
      when 'y'
        # nothing, continue
      when 'yes'
        # nothing, continue
      when 'n'
        raise "User cancelled due to lost content."
      when 'no'
        raise "User cancelled due to lost content."
      when 'cancel'
        raise "User cancelled due to lost content."
      when 'quit'
        raise "User cancelled due to lost content."
      when 'exit'
        raise "User cancelled due to lost content."
      when 'diff'
        show_diff(@note.content,unconverted_content)
      else
        raise
    end
    
    
  end
end

#edit_actionObject



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rnote/noun/note/edit.rb', line 122

def edit_action
  raise if not @note or not @last_saved_note
  
  if Edit.has_set_options(@options)
  
    apply_set_options
  
    if @use_editor
      editor
    else
      # if not going to open an editor, then just update immediately
      save_note
    end
  
  elsif @use_editor
    # no --set options
    editor
  else
    raise "you've specified --no-editor but provided not --set options either."
  end
  
end

#editorObject



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/rnote/noun/note/edit.rb', line 260

def editor
  
  ENV['EDITOR'] ||= 'vim'
  
  check_for_lost_content
  
  file = Tempfile.new(['rnote','.' + @format])
  begin
  
    # fill the tempfile with the yaml stream
    yaml_stream = @note.yaml_stream(@format)
    file.write(yaml_stream)
    file.close()
  
    # error detection loop, to retry editing the file
    successful_edit = false
    until successful_edit do
  
      has_file_changed(file) # initialize the file change tracking.
  
      # run editor in background
      pid = fork do
        exec(ENV['EDITOR'],file.path)
      end
  
      wwt = WaitPidTimeout.new(pid,1) # 1 second
  
      editor_done = false
      until editor_done do
        if not @watch_editor
          Process.waitpid(pid)
          editor_done = true
        elsif wwt.wait
          # process done
          editor_done = true
        else
          # timeout exceeded
  
          # has the file changed?
          if has_file_changed(file)
            # protect the running editor from our failures.
            begin
              update_note_from_file(file.path)
            rescue Exception => e
              $stderr.puts "rnote: an error occured while updating the note: #{e.message}"
            end
          end
        end
      end
  
      # one last update of the note
      # this time we care if there are errors
      if has_file_changed(file)
        begin
          update_note_from_file(file.path)
        rescue Exception => e

          puts "There was an error while uploading the note"
          puts e.message
          puts e.backtrace.join("\n    ")

          successful_edit = ! agree("Return to editor? (otherwise changes will be lost)  ")
        else
          successful_edit = true
        end
      else
        # no changes to file, no need to save.
        successful_edit = true
      end
  
    end # successful edit loop
  
  ensure
    file.unlink
  end
  
end

#has_file_changed(file) ⇒ Object

has the file changed since the last time we checked.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/rnote/noun/note/edit.rb', line 243

def has_file_changed(file)
  
  @last_mtime ||= nil
  @last_md5 ||= nil
  
  this_mtime = File.mtime(file.path)
  this_md5 = md5(file.path)
  
  changed = this_mtime != @last_mtime && this_md5 != @last_md5
  
  @last_mtime = this_mtime
  @last_md5 = this_md5
  
  changed
end

#md5(filename) ⇒ Object



237
238
239
240
# File 'lib/rnote/noun/note/edit.rb', line 237

def md5(filename)
  # TODO sloppy, switch with non shell command
  `cat #{filename} | md5`.chomp
end

#note(note) ⇒ Object



117
118
119
120
# File 'lib/rnote/noun/note/edit.rb', line 117

def note(note)
  @note = note
  @last_saved_note = note.deep_dup
end

#options(options) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/rnote/noun/note/edit.rb', line 109

def options(options)
  @options = options
  @use_editor = options[:editor]
  @watch_editor = options[:watch]
  @format = options[:format]
  raise "format #{@format} not known" unless %w{txt enml}.include?(@format)
end

#save_noteObject



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/rnote/noun/note/edit.rb', line 151

def save_note
  
  diff_note = @last_saved_note.diff(@note)
  
  # only update if necessary
  if diff_note
    
    # create or update
    if diff_note.guid
      @auth.client.note_store.updateNote(diff_note)
    else
      raise "cannot create note with nil content" if diff_note.content.nil?
      new_note = @auth.client.note_store.createNote(diff_note)
      # a few things to copy over
      @note.guid = new_note.guid
    end
    
    # track what the last version we saved was. for diffing
    @last_saved_note = @note.deep_dup
  end
  
end

#show_diff(original, altered) ⇒ Object

output both forms to a file, and run “diff | less”



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rnote/noun/note/edit.rb', line 175

def show_diff(original,altered)
  
  file1 = Tempfile.new('rnote')
  file2 = Tempfile.new('rnote')
  begin
    
    file1.write(original)
    file1.close
    
    file2.write(altered)
    file2.close
    
    system("diff #{file1.path} #{file2.path} | less")
      
    raise "User cnacelled due to lost content." unless agree("Continue editing note?  ")
      
  ensure
    file1.unlink
    file2.unlink
  end
end

#update_note_from_file(path) ⇒ Object



338
339
340
341
342
343
344
# File 'lib/rnote/noun/note/edit.rb', line 338

def update_note_from_file(path)
  
  yaml_stream = File.open(path,'r').read
  @note.set_yaml_stream(@format,yaml_stream)
  
  save_note
end