rnote 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/rnote +1 -4
- data/lib/rnote/cmd/create.rb +13 -3
- data/lib/rnote/cmd/edit.rb +6 -4
- data/lib/rnote/cmd/find.rb +7 -1
- data/lib/rnote/cmd/login.rb +2 -1
- data/lib/rnote/cmd/logout.rb +2 -1
- data/lib/rnote/cmd/remove.rb +5 -4
- data/lib/rnote/cmd/show.rb +15 -5
- data/lib/rnote/cmd/who.rb +2 -1
- data/lib/rnote/consumer.rb +1 -2
- data/lib/rnote/converter.rb +144 -73
- data/lib/rnote/edit.rb +115 -17
- data/lib/rnote/find.rb +1 -1
- data/lib/rnote/version.rb +1 -1
- metadata +3 -2
data/bin/rnote
CHANGED
@@ -6,7 +6,7 @@ include GLI::App
|
|
6
6
|
|
7
7
|
program_desc 'Evernote Command Line'
|
8
8
|
|
9
|
-
|
9
|
+
version Rnote::VERSION
|
10
10
|
|
11
11
|
desc 'prompt for input and run an editor when necessary'
|
12
12
|
default_value true
|
@@ -46,9 +46,6 @@ on_error do |exception|
|
|
46
46
|
elsif exception.instance_of?(Evernote::EDAM::Error::EDAMSystemException)
|
47
47
|
puts exception.error_message
|
48
48
|
true
|
49
|
-
elsif exception.class == Evernote::EDAM::Error::InvalidXmlError
|
50
|
-
puts exception.xml
|
51
|
-
true
|
52
49
|
else
|
53
50
|
true
|
54
51
|
end
|
data/lib/rnote/cmd/create.rb
CHANGED
@@ -6,10 +6,17 @@ require 'rnote/edit'
|
|
6
6
|
include GLI::App
|
7
7
|
|
8
8
|
|
9
|
-
|
9
|
+
d 'create a new note'
|
10
|
+
long_desc <<EOF
|
11
|
+
Create a new note and, optionally, launch an editor to provide its content
|
12
|
+
|
13
|
+
Unlike most commands, the command line arguments aren't used in a search.
|
14
|
+
Instead any command line arguments provided are used for the title of the new note.
|
15
|
+
EOF
|
10
16
|
command :create do |verb|
|
11
|
-
verb.command :note do |noun|
|
12
17
|
|
18
|
+
d 'create a new note'
|
19
|
+
verb.command :note do |noun|
|
13
20
|
|
14
21
|
Rnote::Edit.include_set_options(noun)
|
15
22
|
Rnote::Edit.include_editor_options(noun)
|
@@ -17,7 +24,10 @@ command :create do |verb|
|
|
17
24
|
noun.action do |global_options,options,args|
|
18
25
|
|
19
26
|
if args.length > 0
|
20
|
-
|
27
|
+
if options[:'set-title']
|
28
|
+
raise "You can't use both --set-title and command line arguments at the same time to set the title of the new note."
|
29
|
+
end
|
30
|
+
options[:'set-title'] = args.join(' ')
|
21
31
|
end
|
22
32
|
|
23
33
|
edit = Rnote::Edit.new($app.auth)
|
data/lib/rnote/cmd/edit.rb
CHANGED
@@ -4,11 +4,13 @@ require 'rnote/find'
|
|
4
4
|
|
5
5
|
include GLI::App
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# TODO why doesn't 'desc' work here instead of 'd'. What is over-riding it?
|
8
|
+
d 'edit/update a note'
|
9
|
+
long_desc 'Edit/update an existing note, usually by launching an editor.'
|
10
10
|
command :edit do |verb|
|
11
11
|
|
12
|
+
verb.desc "edit a note"
|
13
|
+
|
12
14
|
verb.command :note do |noun|
|
13
15
|
|
14
16
|
Rnote::Edit.include_set_options(noun)
|
@@ -19,7 +21,7 @@ command :edit do |verb|
|
|
19
21
|
|
20
22
|
find = Rnote::Find.new($app.auth,$app.persister)
|
21
23
|
note = find.find_note(options.merge(global_options),args)
|
22
|
-
|
24
|
+
|
23
25
|
edit = Rnote::Edit.new($app.auth)
|
24
26
|
edit.options(options.merge(global_options))
|
25
27
|
edit.note(note)
|
data/lib/rnote/cmd/find.rb
CHANGED
@@ -4,9 +4,15 @@ require 'rnote/find'
|
|
4
4
|
include GLI::App
|
5
5
|
|
6
6
|
|
7
|
-
|
7
|
+
d 'search for notes'
|
8
|
+
long_desc <<EOF
|
9
|
+
Provide a query and find matching notes. Provides a short summary of each note in the result.
|
10
|
+
|
11
|
+
You can run this command before running other commands that require a note to be selected, such as 'edit', or 'remove'. And then specify the result number on the next command line.
|
12
|
+
EOF
|
8
13
|
command :find do |verb|
|
9
14
|
|
15
|
+
verb.desc 'find notes'
|
10
16
|
verb.command :note do |noun|
|
11
17
|
|
12
18
|
Rnote::Find.include_search_options(noun)
|
data/lib/rnote/cmd/login.rb
CHANGED
@@ -3,7 +3,8 @@ require 'highline/import'
|
|
3
3
|
|
4
4
|
include GLI::App
|
5
5
|
|
6
|
-
|
6
|
+
d 'login to evernote'
|
7
|
+
long_desc 'Provide credentials and log a user into evernote. The users password is never saved, but an auth token will be.'
|
7
8
|
command :login do |c|
|
8
9
|
|
9
10
|
c.desc "username"
|
data/lib/rnote/cmd/logout.rb
CHANGED
@@ -11,7 +11,8 @@ but won't forget about a consumer key, as that by itself is not considered a log
|
|
11
11
|
|
12
12
|
=end
|
13
13
|
|
14
|
-
|
14
|
+
d 'logout user'
|
15
|
+
long_desc "Log a user out of evernote. This forgets any credential information that may have been cached. currently this does not revoke the token though. It simply forgets what the token was."
|
15
16
|
command :logout do |c|
|
16
17
|
c.action do |global_options,options,args|
|
17
18
|
raise unless args.length == 0
|
data/lib/rnote/cmd/remove.rb
CHANGED
@@ -6,10 +6,11 @@ include GLI::App
|
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
command :remove do |verb|
|
12
|
-
|
9
|
+
d 'remove a note'
|
10
|
+
long_desc "Remove a note, but don't expunge it. The note stays in the users Trash"
|
11
|
+
command :remove do |verb|
|
12
|
+
|
13
|
+
verb.desc 'remove a note'
|
13
14
|
verb.command :note do |noun|
|
14
15
|
|
15
16
|
Rnote::Find.include_search_options(noun)
|
data/lib/rnote/cmd/show.rb
CHANGED
@@ -4,27 +4,37 @@ require 'rnote/find'
|
|
4
4
|
include GLI::App
|
5
5
|
|
6
6
|
|
7
|
-
|
7
|
+
d 'show note content'
|
8
|
+
long_desc "output a note's content to the console."
|
8
9
|
command :show do |verb|
|
9
10
|
|
10
|
-
verb.desc
|
11
|
+
verb.desc "output a note's content"
|
11
12
|
verb.command :note do |noun|
|
12
13
|
|
13
14
|
Rnote::Find.include_search_options(noun)
|
14
15
|
|
15
16
|
noun.desc 'include title in the output'
|
16
17
|
noun.default_value true
|
17
|
-
noun.switch :'include-title', :'inc-title'
|
18
|
+
noun.switch :'include-title', :'inc-title', :'output-title', :'show-title'
|
19
|
+
|
20
|
+
noun.desc 'which format to output? (txt or enml)'
|
21
|
+
noun.default_value 'txt'
|
22
|
+
noun.flag :format
|
18
23
|
|
19
24
|
noun.action do |global_options,options,args|
|
20
25
|
|
21
26
|
find = Rnote::Find.new($app.auth,$app.persister)
|
22
27
|
note = find.find_note(options.merge(global_options),args)
|
23
28
|
|
24
|
-
content = note.txt_content
|
25
29
|
|
26
30
|
puts note.title if options[:'include-title']
|
27
|
-
|
31
|
+
if options[:format] == 'txt'
|
32
|
+
puts note.txt_content
|
33
|
+
elsif options[:format] == 'enml'
|
34
|
+
puts note.content
|
35
|
+
else
|
36
|
+
raise "Unknown outoput format specified."
|
37
|
+
end
|
28
38
|
|
29
39
|
end
|
30
40
|
|
data/lib/rnote/cmd/who.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
|
2
2
|
include GLI::App
|
3
3
|
|
4
|
-
|
4
|
+
d 'which user is logged in'
|
5
|
+
long_desc 'see what username is logged in, or if your using a developer token instead of a username.'
|
5
6
|
command :who do |c|
|
6
7
|
c.action do |global_options,options,args|
|
7
8
|
raise unless args.length == 0
|
data/lib/rnote/consumer.rb
CHANGED
data/lib/rnote/converter.rb
CHANGED
@@ -4,94 +4,160 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
require 'evernote-thrift'
|
6
6
|
|
7
|
-
module Evernote::EDAM::Error
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
8
|
+
# converting between text formats and enml
|
9
|
+
#
|
10
|
+
# we have two types of conversion
|
11
|
+
#
|
12
|
+
# simple,
|
13
|
+
# single document conversion.
|
14
|
+
# which is enml <=> txt
|
15
|
+
#
|
16
|
+
# then our own additional wrappers we put on top of those 2 document types
|
17
|
+
# adding metadata to them.
|
18
|
+
# yaml_stream <=> notes attributes
|
19
|
+
# content is just considered an 'attribute' in the latter
|
20
|
+
#
|
21
|
+
# the yaml_stream is just a string
|
22
|
+
# the note attributes get its own class and thats where we stick the conversion routines.
|
23
|
+
|
24
|
+
class Evernote::EDAM::Type::Note
|
25
|
+
|
26
|
+
# simple xhtml to txt converter
|
27
|
+
# just tries to convert evernotes simple xhtml.
|
28
|
+
# the kind its own editors create. Which doesn't involve much nesting.
|
29
|
+
class EnmlDocument < Nokogiri::XML::SAX::Document # Nokogiri SAX parser
|
30
|
+
|
31
|
+
attr_accessor :_txt, :in_div, :in_pre
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@_txt = ''
|
35
|
+
@in_div = false
|
36
|
+
@in_pre = false
|
37
|
+
super
|
38
|
+
end
|
29
39
|
|
30
|
-
|
40
|
+
def characters string
|
41
|
+
|
42
|
+
if ! self.in_div and ! self.in_pre and string == "\n"
|
43
|
+
# ignore lone newlines that occur outside a div
|
44
|
+
else
|
45
|
+
self._txt << string
|
46
|
+
end
|
47
|
+
end
|
31
48
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
49
|
+
def start_element name, attrs = []
|
50
|
+
case name
|
51
|
+
when 'en-todo'
|
52
|
+
if Hash[attrs]['checked'] == 'true'
|
53
|
+
self._txt << '[X]'
|
54
|
+
else
|
55
|
+
self._txt << '[ ]'
|
56
|
+
end
|
57
|
+
when 'div'
|
58
|
+
self.in_div = true
|
59
|
+
when 'pre'
|
60
|
+
self.in_pre = true
|
61
|
+
else
|
62
|
+
# nothing
|
63
|
+
end
|
35
64
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
65
|
+
|
66
|
+
def end_element name
|
67
|
+
case name
|
68
|
+
when 'div'
|
69
|
+
self.in_div = false
|
70
|
+
# a newline for every div (whether its got a <br> in it or not)
|
71
|
+
self._txt << "\n"
|
72
|
+
when 'pre'
|
73
|
+
self.in_pre = false
|
74
|
+
when 'br'
|
75
|
+
# ignore it, as its always in a div, and every div will be a newline anyways
|
76
|
+
else
|
77
|
+
# nothing
|
78
|
+
end
|
42
79
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
def self.enml_to_markdown(enml)
|
50
|
-
enml_to_txt(enml)
|
80
|
+
|
81
|
+
def txt
|
82
|
+
# always remove the last newline. to match up with WYSIWYG interfaces.
|
83
|
+
self._txt.chomp
|
84
|
+
end
|
85
|
+
|
51
86
|
end
|
52
87
|
|
53
|
-
|
54
|
-
txt_to_enml(markdown)
|
55
|
-
end
|
56
|
-
|
57
|
-
def markdown_content=(markdown_content)
|
58
|
-
self.content = self.class.markdown_to_enml(markdown_content)
|
59
|
-
end
|
60
|
-
|
61
|
-
def markdown_content
|
62
|
-
self.class.enml_to_markdown(content)
|
63
|
-
end
|
64
|
-
|
88
|
+
|
65
89
|
def self.enml_to_txt(enml)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
90
|
+
raise 'not given xml' if ! enml.start_with? '<?xml'
|
91
|
+
|
92
|
+
sax_document = EnmlDocument.new
|
93
|
+
parser = Nokogiri::XML::SAX::Parser.new(sax_document)
|
94
|
+
parser.parse(enml)
|
95
|
+
|
96
|
+
enml = sax_document.txt
|
97
|
+
|
98
|
+
enml
|
74
99
|
end
|
75
100
|
|
76
101
|
def self.txt_to_enml(txt)
|
77
|
-
if txt.start_with? '<?xml'
|
78
|
-
|
79
|
-
|
102
|
+
raise 'given xml instead of txt' if txt.start_with? '<?xml'
|
103
|
+
|
104
|
+
# TODO create a proper DOM, with proper xml entity escapes and tag structure
|
105
|
+
|
106
|
+
# escape any entities
|
107
|
+
txt.gsub!('<','<')
|
108
|
+
txt.gsub!('>','>')
|
109
|
+
|
110
|
+
# replace todo items
|
111
|
+
txt.gsub!('[ ]','<en-todo checked="false"/>')
|
112
|
+
txt.gsub!('[X]','<en-todo checked="true"/>')
|
113
|
+
|
114
|
+
# every newline becomes a <div></div>
|
115
|
+
# an empty line becomes a <div><br/></div>
|
116
|
+
|
117
|
+
lines = txt.split("\n",-1)
|
118
|
+
lines = [''] if txt == ''
|
119
|
+
raise if lines.length == 0
|
120
|
+
|
121
|
+
xhtml = lines.map { |string|
|
122
|
+
if string == ''
|
123
|
+
"<div><br/></div>\n"
|
124
|
+
else
|
125
|
+
"<div>#{string}</div>\n"
|
126
|
+
end
|
127
|
+
}.join('')
|
128
|
+
|
80
129
|
<<EOF
|
81
130
|
<?xml version='1.0' encoding='utf-8'?>
|
82
131
|
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
|
83
132
|
<en-note>
|
84
|
-
|
85
|
-
</en-note>
|
133
|
+
#{xhtml}</en-note>
|
86
134
|
EOF
|
87
135
|
end
|
88
136
|
|
89
|
-
def
|
90
|
-
|
137
|
+
def self.enml_to_format(format,enml)
|
138
|
+
case format
|
139
|
+
when 'enml'
|
140
|
+
enml
|
141
|
+
when 'txt'
|
142
|
+
enml_to_txt(enml)
|
143
|
+
else
|
144
|
+
raise
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.format_to_enml(format,formatted_content)
|
149
|
+
case format
|
150
|
+
when 'enml'
|
151
|
+
formatted_content
|
152
|
+
when 'txt'
|
153
|
+
txt_to_enml(formatted_content)
|
154
|
+
else
|
155
|
+
raise
|
156
|
+
end
|
91
157
|
end
|
92
158
|
|
93
159
|
def txt_content
|
94
|
-
self.class.
|
160
|
+
self.class.enml_to_format('txt',self.content)
|
95
161
|
end
|
96
162
|
|
97
163
|
# The yaml stream is what we give to the user to edit in their editor
|
@@ -99,25 +165,30 @@ EOF
|
|
99
165
|
# Its just a string, but its composed of 2 parts. the note attributes and the note content.
|
100
166
|
#
|
101
167
|
# 1. a small yaml document with the note attributes as a hash.
|
102
|
-
# 2. followed by the note content as
|
103
|
-
def
|
168
|
+
# 2. followed by the note content as txt
|
169
|
+
def set_yaml_stream(format,yaml_stream)
|
104
170
|
|
105
171
|
m = yaml_stream.match /^(---.+?---\n)(.*)$/m
|
106
172
|
raise "failed to parse yaml stream\n#{yaml_stream}" unless m
|
107
173
|
|
108
174
|
attributes_yaml = m[1]
|
109
|
-
|
175
|
+
txt = m[2]
|
110
176
|
|
111
|
-
enml = self.class.
|
177
|
+
enml = self.class.format_to_enml(format,txt)
|
112
178
|
attributes_hash = YAML.load(attributes_yaml)
|
179
|
+
|
180
|
+
# process tag names
|
181
|
+
# allow for comma separated tag list
|
182
|
+
tag_names = attributes_hash['tagNames']
|
183
|
+
tag_names = tag_names.split(/\s*,\s*/) if tag_names.instance_of?(String)
|
113
184
|
|
114
185
|
self.title = attributes_hash['title']
|
115
186
|
self.tagNames = attributes_hash['tagNames']
|
116
187
|
self.content = enml
|
117
188
|
end
|
118
189
|
|
119
|
-
def yaml_stream
|
120
|
-
YAML.dump({ 'title' => title, 'tagNames' => tagNames }) + "\n---\n" + self.class.
|
190
|
+
def yaml_stream(format)
|
191
|
+
YAML.dump({ 'title' => title, 'tagNames' => tagNames }) + "\n---\n" + self.class.enml_to_format(format,content)
|
121
192
|
end
|
122
193
|
|
123
194
|
def summarize
|
data/lib/rnote/edit.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
|
2
2
|
require 'highline'
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'tempfile'
|
4
5
|
|
5
6
|
class WaitPidTimeout
|
6
7
|
|
@@ -77,7 +78,7 @@ module Rnote
|
|
77
78
|
def initialize(auth)
|
78
79
|
@auth = auth
|
79
80
|
@note = Evernote::EDAM::Type::Note.new
|
80
|
-
@note.
|
81
|
+
@note.content = @note.class.format_to_enml('txt','') # for creating new notes.
|
81
82
|
@last_saved_note = Evernote::EDAM::Type::Note.new
|
82
83
|
end
|
83
84
|
|
@@ -94,6 +95,10 @@ module Rnote
|
|
94
95
|
noun.desc 'open an interactive editor to modify the note'
|
95
96
|
noun.default_value true
|
96
97
|
noun.switch :editor
|
98
|
+
|
99
|
+
noun.desc 'which format do you want to edit the note in? default is "txt", other option is "enml"'
|
100
|
+
noun.default_value 'txt'
|
101
|
+
noun.flag :format
|
97
102
|
end
|
98
103
|
|
99
104
|
def Edit.has_set_options(options)
|
@@ -104,6 +109,8 @@ module Rnote
|
|
104
109
|
@options = options
|
105
110
|
@use_editor = options[:editor]
|
106
111
|
@watch_editor = options[:watch]
|
112
|
+
@format = options[:format]
|
113
|
+
raise "format #{@format} not known" unless %w{txt enml}.include?(@format)
|
107
114
|
end
|
108
115
|
|
109
116
|
def note(note)
|
@@ -162,16 +169,104 @@ module Rnote
|
|
162
169
|
end
|
163
170
|
|
164
171
|
end
|
172
|
+
|
173
|
+
# output both forms to a file, and run "diff | less"
|
174
|
+
def show_diff(original,altered)
|
175
|
+
|
176
|
+
file1 = Tempfile.new('rnote')
|
177
|
+
file2 = Tempfile.new('rnote')
|
178
|
+
begin
|
179
|
+
|
180
|
+
file1.write(original)
|
181
|
+
file1.close
|
182
|
+
|
183
|
+
file2.write(altered)
|
184
|
+
file2.close
|
185
|
+
|
186
|
+
system("diff #{file1.path} #{file2.path} | less")
|
187
|
+
|
188
|
+
raise "User cnacelled due to lost content." unless agree("Continue editing note? ")
|
189
|
+
|
190
|
+
ensure
|
191
|
+
file1.unlink
|
192
|
+
file2.unlink
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# check if we lose content/formating when converting the note
|
197
|
+
# and if so ask the user if they want to continue.
|
198
|
+
def check_for_lost_content
|
199
|
+
|
200
|
+
converted_content = @note.class.enml_to_format(@format, @note.content)
|
201
|
+
unconverted_content = @note.class.format_to_enml(@format, converted_content)
|
202
|
+
|
203
|
+
if @note.content != unconverted_content
|
204
|
+
puts "Some content or formatting may be lost in the note due to editing format conversion."
|
205
|
+
reply_continue = ask("Continue editing the note? (yes/no/diff) ") { |q|
|
206
|
+
q.validate = /\A(y|n|d|q|e|c|yes|no|cancel|quit|exit|diff)\Z/i
|
207
|
+
q.responses[:not_valid] = 'Please enter "yes", "no", "diff", or "cancel".'
|
208
|
+
q.responses[:ask_on_error] = :question
|
209
|
+
}
|
210
|
+
|
211
|
+
case reply_continue.downcase
|
212
|
+
when 'y'
|
213
|
+
# nothing, continue
|
214
|
+
when 'yes'
|
215
|
+
# nothing, continue
|
216
|
+
when 'n'
|
217
|
+
raise "User cancelled due to lost content."
|
218
|
+
when 'no'
|
219
|
+
raise "User cancelled due to lost content."
|
220
|
+
when 'cancel'
|
221
|
+
raise "User cancelled due to lost content."
|
222
|
+
when 'quit'
|
223
|
+
raise "User cancelled due to lost content."
|
224
|
+
when 'exit'
|
225
|
+
raise "User cancelled due to lost content."
|
226
|
+
when 'diff'
|
227
|
+
show_diff(@note.content,converted_content)
|
228
|
+
else
|
229
|
+
raise
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def md5(filename)
|
237
|
+
# TODO sloppy, switch with non shell command
|
238
|
+
`cat #{filename} | md5`.chomp
|
239
|
+
end
|
240
|
+
|
241
|
+
# has the file changed since the last time we checked.
|
242
|
+
def has_file_changed(file)
|
243
|
+
|
244
|
+
@last_mtime ||= nil
|
245
|
+
@last_md5 ||= nil
|
246
|
+
|
247
|
+
this_mtime = File.mtime(file.path)
|
248
|
+
this_md5 = md5(file.path)
|
249
|
+
|
250
|
+
changed = this_mtime != @last_mtime && this_md5 != @last_md5
|
251
|
+
|
252
|
+
@last_mtime = this_mtime
|
253
|
+
@last_md5 = this_md5
|
254
|
+
|
255
|
+
changed
|
256
|
+
end
|
257
|
+
|
165
258
|
|
166
259
|
def editor
|
167
260
|
|
168
261
|
ENV['EDITOR'] ||= 'vim'
|
262
|
+
|
263
|
+
check_for_lost_content
|
169
264
|
|
170
|
-
file = Tempfile.new(['rnote','
|
265
|
+
file = Tempfile.new(['rnote','.' + @format])
|
171
266
|
begin
|
172
267
|
|
173
268
|
# fill the tempfile with the yaml stream
|
174
|
-
yaml_stream = @note.yaml_stream
|
269
|
+
yaml_stream = @note.yaml_stream(@format)
|
175
270
|
file.write(yaml_stream)
|
176
271
|
file.close()
|
177
272
|
|
@@ -179,7 +274,7 @@ module Rnote
|
|
179
274
|
successful_edit = false
|
180
275
|
until successful_edit do
|
181
276
|
|
182
|
-
|
277
|
+
has_file_changed(file) # initialize the file change tracking.
|
183
278
|
|
184
279
|
# run editor in background
|
185
280
|
pid = fork do
|
@@ -200,31 +295,34 @@ module Rnote
|
|
200
295
|
# timeout exceeded
|
201
296
|
|
202
297
|
# has the file changed?
|
203
|
-
|
204
|
-
if this_mtime != last_mtime
|
298
|
+
if has_file_changed(file)
|
205
299
|
# protect the running editor from our failures.
|
206
300
|
begin
|
207
301
|
update_note_from_file(file.path)
|
208
302
|
rescue Exception => e
|
209
303
|
$stderr.puts "rnote: an error occured while updating the note: #{e.message}"
|
210
304
|
end
|
211
|
-
last_mtime = this_mtime
|
212
305
|
end
|
213
306
|
end
|
214
307
|
end
|
215
308
|
|
216
309
|
# one last update of the note
|
217
310
|
# this time we care if there are errors
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
311
|
+
if has_file_changed(file)
|
312
|
+
begin
|
313
|
+
update_note_from_file(file.path)
|
314
|
+
rescue Exception => e
|
315
|
+
|
316
|
+
puts "There was an error while uploading the note"
|
317
|
+
puts e.message
|
318
|
+
puts e.backtrace.join("\n ")
|
319
|
+
|
320
|
+
successful_edit = ! agree("Return to editor? (otherwise changes will be lost) ")
|
321
|
+
else
|
322
|
+
successful_edit = true
|
323
|
+
end
|
227
324
|
else
|
325
|
+
# no changes to file, no need to save.
|
228
326
|
successful_edit = true
|
229
327
|
end
|
230
328
|
|
@@ -239,7 +337,7 @@ module Rnote
|
|
239
337
|
def update_note_from_file(path)
|
240
338
|
|
241
339
|
yaml_stream = File.open(path,'r').read
|
242
|
-
@note.yaml_stream
|
340
|
+
@note.set_yaml_stream(@format,yaml_stream)
|
243
341
|
|
244
342
|
save_note
|
245
343
|
end
|
data/lib/rnote/find.rb
CHANGED
@@ -101,7 +101,7 @@ module Rnote
|
|
101
101
|
# no search options, one argument, and its a small number
|
102
102
|
# they are asking to pick from the last search results
|
103
103
|
guids = @persister.get_last_search_guids
|
104
|
-
guid = guids[args[0].to_i] # the chosen note
|
104
|
+
guid = guids[args[0].to_i - 1] # the chosen note
|
105
105
|
note = get_full_note(guid)
|
106
106
|
results = [note] # fake a result set with it.
|
107
107
|
else
|
data/lib/rnote/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rnote
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -231,3 +231,4 @@ signing_key:
|
|
231
231
|
specification_version: 3
|
232
232
|
summary: CLI to Evernote
|
233
233
|
test_files: []
|
234
|
+
has_rdoc: true
|