cali 0.1.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.
Files changed (9) hide show
  1. data/.gitignore +2 -0
  2. data/LICENCE +13 -0
  3. data/README +32 -0
  4. data/Rakefile +14 -0
  5. data/VERSION +1 -0
  6. data/bin/cali +19 -0
  7. data/examples/dotcalirc.rb +13 -0
  8. data/lib/cali.rb +265 -0
  9. metadata +87 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg/
2
+ cali.gemspec
data/LICENCE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright © 2008-2010, Tom Adams
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
data/README ADDED
@@ -0,0 +1,32 @@
1
+
2
+ cali
3
+ ====
4
+
5
+ Interactive cal(1) (but the name ical was taken)
6
+
7
+ .calirc.rb
8
+ ==========
9
+
10
+ This file lives in your home directory and is a Ruby script which gets
11
+ required if it exists. See examples/dotcalirc.rb for an example.
12
+
13
+ dates
14
+ =====
15
+
16
+ The -d/--dates option takes a filename as an argument. That file should
17
+ contain linebreak-separated items containing strings of the form
18
+ /\d{4}-\d{2}-\d{2}/.
19
+
20
+ I have something similar in my home directory containing items such as:
21
+
22
+ 2008-12-21 Start on RE essay, ML revision
23
+
24
+ 2009-01-04 The L Word season 6 (final season)
25
+
26
+ 2009-01-22 Shop meeting
27
+
28
+ It's a very simple diary. Try running:
29
+ ruby -rubygems bin/cali -d README
30
+
31
+ The above dates should be underlined in the calendar, and pressing the
32
+ appropriate key should display the item below the calendar.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "cali"
5
+ gem.summary = %Q{Interactive cal(1) (but the name ical was taken)}
6
+ gem.email = "tom@holizz.com"
7
+ gem.homepage = "http://github.com/holizz/cali"
8
+ gem.authors = ["Tom Adams"]
9
+ gem.add_runtime_dependency "ncurses"
10
+ end
11
+ Jeweler::GemcutterTasks.new
12
+ rescue LoadError
13
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/cali ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright © 2008-2010, Tom Adams
4
+ #
5
+ # Permission to use, copy, modify, and/or distribute this software for any
6
+ # purpose with or without fee is hereby granted, provided that the above
7
+ # copyright notice and this permission notice appear in all copies.
8
+ #
9
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ # PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ require 'cali'
18
+
19
+ Cali::run
@@ -0,0 +1,13 @@
1
+ # Sample rc file for cali
2
+ class Cali
3
+ def preinit_hook
4
+ @default_dates = "#{ENV['HOME']}/dates"
5
+ end
6
+ def postinit_hook
7
+ define_key('.',:showevents)
8
+ end
9
+ def define_key(key,action)
10
+ key = key[0] if key.instance_of? String
11
+ @key[key]=action
12
+ end
13
+ end
data/lib/cali.rb ADDED
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright © 2008-2010, Tom Adams
4
+ #
5
+ # Permission to use, copy, modify, and/or distribute this software for any
6
+ # purpose with or without fee is hereby granted, provided that the above
7
+ # copyright notice and this permission notice appear in all copies.
8
+ #
9
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ # PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ require 'date'
18
+ require 'optparse'
19
+ require 'ncurses'
20
+
21
+ class Cali
22
+ KEYBINDINGS = {
23
+ ['q'[0]]=> :quit,
24
+ [12]=> :refresh, # C-l
25
+ ['l'[0], Ncurses::KEY_RIGHT, 6]=> :tomorrow, # C-f
26
+ ['h'[0], Ncurses::KEY_LEFT, 2]=> :yesterday, # C-b
27
+ ['j'[0], Ncurses::KEY_DOWN, 14]=> :nextweek, # C-n
28
+ ['k'[0], Ncurses::KEY_UP, 16]=> :prevweek, # C-p
29
+ ['n'[0], Ncurses::KEY_NPAGE]=> :nextmonth,
30
+ ['p'[0], Ncurses::KEY_PPAGE]=> :prevmonth,
31
+ ['}'[0]]=> :nextyear,
32
+ ['{'[0]]=> :prevyear,
33
+ ['w'[0]]=> :nextevent,
34
+ ['b'[0]]=> :prevevent
35
+ }
36
+
37
+ def Cali::run
38
+ options = {}
39
+ OptionParser.new { |opts|
40
+ opts.banner = "Usage: cali [-d FILE]"
41
+ opts.on("-d","--dates FILE","Use FILE for events") {|d|
42
+ options[:dates] = d
43
+ }
44
+ }.parse!
45
+ dotcali = Dir["#{ENV['HOME']}/.calirc.rb"][0]
46
+ require dotcali if dotcali
47
+ cali=Cali.new(options[:dates])
48
+ cali.run
49
+ end
50
+
51
+ def initialize(dates=nil)
52
+ preinit_hook
53
+ @today = Date.today
54
+ @days = {}
55
+ dates ||= @default_dates
56
+ @dates = {}
57
+ if dates
58
+ open(dates){|f|
59
+ until f.eof
60
+ line = f.readline.strip
61
+ d = line.match(/(\d{4})-(\d{2})-(\d{2})/)
62
+ if d
63
+ date = Date.new(*d[1..3].map{|m|m.to_i})
64
+ @dates[date] ||= []
65
+ @dates[date] << line
66
+ end
67
+ end
68
+ }
69
+ end
70
+ @key = {}
71
+ KEYBINDINGS.each {|k,v|
72
+ k.each {|kk|
73
+ @key[kk] = v
74
+ }
75
+ }
76
+ postinit_hook
77
+ end
78
+ def run
79
+ begin
80
+ Ncurses.initscr
81
+ Ncurses.cbreak
82
+ Ncurses.noecho
83
+ Ncurses.keypad(Ncurses.stdscr,true)
84
+ mainloop
85
+ ensure
86
+ Ncurses.endwin
87
+ end
88
+ end
89
+ def mainloop
90
+ displaycal
91
+ displayevents
92
+ catch :quit do
93
+ while true
94
+ move @key[Ncurses.getch]
95
+ end
96
+ end
97
+ end
98
+ def displaycal
99
+ Ncurses.clear
100
+ Ncurses.move(0,0)
101
+ Ncurses.printw(@today.strftime(" %B %Y\n"))
102
+ Ncurses.printw(weekdays.join(" ")+"\n")
103
+ displaydays
104
+ Ncurses.refresh
105
+ end
106
+ def displaydays
107
+ counter = (first - first.wday)
108
+ before_month = true
109
+ after_month = false
110
+ while not after_month
111
+ if counter.month == @today.month and before_month
112
+ before_month = false
113
+ elsif counter.month != @today.month and not before_month
114
+ after_month = true
115
+ end
116
+ if before_month or after_month
117
+ Ncurses.printw(" ")
118
+ Ncurses.printw("\n") if after_month
119
+ else
120
+ @days[counter.day] = [Ncurses.getcurx(Ncurses.stdscr),
121
+ Ncurses.getcury(Ncurses.stdscr)]
122
+ if counter == @today
123
+ x,y = Ncurses.getcurx(Ncurses.stdscr),Ncurses.getcury(Ncurses.stdscr)
124
+ end
125
+ Ncurses.attron(Ncurses::A_UNDERLINE) if has_items?(counter)
126
+ Ncurses.attron(Ncurses::A_REVERSE) if counter == @today
127
+ Ncurses.printw("%2d" % counter.day)
128
+ Ncurses.attroff(Ncurses::A_REVERSE) if counter == @today
129
+ Ncurses.attroff(Ncurses::A_UNDERLINE) if has_items?(counter)
130
+ Ncurses.printw(" ")
131
+ end
132
+ if counter.wday == 6
133
+ Ncurses.printw("\n")
134
+ end
135
+ counter += 1
136
+ end
137
+ Ncurses.move(y,x+1)
138
+ end
139
+ def displayevents
140
+ displaycal
141
+ bounce {
142
+ y = @days[last.day][1]
143
+ @dates[@today].each {|l|
144
+ y += 2
145
+ Ncurses.move(y,0)
146
+ Ncurses.printw("#{l}")
147
+ } if @dates[@today]
148
+ }
149
+ end
150
+ def bounce (&block)
151
+ y,x = Ncurses.getcury(Ncurses.stdscr),Ncurses.getcurx(Ncurses.stdscr)
152
+ yield
153
+ Ncurses.move(y,x)
154
+ end
155
+ def movecursor(old)
156
+ if old != @today
157
+ a = @days[old.day]
158
+ Ncurses.attron(Ncurses::A_UNDERLINE) if has_items?(old)
159
+ Ncurses.mvprintw(a[1],a[0],"%2d" % old.day)
160
+ Ncurses.attroff(Ncurses::A_UNDERLINE) if has_items?(old)
161
+ end
162
+
163
+ Ncurses.attron(Ncurses::A_UNDERLINE) if has_items?(@today)
164
+ Ncurses.attron(Ncurses::A_REVERSE)
165
+ a = @days[@today.day]
166
+ Ncurses.mvprintw(a[1],a[0],"%2d" % @today.day)
167
+ Ncurses.attroff(Ncurses::A_REVERSE)
168
+ Ncurses.attroff(Ncurses::A_UNDERLINE) if has_items?(@today)
169
+ Ncurses.move(a[1],a[0]+1)
170
+ end
171
+ def update(&block)
172
+ oldtoday = @today.dup
173
+ yield
174
+ if oldtoday.month == @today.month and oldtoday.year == @today.year
175
+ movecursor(oldtoday)
176
+ else
177
+ displaycal
178
+ end
179
+ end
180
+ def move(to)
181
+ case to
182
+ when :quit
183
+ throw :quit
184
+ when :refresh
185
+ displaycal
186
+ when :tomorrow
187
+ update { @today += 1 }
188
+ when :yesterday
189
+ update { @today -= 1 }
190
+ when :nextweek
191
+ update { @today += 7 }
192
+ when :prevweek
193
+ update { @today -= 7 }
194
+ when :nextmonth
195
+ oldtoday = @today.dup
196
+ @today += 4*7
197
+ if @today.month == oldtoday.month
198
+ @today += 7
199
+ end
200
+ displaycal
201
+ when :prevmonth
202
+ oldtoday = @today.dup
203
+ @today -= 4*7
204
+ if @today.month == oldtoday.month
205
+ @today -= 7
206
+ end
207
+ displaycal
208
+ when :nextyear
209
+ oldtoday = @today.dup
210
+ @today += 52*7
211
+ while @today.year == oldtoday.year or @today.month != oldtoday.month
212
+ @today += 7
213
+ end
214
+ displaycal
215
+ when :prevyear
216
+ oldtoday = @today.dup
217
+ @today -= 52*7
218
+ while @today.year == oldtoday.year or @today.month != oldtoday.month
219
+ @today -= 7
220
+ end
221
+ displaycal
222
+ when :nextevent
223
+ update {
224
+ newtoday = @dates.keys.select{|d| @today < d }.sort.first
225
+ @today = newtoday if newtoday
226
+ }
227
+ when :prevevent
228
+ update {
229
+ newtoday = @dates.keys.select{|d| @today > d }.sort.last
230
+ @today = newtoday if newtoday
231
+ }
232
+ end
233
+ displayevents
234
+ end
235
+ def weekdays
236
+ wds = []
237
+ counter = (@today - @today.wday)
238
+ n = 0
239
+ while n < 7
240
+ #TODO: handle other charsets correctly
241
+ wds << counter.strftime('%a')[0..1]
242
+ counter += 1
243
+ n += 1
244
+ end
245
+ wds
246
+ end
247
+ def first
248
+ Date.new(@today.year,@today.month,1)
249
+ end
250
+ def last
251
+ newlast = @today.dup
252
+ until newlast.month != @today.month
253
+ last = newlast.dup
254
+ newlast += 1
255
+ end
256
+ last
257
+ end
258
+ def has_items?(date=@today)
259
+ @dates.include?(date)
260
+ end
261
+ def preinit_hook
262
+ end
263
+ def postinit_hook
264
+ end
265
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cali
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Tom Adams
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-31 00:00:00 +01:00
19
+ default_executable: cali
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ncurses
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description:
36
+ email: tom@holizz.com
37
+ executables:
38
+ - cali
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ files:
44
+ - .gitignore
45
+ - LICENCE
46
+ - README
47
+ - Rakefile
48
+ - VERSION
49
+ - bin/cali
50
+ - examples/dotcalirc.rb
51
+ - lib/cali.rb
52
+ has_rdoc: true
53
+ homepage: http://github.com/holizz/cali
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --charset=UTF-8
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Interactive cal(1) (but the name ical was taken)
86
+ test_files:
87
+ - examples/dotcalirc.rb