jota 0.8.0
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/INSTALL +145 -0
- data/bin/jota +12 -0
- data/bin/jotacli +12 -0
- data/lib/app_error.rb +5 -0
- data/lib/cli.rb +277 -0
- data/lib/clip.rb +137 -0
- data/lib/clip_array.rb +393 -0
- data/lib/gui.rb +792 -0
- data/lib/helper.rb +129 -0
- data/lib/jota.glade +730 -0
- data/lib/jota.rb +176 -0
- data/lib/preferences.rb +83 -0
- data/lib/svn_info.rb +16 -0
- data/lib/version.rb +59 -0
- data/tests/test_all.rb +10 -0
- data/tests/test_clip.rb +172 -0
- data/tests/test_clip_array.rb +177 -0
- data/tests/test_preferences.rb +185 -0
- metadata +81 -0
data/INSTALL
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
|
2
|
+
$Id: INSTALL 37 2009-02-09 10:06:02Z dz $
|
3
|
+
|
4
|
+
Jota is a written in the Ruby programming language and uses GTK+ Widgets.
|
5
|
+
|
6
|
+
To set up a working run time environment to have to install the
|
7
|
+
following packages:
|
8
|
+
|
9
|
+
- Ruby interpreter often already installed
|
10
|
+
- GTK+ libraries comes with Gnome, you probably have it already
|
11
|
+
- libglade a library for loadable user interfaces
|
12
|
+
part of the GTK+ project
|
13
|
+
- Ruby bindings for GTK+ and libglade
|
14
|
+
- Ruby Gems the Ruby packet manager
|
15
|
+
|
16
|
+
If you want to use the command line version of Jota, you will need the
|
17
|
+
'Cmd' gem: gem install cmd
|
18
|
+
|
19
|
+
|
20
|
+
PREREQUISITES
|
21
|
+
-------------
|
22
|
+
|
23
|
+
For the common operating systems you can use the following command:
|
24
|
+
|
25
|
+
* Ubuntu/Debian
|
26
|
+
|
27
|
+
% apt-get install libglade2-ruby1.8 rubygems
|
28
|
+
|
29
|
+
|
30
|
+
* FreeBSD
|
31
|
+
|
32
|
+
% portinstall ruby18-libglade2 ruby18-gems
|
33
|
+
|
34
|
+
or
|
35
|
+
|
36
|
+
% cd /usr/ports/devel/ruby-libglade2
|
37
|
+
% make
|
38
|
+
% make install
|
39
|
+
|
40
|
+
|
41
|
+
* Fedora (unfinished)
|
42
|
+
|
43
|
+
% yum install ...
|
44
|
+
|
45
|
+
|
46
|
+
* OpenSUSE
|
47
|
+
|
48
|
+
Does not work for 11.0, probably 10.0 and maybe 11.1. Sorry!
|
49
|
+
|
50
|
+
At first, install the packages ruby and rubygems from the standard SUSE
|
51
|
+
repositories. Because the other GTK+ related packages that you will
|
52
|
+
need are not in these repositories, you have to fetch and install the
|
53
|
+
RPMs manually. Read
|
54
|
+
http://ruby-gnome2.sourceforge.jp/hiki.cgi?Install+Guide+for+SUSE
|
55
|
+
and fetch the tgz, e.g.
|
56
|
+
|
57
|
+
% wget http://franz.hob-bruneck.info/downloads/suse100/ruby-gnome2/0.14.1/\
|
58
|
+
ruby-gnome2-0.14.1.suse100.tar.gz
|
59
|
+
|
60
|
+
Create a temporary directory somewhere
|
61
|
+
|
62
|
+
% mkdir opensuse.tmp
|
63
|
+
% cd opensuse.tmp
|
64
|
+
|
65
|
+
Unpack and install the necessary RPMs
|
66
|
+
|
67
|
+
% tar xvfz ../ruby-gnome2*.tar.gz
|
68
|
+
% rpm -i ruby-glib2*
|
69
|
+
% rpm -i ruby-atk*
|
70
|
+
% rpm -i ruby-pango*
|
71
|
+
% rpm -i --nodeps ruby-gdkpixbuf2*
|
72
|
+
% rpm -i ruby-gtk2*
|
73
|
+
% rpm -i ruby-libglade2*
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
* Windows
|
78
|
+
|
79
|
+
Windows of course has no sophisticated package management. You have to
|
80
|
+
download and install the following by hand.
|
81
|
+
|
82
|
+
Go to http://ruby-gnome2.sourceforge.jp/#Ruby-GNOME2+Win32+GUI+Installer
|
83
|
+
and follow the three steps. In short:
|
84
|
+
|
85
|
+
1. install http://rubyforge.org/frs/download.php/17357/ruby185-22.exe
|
86
|
+
(enable RubyGems)
|
87
|
+
2. install http://prdownloads.sourceforge.net/ruby-gnome2/ruby-gnome2-0.16.0-1-i386-mswin32.exe?download
|
88
|
+
|
89
|
+
|
90
|
+
INSTALLING
|
91
|
+
----------
|
92
|
+
|
93
|
+
Now install Jota as a ruby gem:
|
94
|
+
|
95
|
+
gem install jota
|
96
|
+
|
97
|
+
alternatively, download jota-$VERSION.gem and install it with
|
98
|
+
|
99
|
+
gem install jota-$VERSION.gem
|
100
|
+
|
101
|
+
If you get the error "ERROR: While executing gem ... (RuntimeError)" and
|
102
|
+
"jota requires cmd >= 0.7.2", you have an older version of gems that does not
|
103
|
+
resolve dependencies on its own.
|
104
|
+
|
105
|
+
So you have to
|
106
|
+
|
107
|
+
gem install cmd
|
108
|
+
|
109
|
+
before
|
110
|
+
|
111
|
+
gem install jota
|
112
|
+
|
113
|
+
(Only if you want to use joacli)
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
RUNNING
|
118
|
+
-------
|
119
|
+
|
120
|
+
Unix:
|
121
|
+
|
122
|
+
Normally, binaries installed through gems should be in the path, so you
|
123
|
+
can simply invoke Jota with the command jota
|
124
|
+
|
125
|
+
If the binary is not in the path, you have to find out the full pathname.
|
126
|
+
This is gems dependant. For Ubuntu Linux, the full name is
|
127
|
+
/var/lib/gems/1.8/bin/jota
|
128
|
+
|
129
|
+
Windows:
|
130
|
+
|
131
|
+
You can run Jota through: Start->Execute: "Jota" or create a shortcut and
|
132
|
+
point it to C:\Ruby\bin\jota.cmd
|
133
|
+
|
134
|
+
|
135
|
+
UPDATING
|
136
|
+
--------
|
137
|
+
|
138
|
+
gem update jota
|
139
|
+
|
140
|
+
or
|
141
|
+
|
142
|
+
gem uninstall jota
|
143
|
+
gem install jota
|
144
|
+
gem cleanup jota
|
145
|
+
|
data/bin/jota
ADDED
data/bin/jotacli
ADDED
data/lib/app_error.rb
ADDED
data/lib/cli.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
|
2
|
+
# $Id: cli.rb 37 2009-02-09 10:06:02Z dz $
|
3
|
+
|
4
|
+
# if you use vim and don't like folds type zR
|
5
|
+
|
6
|
+
require 'clip'
|
7
|
+
require 'clip_array'
|
8
|
+
require 'preferences'
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'cmd'
|
12
|
+
rescue LoadError
|
13
|
+
require 'rubygems'
|
14
|
+
require 'cmd'
|
15
|
+
end
|
16
|
+
|
17
|
+
class JotaCli < Cmd
|
18
|
+
|
19
|
+
require 'tempfile'
|
20
|
+
prompt_with :prompt_command
|
21
|
+
|
22
|
+
doc :open, "Open clip file"
|
23
|
+
doc :close, "Close clip file"
|
24
|
+
doc :create, "Create a new empty clip file"
|
25
|
+
doc :list, "List clips with type, index number and title"
|
26
|
+
doc :edit, "Edit clip with $EDITOR (or /usr/bin/vi if not set)"
|
27
|
+
doc :show, "Show contents of clip"
|
28
|
+
doc :new, "Create a new clip"
|
29
|
+
doc :delete, "Delete a clip"
|
30
|
+
doc :default, "Set default command"
|
31
|
+
doc :page, "Show content of clip through $PAGER"
|
32
|
+
|
33
|
+
|
34
|
+
def do_open(args)
|
35
|
+
#{{{1
|
36
|
+
filename = args.to_s
|
37
|
+
@data.close if @data
|
38
|
+
begin
|
39
|
+
@data = ClipArray.open(filename)
|
40
|
+
rescue SystemCallError, AppError => msg
|
41
|
+
puts msg
|
42
|
+
@data = nil
|
43
|
+
end
|
44
|
+
end #}}}1
|
45
|
+
|
46
|
+
def do_close
|
47
|
+
#{{{1
|
48
|
+
return if @data.nil?
|
49
|
+
|
50
|
+
@data.close
|
51
|
+
@data = nil
|
52
|
+
end #}}}1
|
53
|
+
|
54
|
+
def do_create(args)
|
55
|
+
#{{{1
|
56
|
+
filename = args.to_s
|
57
|
+
@data.close if @data
|
58
|
+
begin
|
59
|
+
@data = ClipArray.create(filename)
|
60
|
+
rescue AppError => msg
|
61
|
+
puts msg
|
62
|
+
@data = nil
|
63
|
+
end
|
64
|
+
end #}}}1
|
65
|
+
|
66
|
+
def do_list
|
67
|
+
#{{{1
|
68
|
+
return if @data.nil?
|
69
|
+
|
70
|
+
@data.each_index do | i |
|
71
|
+
print "%2d %s %s\n" % [
|
72
|
+
i+1,
|
73
|
+
type_to_char(@data[i].type),
|
74
|
+
@data[i].title]
|
75
|
+
end
|
76
|
+
end #}}}1
|
77
|
+
|
78
|
+
def do_edit(args)
|
79
|
+
#{{{1
|
80
|
+
index = get_index(args)
|
81
|
+
return if index.nil?
|
82
|
+
|
83
|
+
file = Tempfile.new("jotacli")
|
84
|
+
filename = file.path
|
85
|
+
print_verbose "creating temporary file '#{filename}'"
|
86
|
+
|
87
|
+
file.puts @data[index].title
|
88
|
+
file.puts @data[index].data
|
89
|
+
file.close
|
90
|
+
|
91
|
+
if ENV["EDITOR"] then
|
92
|
+
cmdline = ENV["EDITOR"]
|
93
|
+
else
|
94
|
+
cmdline = "/usr/bin/vi"
|
95
|
+
end
|
96
|
+
cmdline = "%s %s" % [cmdline, filename]
|
97
|
+
print_verbose "executing '#{cmdline}'"
|
98
|
+
|
99
|
+
if system(cmdline) then
|
100
|
+
file = File.open(filename,"r")
|
101
|
+
lines = file.readlines
|
102
|
+
@data[index].title = lines[0].chomp
|
103
|
+
@data[index].data = lines[1..lines.length-1].join("")
|
104
|
+
file.close
|
105
|
+
else
|
106
|
+
puts "Error executing '#{cmdline}' with exit code #{$?}"
|
107
|
+
end
|
108
|
+
|
109
|
+
File.unlink(filename)
|
110
|
+
|
111
|
+
# because of this save we do not not need autosave for the cli version
|
112
|
+
@data.save
|
113
|
+
end #}}}1
|
114
|
+
|
115
|
+
def do_show(args)
|
116
|
+
#{{{1
|
117
|
+
index = get_index(args)
|
118
|
+
return if index.nil?
|
119
|
+
|
120
|
+
puts @data[index].title
|
121
|
+
puts @data[index].data
|
122
|
+
end #}}}1
|
123
|
+
|
124
|
+
def do_delete(args)
|
125
|
+
#{{{1
|
126
|
+
index = get_index(args)
|
127
|
+
return if index.nil?
|
128
|
+
|
129
|
+
@data.current_index = index
|
130
|
+
|
131
|
+
if pref("deletesave_enable") and not @data.current.empty? then
|
132
|
+
deletefile = expand_filename(pref("deletesave_file"),
|
133
|
+
@data.dirname, @data.filename)
|
134
|
+
end
|
135
|
+
|
136
|
+
begin
|
137
|
+
@data.current.append_as_mbox(deletefile)
|
138
|
+
rescue SystemCallError => msg
|
139
|
+
puts msg
|
140
|
+
end
|
141
|
+
|
142
|
+
@data.delete
|
143
|
+
end #}}}1
|
144
|
+
|
145
|
+
def do_new
|
146
|
+
#{{{1
|
147
|
+
return if @data.nil?
|
148
|
+
|
149
|
+
@data.new
|
150
|
+
end #}}}1
|
151
|
+
|
152
|
+
def do_page(args)
|
153
|
+
#{{{1
|
154
|
+
index = get_index(args)
|
155
|
+
return if index.nil?
|
156
|
+
|
157
|
+
file = Tempfile.new("jotacli")
|
158
|
+
filename = file.path
|
159
|
+
print_verbose "creating temporary file '#{filename}'"
|
160
|
+
|
161
|
+
file.puts @data[index].title
|
162
|
+
file.puts @data[index].data
|
163
|
+
file.close
|
164
|
+
|
165
|
+
if ENV["PAGER"] then
|
166
|
+
cmdline = ENV["PAGER"]
|
167
|
+
else
|
168
|
+
cmdline = "/bin/more"
|
169
|
+
end
|
170
|
+
cmdline = "%s %s" % [cmdline, filename]
|
171
|
+
print_verbose "executing '#{cmdline}'"
|
172
|
+
|
173
|
+
if not system(cmdline) then
|
174
|
+
puts "Error executing '#{cmdline}' with exit code #{$?}"
|
175
|
+
end
|
176
|
+
|
177
|
+
File.unlink(filename)
|
178
|
+
end #}}}1
|
179
|
+
|
180
|
+
def do_default(args)
|
181
|
+
#{{{1
|
182
|
+
if args.nil? or args == "" then
|
183
|
+
puts "Default command is '#{@default_command}'"
|
184
|
+
elsif args =~ /^(show|edit|page)$/ then
|
185
|
+
@default_command = args
|
186
|
+
else
|
187
|
+
puts "Illegal default command. Valid are show, edit, and page"
|
188
|
+
end
|
189
|
+
end #}}}1
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def setup
|
194
|
+
#{{{1
|
195
|
+
puts "#{Version::PROGRAM_NAME} #{Version::STRING} ready"
|
196
|
+
puts "Type 'help' for commands"
|
197
|
+
|
198
|
+
@data = nil
|
199
|
+
@default_command = "page"
|
200
|
+
end #}}}1
|
201
|
+
|
202
|
+
def command_missing(command, args)
|
203
|
+
#{{{1
|
204
|
+
case @default_command
|
205
|
+
when "show"
|
206
|
+
do_show(command)
|
207
|
+
when "edit"
|
208
|
+
do_edit(command)
|
209
|
+
when "page"
|
210
|
+
do_page(command)
|
211
|
+
end
|
212
|
+
end #}}}1
|
213
|
+
|
214
|
+
def prompt_command
|
215
|
+
#{{{1
|
216
|
+
if @data.nil? then
|
217
|
+
"> "
|
218
|
+
else
|
219
|
+
@data.filename+"> "
|
220
|
+
end
|
221
|
+
end #}}}1
|
222
|
+
|
223
|
+
def postloop
|
224
|
+
#{{{1
|
225
|
+
@data.save if @data
|
226
|
+
end #}}}1
|
227
|
+
|
228
|
+
def type_to_char(t)
|
229
|
+
#{{{1
|
230
|
+
case t
|
231
|
+
when :text
|
232
|
+
return "t"
|
233
|
+
when :pref
|
234
|
+
return "p"
|
235
|
+
else
|
236
|
+
return "?"
|
237
|
+
end
|
238
|
+
end #}}}1
|
239
|
+
|
240
|
+
def get_index(str)
|
241
|
+
#{{{1
|
242
|
+
return nil if @data.nil? or str.nil?
|
243
|
+
|
244
|
+
if str =~ /^\d+$/ then
|
245
|
+
result = str.to_i - 1
|
246
|
+
else
|
247
|
+
result = nil
|
248
|
+
re = Regexp.new(str,Regexp::IGNORECASE)
|
249
|
+
@data.each_index do | i |
|
250
|
+
if @data[i].title.match(re) then
|
251
|
+
result = i
|
252
|
+
break
|
253
|
+
end
|
254
|
+
end
|
255
|
+
if result.nil? then
|
256
|
+
return nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
if result < 0 or result >= @data.length then
|
260
|
+
return nil
|
261
|
+
else
|
262
|
+
return result
|
263
|
+
end
|
264
|
+
end #}}}1
|
265
|
+
|
266
|
+
def pref(key)
|
267
|
+
#{{{1
|
268
|
+
if @data.nil? then
|
269
|
+
return Preferences.defaults[key]
|
270
|
+
else
|
271
|
+
@data.pref[key]
|
272
|
+
end
|
273
|
+
end #}}}1
|
274
|
+
|
275
|
+
end # class
|
276
|
+
|
277
|
+
# vim600: set foldmethod=marker:
|
data/lib/clip.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
|
2
|
+
# $Id: clip.rb 37 2009-02-09 10:06:02Z dz $
|
3
|
+
|
4
|
+
# if you use vim and don't like folds type zR
|
5
|
+
|
6
|
+
require 'time'
|
7
|
+
require 'version'
|
8
|
+
|
9
|
+
class Clip
|
10
|
+
|
11
|
+
|
12
|
+
# Instance Variables
|
13
|
+
# data String "" text (*every* line ends with an LF)
|
14
|
+
# wrap Boolean false line wrap?
|
15
|
+
# type Symbol :text :text, :pref
|
16
|
+
# title String "" first line of clip (without LF)
|
17
|
+
# created Time now creation time
|
18
|
+
# pos Int 0 saved cursor position
|
19
|
+
|
20
|
+
|
21
|
+
attr_accessor :wrap, :title, :created, :pos, :type, :data
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
#{{{1
|
25
|
+
@data = "" # no lines at all, "\n" would be 1 empty line
|
26
|
+
@wrap = false
|
27
|
+
@type = :text
|
28
|
+
@title = ""
|
29
|
+
@created = Time.now
|
30
|
+
@pos = 0
|
31
|
+
end #}}}1
|
32
|
+
|
33
|
+
def Clip.from_mbox(str)
|
34
|
+
#{{{1
|
35
|
+
# "From_" line already removed
|
36
|
+
cl = Clip.new
|
37
|
+
in_header = true
|
38
|
+
str.each_line do | line |
|
39
|
+
if in_header then
|
40
|
+
if line == "\n" then
|
41
|
+
in_header = false
|
42
|
+
next
|
43
|
+
end
|
44
|
+
#(key, value) = line.split(/\s*:\s*/,2)
|
45
|
+
# stricter pattern to preserve leading spaces
|
46
|
+
(key, value) = line.split(/\s*: /,2)
|
47
|
+
value.chomp!
|
48
|
+
case key.downcase
|
49
|
+
when "x-wrap"
|
50
|
+
cl.wrap = (value.downcase == "true")
|
51
|
+
when "subject"
|
52
|
+
cl.title = value
|
53
|
+
when "date"
|
54
|
+
cl.created = Time.parse(value)
|
55
|
+
when "content-type"
|
56
|
+
case value
|
57
|
+
when "text/plain"
|
58
|
+
cl.type = :text
|
59
|
+
when "application/x-jota-pref"
|
60
|
+
cl.type = :pref
|
61
|
+
else
|
62
|
+
cl.type = :text # safe fallback type
|
63
|
+
end
|
64
|
+
end
|
65
|
+
else
|
66
|
+
cl.data << line
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return cl
|
70
|
+
end #}}}1
|
71
|
+
|
72
|
+
def to_mbox
|
73
|
+
#{{{1
|
74
|
+
str = ""
|
75
|
+
str << "Date: %s\n" % @created.ctime
|
76
|
+
str << "Subject: %s\n" % @title
|
77
|
+
case @type
|
78
|
+
when :text
|
79
|
+
str << "Content-Type: text/plain\n"
|
80
|
+
when :pref
|
81
|
+
str << "Content-Type: application/x-jota-pref\n"
|
82
|
+
end
|
83
|
+
str << "X-Wrap: %s\n" % @wrap.to_s
|
84
|
+
str << "X-Saved-By: %s %s\n" % [
|
85
|
+
Version::PROGRAM_NAME, Version::STRING]
|
86
|
+
str << "\n"
|
87
|
+
str << @data
|
88
|
+
return str
|
89
|
+
end #}}}1
|
90
|
+
|
91
|
+
def Clip.from_hash(hash)
|
92
|
+
#{{{1
|
93
|
+
cl = Clip.new
|
94
|
+
case hash["type"]
|
95
|
+
when :text
|
96
|
+
cl.wrap = hash["wrap"]
|
97
|
+
cl.data = hash["data"]
|
98
|
+
cl.title = hash["title"]
|
99
|
+
cl.created = hash["created"]
|
100
|
+
end
|
101
|
+
return cl
|
102
|
+
end #}}}1
|
103
|
+
|
104
|
+
def to_hash
|
105
|
+
#{{{1
|
106
|
+
hash = Hash.new
|
107
|
+
hash["type"] = @type
|
108
|
+
hash["wrap"] = @wrap
|
109
|
+
hash["data"] = @data
|
110
|
+
hash["title"] = @title
|
111
|
+
hash["created"] = @created
|
112
|
+
return hash
|
113
|
+
end #}}}1
|
114
|
+
|
115
|
+
def append_as_mbox(file_and_path)
|
116
|
+
#{{{1
|
117
|
+
File.open(file_and_path,"a") do | f |
|
118
|
+
f.print "From %s@localhost %s\n" %
|
119
|
+
[Version::PROGRAM_NAME, Time.now.ctime]
|
120
|
+
f.print(to_mbox)
|
121
|
+
end
|
122
|
+
end #}}}1
|
123
|
+
|
124
|
+
def empty?
|
125
|
+
#{{{1
|
126
|
+
# strip also removes LFs
|
127
|
+
return @data.strip == "" && @title.strip == ""
|
128
|
+
end #}}}1
|
129
|
+
|
130
|
+
def ==(clip)
|
131
|
+
#{{{1
|
132
|
+
return self.to_hash == clip.to_hash
|
133
|
+
end #}}}1
|
134
|
+
|
135
|
+
end #class
|
136
|
+
|
137
|
+
# vim600: set foldmethod=marker:
|