tasku 0.2.2 → 0.3.1
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.
- checksums.yaml +4 -4
- data/exe/tasku +5 -1
- data/lib/tasku/cli.rb +103 -9
- data/lib/tasku/config.rb +52 -0
- data/lib/tasku/database.rb +5 -0
- data/lib/tasku/output/terminal.rb +71 -11
- data/lib/tasku/project.rb +13 -0
- data/lib/tasku/version.rb +1 -1
- data/lib/tasku.rb +7 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d01584cb8583cbcb7623bf5ba3487efa0f9ae428db88b5cd3cf2e6d90393381d
|
|
4
|
+
data.tar.gz: cb79bddf2a6c141a23ee9f0dcf52169767dfb34ab9e86870afeba7d7dc158d33
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92d51c1a51d85b185ba14e982ccc5eb8a5bbe7bb6f04f74c5dac3d6b0ae0b916174e7afbc09a3230f9525a08650fd8b228a2e4724c20c7f5bdb3a1de71db5ba0
|
|
7
|
+
data.tar.gz: de7d23c5f2032c57ded24ff9d8920001ba7e650538d6a58d0e08d9647d538ee67aa0588d98e29b5986c080ebfe798a5557d02fb100ac53904db29c378fa19df0
|
data/exe/tasku
CHANGED
data/lib/tasku/cli.rb
CHANGED
|
@@ -13,7 +13,45 @@ module Tasku
|
|
|
13
13
|
|
|
14
14
|
TAGLINE = "\u30BF\u30B9\u30AF\u30EA\u30B9\u30C8 \u2014 terminal task manager"
|
|
15
15
|
|
|
16
|
+
class ConfigApp < Thor
|
|
17
|
+
desc "list", "Show all preferences and their current values"
|
|
18
|
+
def list
|
|
19
|
+
pastel = Pastel.new
|
|
20
|
+
puts ""
|
|
21
|
+
Tasku::Config::VALID_KEYS.each do |key, meta|
|
|
22
|
+
current = Tasku::Config.get(key)
|
|
23
|
+
options_str = meta[:values].map { |v| v == current ? pastel.bold(pastel.green(v)) : pastel.dim(v) }.join(", ")
|
|
24
|
+
puts " #{pastel.bold(key.ljust(20))} #{options_str} #{pastel.dim("— #{meta[:description]}")}"
|
|
25
|
+
end
|
|
26
|
+
puts ""
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
desc "set KEY VALUE", "Set a preference value"
|
|
30
|
+
def set(key, value)
|
|
31
|
+
pastel = Pastel.new
|
|
32
|
+
meta = Tasku::Config::VALID_KEYS[key]
|
|
33
|
+
abort pastel.red("Unknown preference '#{key}'. Run `tasku config list` to see available keys.") unless meta
|
|
34
|
+
unless meta[:values].include?(value)
|
|
35
|
+
abort pastel.red("Invalid value '#{value}' for '#{key}'. Valid: #{meta[:values].join(', ')}")
|
|
36
|
+
end
|
|
37
|
+
Tasku::Config.set(key, value)
|
|
38
|
+
puts pastel.green(" ✓ #{key} set to '#{value}'.")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
desc "get KEY", "Get the current value of a preference"
|
|
42
|
+
def get(key)
|
|
43
|
+
pastel = Pastel.new
|
|
44
|
+
meta = Tasku::Config::VALID_KEYS[key]
|
|
45
|
+
abort pastel.red("Unknown preference '#{key}'. Run `tasku config list` to see available keys.") unless meta
|
|
46
|
+
puts " #{key}: #{pastel.bold(Tasku::Config.get(key))}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
16
50
|
class App < Thor
|
|
51
|
+
def self.exit_on_failure?
|
|
52
|
+
true
|
|
53
|
+
end
|
|
54
|
+
|
|
17
55
|
def self.start(args = ARGV, **opts)
|
|
18
56
|
sql_index = args.index("--sql")
|
|
19
57
|
if sql_index
|
|
@@ -33,6 +71,19 @@ module Tasku
|
|
|
33
71
|
|
|
34
72
|
class_option :db, type: :string, desc: "Path to SQLite database (default: ~/.tasku/tasks.db)", hide: true
|
|
35
73
|
|
|
74
|
+
desc "config SUBCOMMAND", "Manage user preferences"
|
|
75
|
+
subcommand "config", ConfigApp
|
|
76
|
+
|
|
77
|
+
def help(*args)
|
|
78
|
+
if args.empty?
|
|
79
|
+
puts ""
|
|
80
|
+
puts pastel.bold(LOGO)
|
|
81
|
+
puts " #{pastel.bold(TAGLINE)}"
|
|
82
|
+
puts ""
|
|
83
|
+
end
|
|
84
|
+
super
|
|
85
|
+
end
|
|
86
|
+
|
|
36
87
|
desc "sql QUERY", "Run a raw SQL query against the database"
|
|
37
88
|
def sql(query)
|
|
38
89
|
if query.strip.upcase.match?(/\A(SELECT|PRAGMA|EXPLAIN)/)
|
|
@@ -123,7 +174,7 @@ module Tasku
|
|
|
123
174
|
option :category, type: :string, desc: "Filter by category"
|
|
124
175
|
option :tags, type: :string, desc: "Filter by tag (comma-separated)"
|
|
125
176
|
option :overdue, type: :boolean, desc: "Show only overdue tasks"
|
|
126
|
-
option :sort, type: :string, desc: "Sort by: name, priority, due, status, created"
|
|
177
|
+
option :sort, type: :string, desc: "Sort by: id, name, priority, due, status, created"
|
|
127
178
|
option :order, type: :string, desc: "Order: asc, desc", default: "asc"
|
|
128
179
|
def list
|
|
129
180
|
dataset = Task.dataset
|
|
@@ -150,20 +201,22 @@ module Tasku
|
|
|
150
201
|
when "priority" then Sequel.case(Task::VALID_PRIORITIES.each_with_index.to_h, 999, :priority)
|
|
151
202
|
when "due" then :due_day
|
|
152
203
|
when "status" then Sequel.case(Task::VALID_STATUSES.each_with_index.to_h, 999, :status)
|
|
153
|
-
|
|
204
|
+
when "created" then :created_at
|
|
205
|
+
else :id
|
|
154
206
|
end
|
|
155
207
|
|
|
156
208
|
order = options[:order] == "desc" ? Sequel.desc(sort_col) : Sequel.asc(sort_col)
|
|
157
209
|
dataset = dataset.order(order)
|
|
158
210
|
|
|
159
211
|
tasks = dataset.all
|
|
160
|
-
|
|
212
|
+
bar = { "bar_project" => Config.get("bar_project"), "bar_priority" => Config.get("bar_priority"), "bar_status" => Config.get("bar_status") }
|
|
213
|
+
terminal.render_list(tasks, colour_map: Project.colour_map, spacing: Config.get("list_spacing"), bar: bar)
|
|
161
214
|
end
|
|
162
215
|
|
|
163
216
|
desc "show ID", "Show task details"
|
|
164
217
|
def show(id)
|
|
165
218
|
task = find_task(id)
|
|
166
|
-
terminal.render_show(task)
|
|
219
|
+
terminal.render_show(task, colour_map: Project.colour_map)
|
|
167
220
|
end
|
|
168
221
|
|
|
169
222
|
desc "edit ID", "Edit a task"
|
|
@@ -241,25 +294,48 @@ module Tasku
|
|
|
241
294
|
desc "stats", "Show task statistics"
|
|
242
295
|
def stats
|
|
243
296
|
tasks = Task.dataset.all
|
|
244
|
-
terminal.render_stats(tasks) if tasks
|
|
297
|
+
terminal.render_stats(tasks, colour_map: Project.colour_map) if tasks
|
|
245
298
|
end
|
|
246
299
|
|
|
247
300
|
desc "projects", "List all projects"
|
|
248
301
|
def projects
|
|
249
|
-
|
|
250
|
-
if
|
|
302
|
+
project_names = Task.dataset.select(:project).where(Sequel.~(project: nil)).distinct.order(:project).map(:project)
|
|
303
|
+
if project_names.empty?
|
|
251
304
|
puts pastel.yellow(" No projects found.")
|
|
252
305
|
return
|
|
253
306
|
end
|
|
254
307
|
|
|
308
|
+
colour_map = Project.colour_map
|
|
255
309
|
puts ""
|
|
256
|
-
|
|
310
|
+
project_names.each do |p|
|
|
257
311
|
count = Task.where(project: p).count
|
|
258
|
-
|
|
312
|
+
colour = colour_map[p]
|
|
313
|
+
swatch = colour ? "#{hex_colour_str("█", colour)} " : " "
|
|
314
|
+
name_str = colour ? hex_bold_str(p, colour) : pastel.bold(p)
|
|
315
|
+
puts " #{swatch}#{name_str} #{pastel.dim("(#{count} task(s))")}"
|
|
259
316
|
end
|
|
260
317
|
puts ""
|
|
261
318
|
end
|
|
262
319
|
|
|
320
|
+
desc "colour PROJECT HEX", "Set a project's display colour (e.g. #FF5733). Omit HEX to clear."
|
|
321
|
+
def colour(project, hex = nil)
|
|
322
|
+
if hex.nil?
|
|
323
|
+
proj = Project[project]
|
|
324
|
+
if proj
|
|
325
|
+
proj.update(colour: nil)
|
|
326
|
+
puts pastel.green(" Colour cleared for project '#{project}'.")
|
|
327
|
+
else
|
|
328
|
+
puts pastel.yellow(" No colour set for project '#{project}'.")
|
|
329
|
+
end
|
|
330
|
+
return
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
validated = validate_hex!(hex)
|
|
334
|
+
Project.find_or_create(name: project).update(colour: validated)
|
|
335
|
+
swatch = hex_colour_str("█", validated)
|
|
336
|
+
puts " #{swatch} Colour #{pastel.bold(validated)} set for project '#{pastel.bold(project)}'."
|
|
337
|
+
end
|
|
338
|
+
|
|
263
339
|
desc "categories", "List all categories"
|
|
264
340
|
def categories
|
|
265
341
|
categories = Task.dataset.select(:category).where(Sequel.~(category: nil)).distinct.order(:category).map(:category)
|
|
@@ -428,6 +504,24 @@ module Tasku
|
|
|
428
504
|
"archived" => :dim
|
|
429
505
|
}.freeze
|
|
430
506
|
|
|
507
|
+
def validate_hex!(hex)
|
|
508
|
+
hex = hex.start_with?("#") ? hex : "##{hex}"
|
|
509
|
+
unless hex.match?(/\A#[0-9a-fA-F]{6}\z/)
|
|
510
|
+
abort pastel.red("Invalid hex colour '#{hex}'. Use format #RRGGBB.")
|
|
511
|
+
end
|
|
512
|
+
hex
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def hex_colour_str(text, hex)
|
|
516
|
+
r, g, b = hex.delete("#").scan(/../).map { |c| c.to_i(16) }
|
|
517
|
+
"\e[38;2;#{r};#{g};#{b}m#{text}\e[0m"
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def hex_bold_str(text, hex)
|
|
521
|
+
r, g, b = hex.delete("#").scan(/../).map { |c| c.to_i(16) }
|
|
522
|
+
"\e[1;38;2;#{r};#{g};#{b}m#{text}\e[0m"
|
|
523
|
+
end
|
|
524
|
+
|
|
431
525
|
def colour_cell(col, padded_val, row)
|
|
432
526
|
case col.to_s
|
|
433
527
|
when "priority"
|
data/lib/tasku/config.rb
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
module Tasku
|
|
7
|
+
class Config
|
|
8
|
+
CONFIG_PATH = File.join(Dir.home, ".tasku", "config.json")
|
|
9
|
+
|
|
10
|
+
VALID_KEYS = {
|
|
11
|
+
"list_spacing" => {
|
|
12
|
+
values: %w[compact spacious],
|
|
13
|
+
default: "compact",
|
|
14
|
+
description: "Row spacing in task list"
|
|
15
|
+
},
|
|
16
|
+
"bar_project" => {
|
|
17
|
+
values: %w[on off],
|
|
18
|
+
default: "on",
|
|
19
|
+
description: "Show project colour segment in row bar"
|
|
20
|
+
},
|
|
21
|
+
"bar_priority" => {
|
|
22
|
+
values: %w[on off],
|
|
23
|
+
default: "on",
|
|
24
|
+
description: "Show priority colour segment in row bar"
|
|
25
|
+
},
|
|
26
|
+
"bar_status" => {
|
|
27
|
+
values: %w[on off],
|
|
28
|
+
default: "on",
|
|
29
|
+
description: "Show status colour segment in row bar"
|
|
30
|
+
}
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
def self.get(key)
|
|
34
|
+
all[key] || VALID_KEYS.dig(key, :default)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.set(key, value)
|
|
38
|
+
current = all
|
|
39
|
+
current[key] = value
|
|
40
|
+
FileUtils.mkdir_p(File.dirname(CONFIG_PATH))
|
|
41
|
+
File.write(CONFIG_PATH, JSON.pretty_generate(current))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.all
|
|
45
|
+
return {} unless File.exist?(CONFIG_PATH)
|
|
46
|
+
|
|
47
|
+
JSON.parse(File.read(CONFIG_PATH))
|
|
48
|
+
rescue JSON::ParserError
|
|
49
|
+
{}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/tasku/database.rb
CHANGED
|
@@ -42,6 +42,11 @@ module Tasku
|
|
|
42
42
|
if db.table_exists?(:tasks) && !db.schema(:tasks).map(&:first).include?(:code)
|
|
43
43
|
db.alter_table(:tasks) { add_column :code, String }
|
|
44
44
|
end
|
|
45
|
+
|
|
46
|
+
db.create_table? :projects do
|
|
47
|
+
String :name, primary_key: true
|
|
48
|
+
String :colour
|
|
49
|
+
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
47
52
|
end
|
|
@@ -5,6 +5,23 @@ require "pastel"
|
|
|
5
5
|
module Tasku
|
|
6
6
|
module Output
|
|
7
7
|
class Terminal
|
|
8
|
+
PRIORITY_HEX = {
|
|
9
|
+
"none" => "#6B7280",
|
|
10
|
+
"low" => "#06B6D4",
|
|
11
|
+
"medium" => "#EAB308",
|
|
12
|
+
"high" => "#EF4444",
|
|
13
|
+
"urgent" => "#E879F9"
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
STATUS_HEX = {
|
|
17
|
+
"backlog" => "#6B7280",
|
|
18
|
+
"todo" => "#3B82F6",
|
|
19
|
+
"in_progress" => "#EAB308",
|
|
20
|
+
"done" => "#22C55E",
|
|
21
|
+
"cancelled" => "#EF4444",
|
|
22
|
+
"archived" => "#6B7280"
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
8
25
|
PRIORITY_STYLES = {
|
|
9
26
|
"none" => { color: :dim, symbol: " " },
|
|
10
27
|
"low" => { color: :cyan, symbol: "↓" },
|
|
@@ -26,16 +43,16 @@ module Tasku
|
|
|
26
43
|
|
|
27
44
|
def initialize
|
|
28
45
|
@pastel = Pastel.new
|
|
29
|
-
@term_width =
|
|
46
|
+
@term_width = terminal_width
|
|
30
47
|
end
|
|
31
48
|
|
|
32
|
-
def render_list(tasks)
|
|
49
|
+
def render_list(tasks, colour_map: {}, spacing: "compact", bar: {})
|
|
33
50
|
if tasks.empty?
|
|
34
51
|
puts @pastel.yellow(" No tasks found.")
|
|
35
52
|
return
|
|
36
53
|
end
|
|
37
54
|
|
|
38
|
-
rows = tasks.map { |t| build_columns(t) }
|
|
55
|
+
rows = tasks.map { |t| build_columns(t, colour_map, bar) }
|
|
39
56
|
col_widths = compute_widths(rows)
|
|
40
57
|
total = col_widths.sum + (COL_SEP.length * (col_widths.length - 1))
|
|
41
58
|
|
|
@@ -44,12 +61,13 @@ module Tasku
|
|
|
44
61
|
rows.each do |cols|
|
|
45
62
|
line = cols.each_with_index.map { |c, i| c.to_s.ljust(col_widths[i]) }.join(COL_SEP)
|
|
46
63
|
puts " #{line}"
|
|
64
|
+
puts "" if spacing == "spacious"
|
|
47
65
|
end
|
|
48
66
|
puts @pastel.dim(" #{"─" * total}")
|
|
49
67
|
puts @pastel.dim(" #{tasks.length} task(s) found")
|
|
50
68
|
end
|
|
51
69
|
|
|
52
|
-
def render_show(task)
|
|
70
|
+
def render_show(task, colour_map: {})
|
|
53
71
|
puts ""
|
|
54
72
|
puts @pastel.bold(" Task ##{task.id}")
|
|
55
73
|
puts @pastel.dim(" #{"─" * 60}")
|
|
@@ -57,7 +75,7 @@ module Tasku
|
|
|
57
75
|
fields = [
|
|
58
76
|
["Name", @pastel.bold(task.name)],
|
|
59
77
|
["Description", task.description ? @pastel.dim(task.description) : @pastel.dim("—")],
|
|
60
|
-
["Project", task.project
|
|
78
|
+
["Project", project_str(task.project, colour_map)],
|
|
61
79
|
["Category", task.category || @pastel.dim("—")],
|
|
62
80
|
["Priority", priority_tag(task.priority)],
|
|
63
81
|
["Status", status_tag(task.status)],
|
|
@@ -90,7 +108,7 @@ module Tasku
|
|
|
90
108
|
puts @pastel.red(" ✗ Task ##{task.id} deleted") + " — #{@pastel.bold(task.name)}"
|
|
91
109
|
end
|
|
92
110
|
|
|
93
|
-
def render_stats(tasks)
|
|
111
|
+
def render_stats(tasks, colour_map: {})
|
|
94
112
|
puts ""
|
|
95
113
|
puts @pastel.bold(" Task Statistics")
|
|
96
114
|
puts @pastel.dim(" #{"─" * 60}")
|
|
@@ -98,12 +116,13 @@ module Tasku
|
|
|
98
116
|
total = tasks.length
|
|
99
117
|
by_status = tasks.group_by(&:status).transform_values(&:length)
|
|
100
118
|
by_priority = tasks.group_by(&:priority).transform_values(&:length)
|
|
119
|
+
by_project = tasks.group_by(&:project).transform_values(&:length)
|
|
101
120
|
overdue = tasks.count(&:overdue?)
|
|
102
|
-
|
|
121
|
+
project_count = tasks.map(&:project).compact.uniq.length
|
|
103
122
|
|
|
104
123
|
puts " #{@pastel.dim("Total tasks:".ljust(20))} #{total}"
|
|
105
124
|
puts " #{@pastel.dim("Overdue:".ljust(20))} #{overdue.positive? ? @pastel.red(overdue.to_s) : @pastel.green("0")}"
|
|
106
|
-
puts " #{@pastel.dim("Projects:".ljust(20))} #{
|
|
125
|
+
puts " #{@pastel.dim("Projects:".ljust(20))} #{project_count}"
|
|
107
126
|
puts ""
|
|
108
127
|
|
|
109
128
|
puts " #{@pastel.dim("By Status:")}"
|
|
@@ -122,16 +141,42 @@ module Tasku
|
|
|
122
141
|
|
|
123
142
|
puts " #{priority_tag(p)} #{@pastel.send(PRIORITY_STYLES.dig(p, :color) || :dim, count.to_s.rjust(3))}"
|
|
124
143
|
end
|
|
144
|
+
|
|
145
|
+
puts ""
|
|
146
|
+
puts " #{@pastel.dim("By Project:")}"
|
|
147
|
+
by_project.sort_by { |_, count| -count }.each do |name, count|
|
|
148
|
+
label = name || @pastel.dim("(none)")
|
|
149
|
+
coloured_name = name && colour_map[name] ? hex_colour_str(name, colour_map[name]) : label
|
|
150
|
+
padding = " " * [20 - strip_ansi(coloured_name).length, 0].max
|
|
151
|
+
puts " #{coloured_name}#{padding} #{@pastel.dim(count.to_s.rjust(3))}"
|
|
152
|
+
end
|
|
125
153
|
puts ""
|
|
126
154
|
end
|
|
127
155
|
|
|
128
156
|
private
|
|
129
157
|
|
|
130
|
-
def build_columns(task)
|
|
158
|
+
def build_columns(task, colour_map = {}, bar = {})
|
|
131
159
|
id_val = task.code && !task.code.empty? ? "#{task.code}-#{task.id}" : task.id.to_s
|
|
132
|
-
|
|
160
|
+
|
|
161
|
+
segments = []
|
|
162
|
+
if bar["bar_project"] != "off"
|
|
163
|
+
proj_colour = task.project && colour_map[task.project]
|
|
164
|
+
segments << (proj_colour ? hex_colour_str("█", proj_colour) : @pastel.dim("█"))
|
|
165
|
+
end
|
|
166
|
+
if bar["bar_priority"] != "off"
|
|
167
|
+
segments << hex_colour_str("█", PRIORITY_HEX[task.priority] || PRIORITY_HEX["none"])
|
|
168
|
+
end
|
|
169
|
+
if bar["bar_status"] != "off"
|
|
170
|
+
segments << hex_colour_str("█", STATUS_HEX[task.status] || STATUS_HEX["backlog"])
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
id_str = if segments.any?
|
|
174
|
+
"#{segments.join} #{@pastel.dim(id_val)}"
|
|
175
|
+
else
|
|
176
|
+
@pastel.dim(id_val)
|
|
177
|
+
end
|
|
133
178
|
name_str = @pastel.bold(task.name)
|
|
134
|
-
proj_str = task.project
|
|
179
|
+
proj_str = project_str(task.project, colour_map)
|
|
135
180
|
prio_str = priority_tag(task.priority)
|
|
136
181
|
stat_str = status_tag(task.status)
|
|
137
182
|
due_str = due_cell(task)
|
|
@@ -181,6 +226,21 @@ module Tasku
|
|
|
181
226
|
@pastel.send(style[:color], "#{style[:symbol]} #{label}")
|
|
182
227
|
end
|
|
183
228
|
|
|
229
|
+
def hex_colour_str(text, hex)
|
|
230
|
+
r, g, b = hex.delete("#").scan(/../).map { |c| c.to_i(16) }
|
|
231
|
+
"\e[38;2;#{r};#{g};#{b}m#{text}\e[0m"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def project_str(project, colour_map)
|
|
235
|
+
return @pastel.dim("—") unless project
|
|
236
|
+
|
|
237
|
+
colour = colour_map[project]
|
|
238
|
+
return project unless colour
|
|
239
|
+
|
|
240
|
+
r, g, b = colour.delete("#").scan(/../).map { |c| c.to_i(16) }
|
|
241
|
+
"\e[38;2;#{r};#{g};#{b}m#{project}\e[0m"
|
|
242
|
+
end
|
|
243
|
+
|
|
184
244
|
def due_cell(task)
|
|
185
245
|
return @pastel.dim("—") unless task.due_day
|
|
186
246
|
|
data/lib/tasku/version.rb
CHANGED
data/lib/tasku.rb
CHANGED
|
@@ -8,6 +8,12 @@ require_relative "tasku/version"
|
|
|
8
8
|
require_relative "tasku/database"
|
|
9
9
|
Tasku::Database.connect
|
|
10
10
|
require_relative "tasku/task"
|
|
11
|
+
require_relative "tasku/project"
|
|
12
|
+
require_relative "tasku/config"
|
|
11
13
|
require_relative "tasku/output/terminal"
|
|
12
14
|
require_relative "tasku/cli"
|
|
13
|
-
|
|
15
|
+
begin
|
|
16
|
+
require_relative "tasku/tui/app"
|
|
17
|
+
rescue LoadError
|
|
18
|
+
# TUI not available in this build
|
|
19
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tasku
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom Dringer
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-08-29 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: thor
|
|
@@ -89,8 +89,10 @@ files:
|
|
|
89
89
|
- exe/tasku
|
|
90
90
|
- lib/tasku.rb
|
|
91
91
|
- lib/tasku/cli.rb
|
|
92
|
+
- lib/tasku/config.rb
|
|
92
93
|
- lib/tasku/database.rb
|
|
93
94
|
- lib/tasku/output/terminal.rb
|
|
95
|
+
- lib/tasku/project.rb
|
|
94
96
|
- lib/tasku/task.rb
|
|
95
97
|
- lib/tasku/version.rb
|
|
96
98
|
homepage: https://github.com/tomdringer/tasku
|