todo-jsonl 0.1.10 → 0.1.16

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/todo.rb +59 -26
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26e087f32b9e0ddb96664aaffcb83aab17a4cf31c75eb651bb1797fa6d7fba09
4
- data.tar.gz: c298e6c64c3bd28f0d0806c6b12204e74bc7c89e6d32939a2763368cae11e17e
3
+ metadata.gz: 6d359c12e487b44bf92a6406c044944c6aac14f4e1e45850b021c7184feb274d
4
+ data.tar.gz: 84b3b6d64e208e96cb81afbad8f6b07ca2f685a13178854fbd7792c5fde9062a
5
5
  SHA512:
6
- metadata.gz: 6221aaca3f2637bd59c35720f2383e9fb6ef1a59faf5604341da0d04148184e504a53bd0d45a18dcd3462141496a5c91bdc0c8bef896c559362ce0670cc1b231
7
- data.tar.gz: 88c148df544f7bc2fb65a50becac172f9f216cbea27a15666add4eb05ae752834b5f5396d191778be7045f2c856034e11a5e38fb3ef210a570bed92aed75f611
6
+ metadata.gz: 2eb6fb53e9ab1abd698a55995f7497de9e26f65787402d79afaaf62ca3c58a84cd79d363167d3001e02df0c0eb9a7e024fdd7be37c19d159833041686d6c85fc
7
+ data.tar.gz: 0edda1d28b4f76aa17bbf0b6c44e11025d433022bb9fef6d1ef1671de360ba841c77dd0c47400afe9f372a0a38c3c13b1a8b85a39de813e7c68fcd146b40ce5f
data/bin/todo.rb CHANGED
@@ -69,6 +69,9 @@ DUE_DATE_DAYS = NEXT_7_DAYS.map do |day| day.strftime('%A').downcase end
69
69
  DUE_DATES_FOR_QUERIES = NEXT_7_DAYS.map do |day| day.strftime(DATE_FORMAT) end
70
70
  DUE_DATE_DAYS_SIMPLE = ['today', 'tomorrow']
71
71
 
72
+ DUE_DATE_TAG_PATTERN = /(^| )due:([a-zA-Z0-9-]+)/
73
+ CONTEXT_TAG_PATTERN = /(^| )[@+][\w-]+/
74
+
72
75
  QUERIES = {
73
76
  ':active' => 'state=(new|started|blocked)',
74
77
  ':done' => 'state=done',
@@ -91,12 +94,12 @@ def usage
91
94
 
92
95
  Commands:
93
96
  * add <text> add new task
94
- * start <tasknumber> mark task as started
95
- * done <tasknumber> mark task as completed
96
- * block <tasknumber> mark task as blocked
97
- * reset <tasknumber> reset task to new state
98
- * prio <tasknumber> toggle high priority flag
99
- * due <tasknumber> <date> set due date (in YYYY-MM-DD format)
97
+ * start <tasknumber> [text] mark task as started, with optional note
98
+ * done <tasknumber> [text] mark task as completed, with optional note
99
+ * block <tasknumber> [text] mark task as blocked, with optional note
100
+ * reset <tasknumber> [text] reset task to new state, with optional note
101
+ * prio <tasknumber> [text] toggle high priority flag, with optional note
102
+ * due <tasknumber> [date] set/unset due date (in YYYY-MM-DD format)
100
103
 
101
104
  * append <tasknumber> <text> append text to task title
102
105
  * rename <tasknumber> <text> rename task
@@ -112,8 +115,12 @@ def usage
112
115
  With list command the following pre-defined regex patterns can be also used:
113
116
  #{QUERIES.keys.join(', ')}
114
117
 
118
+ Due dates can be also added via tags in task title: "due:YYYY-MM-DD"
119
+
115
120
  Legend:
116
121
  #{STATES.select { |k, v| k != 'default' }.map { |k, v| "#{k} #{v}" }.join(', ') }, priority #{PRIORITY_FLAG}
122
+
123
+ Todo file: #{TODO_FILE}
117
124
  USAGE
118
125
  end
119
126
 
@@ -143,12 +150,22 @@ def write_tasks(tasks)
143
150
  end
144
151
  end
145
152
 
153
+ def postprocess_tags(task)
154
+ match_data = task[:title].match(DUE_DATE_TAG_PATTERN)
155
+ if match_data
156
+ task[:title] = task[:title].gsub(DUE_DATE_TAG_PATTERN, '')
157
+ task[:due] = convert_due_date(match_data[2])
158
+ end
159
+ raise 'title must not be empty' if task[:title].empty?
160
+ end
161
+
146
162
  def add(text)
147
163
  task = {
148
164
  state: 'new',
149
165
  title: text,
150
166
  modified: Time.now.strftime(DATE_FORMAT)
151
167
  }
168
+ postprocess_tags(task)
152
169
  File.open(TODO_FILE, 'a:UTF-8') do |file|
153
170
  file.write(JSON.generate(task) + "\n")
154
171
  end
@@ -159,6 +176,7 @@ def append(item, text = '')
159
176
  tasks = load_tasks(item)
160
177
  tasks[item][:title] = [tasks[item][:title], text].join(' ')
161
178
  tasks[item][:modified] = Time.now.strftime(DATE_FORMAT)
179
+ postprocess_tags(tasks[item])
162
180
  write_tasks(tasks)
163
181
  list(tasks)
164
182
  end
@@ -167,6 +185,7 @@ def rename(item, text)
167
185
  tasks = load_tasks(item)
168
186
  tasks[item][:title] = text
169
187
  tasks[item][:modified] = Time.now.strftime(DATE_FORMAT)
188
+ postprocess_tags(tasks[item])
170
189
  write_tasks(tasks)
171
190
  list(tasks)
172
191
  end
@@ -178,30 +197,33 @@ def delete(item)
178
197
  list
179
198
  end
180
199
 
181
- def change_state(item, state)
200
+ def change_state(item, state, note = nil)
182
201
  tasks = load_tasks(item)
183
202
  tasks[item][:state] = state
184
203
  tasks[item][:modified] = Time.now.strftime(DATE_FORMAT)
204
+ if !note.nil? && !note.empty?
205
+ tasks[item][:note] ||= []
206
+ tasks[item][:note].push(note)
207
+ end
185
208
  write_tasks(tasks)
186
209
  list(tasks)
187
210
  end
188
211
 
189
- def set_priority(item)
212
+ def set_priority(item, note = nil)
190
213
  tasks = load_tasks(item)
191
214
  tasks[item][:priority] = !tasks[item][:priority]
192
215
  tasks[item][:modified] = Time.now.strftime(DATE_FORMAT)
216
+ if !note.nil? && !note.empty?
217
+ tasks[item][:note] ||= []
218
+ tasks[item][:note].push(note)
219
+ end
193
220
  write_tasks(tasks)
194
221
  list(tasks)
195
222
  end
196
223
 
197
- def due_date(item, date = '')
224
+ def due_date(item, date = '', task = nil)
198
225
  tasks = load_tasks(item)
199
- day_index = DUE_DATE_DAYS.index(date.to_s.downcase) || DUE_DATE_DAYS_SIMPLE.index(date.to_s.downcase)
200
- if day_index
201
- tasks[item][:due] = (TODAY.to_date + day_index).strftime(DATE_FORMAT)
202
- else
203
- tasks[item][:due] = date.nil? || date.empty? ? nil : Date.parse(date).strftime(DATE_FORMAT)
204
- end
226
+ tasks[item][:due] = convert_due_date(date)
205
227
  tasks[item][:modified] = Time.now.strftime(DATE_FORMAT)
206
228
  write_tasks(tasks)
207
229
  list(tasks)
@@ -227,7 +249,9 @@ def list(tasks = nil, patterns = nil)
227
249
  state = task[:state] || 'default'
228
250
  color = COLORS[state]
229
251
  display_state = colorize(STATES[state], color)
230
- title = task[:title].gsub(/@\w+/) { |tag| colorize(tag, :cyan) }
252
+ title = task[:title].gsub(CONTEXT_TAG_PATTERN) do |tag|
253
+ (tag.start_with?(' ') ? ' ' : '') + colorize(tag.strip, :cyan)
254
+ end
231
255
  priority_flag = task[:priority] ? colorize(PRIORITY_FLAG, :red) : ' '
232
256
  due_date = ''
233
257
  if task[:due] && state != 'done'
@@ -288,6 +312,19 @@ def colorize(text, color)
288
312
  "\e[#{COLOR_CODES[color]}m#{text}\e[0m"
289
313
  end
290
314
 
315
+ def convert_due_date(date = '')
316
+ due = nil
317
+ day_index = DUE_DATE_DAYS.index(date.to_s.downcase) ||
318
+ DUE_DATE_DAYS_SIMPLE.index(date.to_s.downcase) ||
319
+ DUE_DATE_DAYS.map do |day| day[0..2] end.index(date.to_s.downcase)
320
+ if day_index
321
+ due = (TODAY.to_date + day_index).strftime(DATE_FORMAT)
322
+ else
323
+ due = date.nil? || date.empty? ? nil : Date.parse(date).strftime(DATE_FORMAT)
324
+ end
325
+ return due
326
+ end
327
+
291
328
  def read(arguments)
292
329
  begin
293
330
  action = arguments.first
@@ -297,20 +334,16 @@ def read(arguments)
297
334
  raise action + ' command requires at least one parameter' if args.nil? || args.empty?
298
335
  add(args.join(' '))
299
336
  when 'start'
300
- raise action + ' command can receive only one task number' if args.length > 1
301
- args.length == 1 ? change_state(args.first.to_i, 'started') : list(nil, [':started'])
337
+ args.length > 0 ? change_state(args.first.to_i, 'started', (args[1..-1] || []).join(' ')) : list(nil, [':started'])
302
338
  when 'done'
303
- raise action + ' command can receive only one task number' if args.length > 1
304
- args.length == 1 ? change_state(args.first.to_i, 'done') : list(nil, [':done'])
339
+ args.length > 0 ? change_state(args.first.to_i, 'done', (args[1..-1] || []).join(' ')) : list(nil, [':done'])
305
340
  when 'block'
306
- raise action + ' command can receive only one task number' if args.length > 1
307
- args.length == 1 ? change_state(args.first.to_i, 'blocked') : list(nil, [':blocked'])
341
+ args.length > 0 ? change_state(args.first.to_i, 'blocked', (args[1..-1] || []).join(' ')) : list(nil, [':blocked'])
308
342
  when 'reset'
309
- raise action + ' command can receive only one task number' if args.length > 1
310
- args.length == 1 ? change_state(args.first.to_i, 'new') : list(nil, [':new'])
343
+ args.length > 0 ? change_state(args.first.to_i, 'new', (args[1..-1] || []).join(' ')) : list(nil, [':new'])
311
344
  when 'prio'
312
- raise action + ' command requires exactly one parameter' if args.length != 1
313
- set_priority(args.first.to_i)
345
+ raise action + ' command requires at least one parameter' if args.length < 1
346
+ set_priority(args.first.to_i, (args[1..-1] || []).join(' '))
314
347
  when 'due'
315
348
  raise action + ' command requires at least one parameter' if args.length < 1
316
349
  due_date(args.first.to_i, (args[1..-1] || []).join(' '))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: todo-jsonl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabor Bata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-27 00:00:00.000000000 Z
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: