tasku 0.3.1 → 0.3.9
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/lib/tasku/cli.rb +5 -1
- data/lib/tasku/output/terminal.rb +26 -0
- data/lib/tasku/tui/mado_list.rb +127 -0
- data/lib/tasku/version.rb +1 -1
- data/lib/tasku.rb +5 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74f35cfb28f9ec9b5b7cc0ce5a0a62028d7162faa7ed1a8e9efedb4f63fa2638
|
|
4
|
+
data.tar.gz: a064d7fa64823a9f3362e9220b4bc69311f2c20f21e10e6ae85501ed5f5f92de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93955913ae30ae85a403b3e11977739d64eac51c1fbebfeb97f07b6beac7149bba991e7da74f067778838f7fdda455ebfe6d74f273cc83e5239daaedc697be48
|
|
7
|
+
data.tar.gz: 0033c68f813e016cb2891fb7ed63e29d736f14460f18617fe021dbeeace9dc46c08639fc25f8764c1ccd0961edea2ad151225677ca7fb561e7214531706e338d
|
data/lib/tasku/cli.rb
CHANGED
|
@@ -210,7 +210,11 @@ module Tasku
|
|
|
210
210
|
|
|
211
211
|
tasks = dataset.all
|
|
212
212
|
bar = { "bar_project" => Config.get("bar_project"), "bar_priority" => Config.get("bar_priority"), "bar_status" => Config.get("bar_status") }
|
|
213
|
-
|
|
213
|
+
if ENV["MADO"] == "1"
|
|
214
|
+
Tasku::TUI::MadoList.new(tasks, colour_map: Project.colour_map, bar: bar).run
|
|
215
|
+
else
|
|
216
|
+
terminal.render_list(tasks, colour_map: Project.colour_map, spacing: Config.get("list_spacing"), bar: bar)
|
|
217
|
+
end
|
|
214
218
|
end
|
|
215
219
|
|
|
216
220
|
desc "show ID", "Show task details"
|
|
@@ -153,6 +153,24 @@ module Tasku
|
|
|
153
153
|
puts ""
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
+
# Returns an array of pre-formatted row strings for MadoList.
|
|
157
|
+
# Accounts for the "[>] " prefix (4 extra chars) when computing widths.
|
|
158
|
+
def build_mado_rows(tasks, colour_map = {}, bar = {})
|
|
159
|
+
return [] if tasks.empty?
|
|
160
|
+
|
|
161
|
+
orig_width = @term_width
|
|
162
|
+
@term_width = [@term_width - 4, 40].max
|
|
163
|
+
|
|
164
|
+
col_rows = tasks.map { |t| build_columns(t, colour_map, bar) }
|
|
165
|
+
col_widths = compute_widths(col_rows)
|
|
166
|
+
result = col_rows.map do |cols|
|
|
167
|
+
cols.each_with_index.map { |c, i| ansi_ljust(c.to_s, col_widths[i]) }.join(COL_SEP)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
@term_width = orig_width
|
|
171
|
+
result
|
|
172
|
+
end
|
|
173
|
+
|
|
156
174
|
private
|
|
157
175
|
|
|
158
176
|
def build_columns(task, colour_map = {}, bar = {})
|
|
@@ -209,6 +227,14 @@ module Tasku
|
|
|
209
227
|
str.gsub(/\e\[[0-9;]*m/, "")
|
|
210
228
|
end
|
|
211
229
|
|
|
230
|
+
# Pad an ANSI-coloured string to `width` visible characters.
|
|
231
|
+
# String#ljust counts bytes (including escape codes), so we compute
|
|
232
|
+
# the visible length ourselves and append plain spaces for the deficit.
|
|
233
|
+
def ansi_ljust(str, width)
|
|
234
|
+
deficit = width - strip_ansi(str).length
|
|
235
|
+
deficit > 0 ? str + (" " * deficit) : str
|
|
236
|
+
end
|
|
237
|
+
|
|
212
238
|
def terminal_width
|
|
213
239
|
IO.console&.winsize&.[](1) || 80
|
|
214
240
|
rescue
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "io/console"
|
|
4
|
+
require "pastel"
|
|
5
|
+
|
|
6
|
+
module Tasku
|
|
7
|
+
module TUI
|
|
8
|
+
# Interactive cursor-based task list for the Mado terminal multiplexer.
|
|
9
|
+
# Triggered when ENV["MADO"] == "1". Arrow keys move the cursor; the
|
|
10
|
+
# selected task's ID is written to ENV["TASKU_SEL_FILE"] so that Mado
|
|
11
|
+
# button handlers can inject it into commands like `tasku edit <id>`.
|
|
12
|
+
class MadoList
|
|
13
|
+
HINT = " ↑↓ navigate a add e/↵ edit d delete q quit"
|
|
14
|
+
|
|
15
|
+
def initialize(tasks, colour_map: {}, bar: {})
|
|
16
|
+
@tasks = tasks
|
|
17
|
+
@cursor = 0
|
|
18
|
+
@pastel = Pastel.new
|
|
19
|
+
@sel_file = ENV["TASKU_SEL_FILE"]
|
|
20
|
+
@running = true
|
|
21
|
+
|
|
22
|
+
# Pre-render row content once so key-press redraws are cheap.
|
|
23
|
+
@rows = Output::Terminal.new.build_mado_rows(tasks, colour_map, bar)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
return if @tasks.empty?
|
|
28
|
+
|
|
29
|
+
write_selection
|
|
30
|
+
|
|
31
|
+
$stdout.print "\e[?25l" # hide cursor
|
|
32
|
+
at_exit { restore_terminal }
|
|
33
|
+
trap("INT") { @running = false }
|
|
34
|
+
|
|
35
|
+
$stdin.raw do |io|
|
|
36
|
+
full_render
|
|
37
|
+
while @running
|
|
38
|
+
prev = @cursor
|
|
39
|
+
key = read_key(io)
|
|
40
|
+
handle_key(key)
|
|
41
|
+
full_render if @running && @cursor != prev
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def write_selection
|
|
49
|
+
return unless @sel_file
|
|
50
|
+
File.write(@sel_file, @tasks[@cursor].id.to_s)
|
|
51
|
+
rescue StandardError
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Full clear + repaint (initial draw or after a command).
|
|
56
|
+
def full_render
|
|
57
|
+
$stdout.print "\e[H\e[J" # cursor home, clear to end of screen
|
|
58
|
+
@rows.each_with_index do |row, i|
|
|
59
|
+
marker = i == @cursor ? @pastel.bright_blue("[>]") : @pastel.dim("[ ]")
|
|
60
|
+
$stdout.print " #{marker} #{row}\r\n"
|
|
61
|
+
end
|
|
62
|
+
$stdout.print "\r\n#{@pastel.dim(HINT)}\r\n"
|
|
63
|
+
$stdout.flush
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def read_key(io)
|
|
67
|
+
byte = io.getbyte
|
|
68
|
+
case byte
|
|
69
|
+
when 0x1B
|
|
70
|
+
second = io.getbyte
|
|
71
|
+
if second == 0x5B
|
|
72
|
+
case io.getbyte
|
|
73
|
+
when 0x41 then :up
|
|
74
|
+
when 0x42 then :down
|
|
75
|
+
else nil
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
:escape
|
|
79
|
+
end
|
|
80
|
+
when 0x03 then :ctrl_c
|
|
81
|
+
when 0x0D, 0x0A then :enter # Return / Enter
|
|
82
|
+
when 0x61 then :add # a
|
|
83
|
+
when 0x64 then :delete # d
|
|
84
|
+
when 0x65 then :edit # e
|
|
85
|
+
when 0x71 then :q # q
|
|
86
|
+
else nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def handle_key(key)
|
|
91
|
+
case key
|
|
92
|
+
when :up
|
|
93
|
+
@cursor = [@cursor - 1, 0].max
|
|
94
|
+
write_selection
|
|
95
|
+
when :down
|
|
96
|
+
@cursor = [@cursor + 1, @tasks.length - 1].min
|
|
97
|
+
write_selection
|
|
98
|
+
when :q, :ctrl_c, :escape
|
|
99
|
+
@running = false
|
|
100
|
+
when :add
|
|
101
|
+
run_command("tasku add -i")
|
|
102
|
+
when :edit, :enter
|
|
103
|
+
return if @tasks.empty?
|
|
104
|
+
run_command("tasku edit #{@tasks[@cursor].id} -i")
|
|
105
|
+
when :delete
|
|
106
|
+
return if @tasks.empty?
|
|
107
|
+
run_command("tasku delete #{@tasks[@cursor].id} -f")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Restore the terminal, run a tasku command interactively, then re-exec
|
|
112
|
+
# `tasku list` so the MadoList restarts fresh with updated data.
|
|
113
|
+
def run_command(cmd)
|
|
114
|
+
@running = false
|
|
115
|
+
restore_terminal
|
|
116
|
+
system(cmd)
|
|
117
|
+
exec("tasku list")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def restore_terminal
|
|
121
|
+
$stdout.print "\e[?25h\e[0m"
|
|
122
|
+
rescue IOError
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
data/lib/tasku/version.rb
CHANGED
data/lib/tasku.rb
CHANGED
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.3.
|
|
4
|
+
version: 0.3.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom Dringer
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: thor
|
|
@@ -94,6 +94,7 @@ files:
|
|
|
94
94
|
- lib/tasku/output/terminal.rb
|
|
95
95
|
- lib/tasku/project.rb
|
|
96
96
|
- lib/tasku/task.rb
|
|
97
|
+
- lib/tasku/tui/mado_list.rb
|
|
97
98
|
- lib/tasku/version.rb
|
|
98
99
|
homepage: https://github.com/tomdringer/tasku
|
|
99
100
|
licenses:
|
|
@@ -116,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
116
117
|
- !ruby/object:Gem::Version
|
|
117
118
|
version: '0'
|
|
118
119
|
requirements: []
|
|
119
|
-
rubygems_version:
|
|
120
|
+
rubygems_version: 4.0.20
|
|
120
121
|
specification_version: 4
|
|
121
122
|
summary: タスクリスト — a beautiful terminal task manager
|
|
122
123
|
test_files: []
|