lexdrill 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +52 -8
- data/lib/lexdrill/beat.rb +121 -0
- data/lib/lexdrill/cli.rb +72 -2
- data/lib/lexdrill/colorizer.rb +12 -2
- data/lib/lexdrill/config.rb +4 -0
- data/lib/lexdrill/default_words.rb +30 -0
- data/lib/lexdrill/format.rb +26 -0
- data/lib/lexdrill/inspector.rb +8 -0
- data/lib/lexdrill/line_formatter.rb +26 -4
- data/lib/lexdrill/version.rb +1 -1
- data/lib/lexdrill/word_list.rb +16 -4
- data/lib/lexdrill.rb +3 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ef368252ef581d3e56aadeef48302fef93cae68d52e95a5bb199977ffdf30fd
|
|
4
|
+
data.tar.gz: 7fb96023b0940dbce09e0cdb60d6561cc50ab52050c73536f777ca879f6f8c8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f0786367ac59cf02606f3c6a59dec98787bb54fc938924c90321d122e8e793bff09a357220c59f4d8a3d2e705ab621ae5fbbb46fc3cc02b787aac9e38063049
|
|
7
|
+
data.tar.gz: d7ec11ee093daff986f0dd1a08ac521bf6067f0e7debf682a8183cb940c17d5a58c5f5ef7aa68c257fdd184b09017734b03dfaad7c6c357e3f92ee64c09919bb
|
data/README.md
CHANGED
|
@@ -40,17 +40,28 @@ banana
|
|
|
40
40
|
cherry
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
If you don't create one, `drill next` seeds `~/.drill.txt` with a default
|
|
44
|
+
starter list (a set of NLP presuppositions) the first time it runs, so
|
|
45
|
+
there's always something to drill.
|
|
46
46
|
|
|
47
|
+
Run `drill next` to print the current word and advance to the next one.
|
|
48
|
+
There are two output styles (`drill format simple|full`, `simple` is the
|
|
49
|
+
default):
|
|
50
|
+
|
|
51
|
+
**simple** — the drill sign (always blue), a space, then the word (in a
|
|
52
|
+
separately-picked random color), all on one line:
|
|
47
53
|
```
|
|
48
|
-
|
|
49
|
-
2/3: banana
|
|
50
|
-
3/3: cherry
|
|
51
|
-
1/3: apple
|
|
54
|
+
⟳ apple
|
|
52
55
|
```
|
|
53
56
|
|
|
57
|
+
**full** — `counter/total⟳[loop_start-loop_end]` on one line, the word on
|
|
58
|
+
the next, in a randomly-picked color:
|
|
59
|
+
```
|
|
60
|
+
1/6⟳[1-3]
|
|
61
|
+
apple
|
|
62
|
+
```
|
|
63
|
+
(word 1 of 6 total; currently in the loop spanning words 1-3)
|
|
64
|
+
|
|
54
65
|
### Shell integration (one-time setup)
|
|
55
66
|
|
|
56
67
|
Add one line to your shell's rc file so the current word prints automatically
|
|
@@ -99,11 +110,44 @@ everything looks correctly configured.
|
|
|
99
110
|
hook block above, so it runs first) instead of relying on it only being in
|
|
100
111
|
`~/.zlogin` / `~/.bash_profile`. It's safe to leave it in both places.
|
|
101
112
|
|
|
113
|
+
### Rhythm (`beat`)
|
|
114
|
+
|
|
115
|
+
By default `next` just advances one word at a time. You can instead have it
|
|
116
|
+
repeat loops of consecutive words — e.g. a loop of 3 words shown twice each
|
|
117
|
+
before moving on:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
drill beat 3 2 # loop size 3, repeat each loop 2 times
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`drill beat none` turns it back off (plain word-by-word again). This is a
|
|
124
|
+
**global** setting — it applies everywhere, independent of which project's
|
|
125
|
+
`.drill.txt` is currently active.
|
|
126
|
+
|
|
127
|
+
There are also named shortcuts for common loop sizes, one word/phrase apart:
|
|
128
|
+
|
|
129
|
+
| Loop size | Alias |
|
|
130
|
+
|-----------|----------|
|
|
131
|
+
| 2 | `polka` |
|
|
132
|
+
| 3 | `waltz` |
|
|
133
|
+
| 4 | `rock` |
|
|
134
|
+
| 5 | `jazz` |
|
|
135
|
+
| 6 | `jiga` |
|
|
136
|
+
| 7 | `balkan` |
|
|
137
|
+
| 8 | `samba` |
|
|
138
|
+
|
|
139
|
+
`drill waltz 16` is shorthand for `drill beat 3 16`. Repetitions default to
|
|
140
|
+
`8` if you leave them off — `drill jazz` alone is `drill beat 5 8`, and
|
|
141
|
+
`drill beat 4` alone is `drill beat 4 8`.
|
|
142
|
+
|
|
102
143
|
### Commands
|
|
103
144
|
|
|
104
145
|
| Command | What it does |
|
|
105
146
|
|---|---|
|
|
106
147
|
| `drill next` | Print the current word and advance |
|
|
107
148
|
| `drill start` / `drill stop` | Pause/resume the automatic per-prompt hook (doesn't affect manual `next`) |
|
|
108
|
-
| `drill inspect` | Show the active `.drill.txt`/`.drill.counter` paths, word count, counter value, and
|
|
149
|
+
| `drill inspect` | Show the active `.drill.txt`/`.drill.counter` paths, word count, counter value, toggle, and beat state |
|
|
109
150
|
| `drill hook zsh\|bash` | Print the shell integration snippet (used above) |
|
|
151
|
+
| `drill beat <2-8> <repetitions>` / `drill beat none` | Set or disable the rhythm |
|
|
152
|
+
| `drill polka\|waltz\|rock\|jazz\|jiga\|balkan\|samba <repetitions>` | Shorthand for a fixed loop size (see table above) |
|
|
153
|
+
| `drill format simple\|full` | Set the output style (`simple` is the default) |
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
# Global rhythm config: repeats loops of `loop_size` consecutive words
|
|
6
|
+
# `repetitions` times before advancing to the next loop. Lives at
|
|
7
|
+
# ~/.drill.beat, independent of whichever project's .drill.txt is active.
|
|
8
|
+
# Disabled (plain word-by-word advance) unless explicitly configured.
|
|
9
|
+
module Lexdrill::Beat
|
|
10
|
+
PATH = File.join(Dir.home, ".drill.beat")
|
|
11
|
+
MIN_LOOP_SIZE = 2
|
|
12
|
+
MAX_LOOP_SIZE = 8
|
|
13
|
+
DEFAULT_REPETITIONS = 8
|
|
14
|
+
|
|
15
|
+
ALIASES = {
|
|
16
|
+
"polka" => 2,
|
|
17
|
+
"waltz" => 3,
|
|
18
|
+
"rock" => 4,
|
|
19
|
+
"jazz" => 5,
|
|
20
|
+
"jiga" => 6,
|
|
21
|
+
"balkan" => 7,
|
|
22
|
+
"samba" => 8
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
# index: 0-based word index. chunk_start/chunk_end: 1-based word positions
|
|
26
|
+
# spanned by the current loop. loop_number: which repeat pass (1-based)
|
|
27
|
+
# through the current loop. total_loops: the configured repetitions.
|
|
28
|
+
LoopInfo = Struct.new(:index, :chunk_start, :chunk_end, :loop_number, :total_loops, keyword_init: true)
|
|
29
|
+
|
|
30
|
+
def self.configured?
|
|
31
|
+
File.exist?(PATH)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.set(loop_size, repetitions)
|
|
35
|
+
File.write(PATH, "#{loop_size} #{repetitions}")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.clear
|
|
39
|
+
FileUtils.rm_f(PATH)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.valid_loop_size?(value)
|
|
43
|
+
(MIN_LOOP_SIZE..MAX_LOOP_SIZE).cover?(value)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.repetitions_or_default(value)
|
|
47
|
+
value ? value.to_i : DEFAULT_REPETITIONS
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.loop_size
|
|
51
|
+
settings[0]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.repetitions
|
|
55
|
+
settings[1]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Total steps in one full cycle through the word list at the current
|
|
59
|
+
# rhythm, or plain `word_count` when no beat is configured.
|
|
60
|
+
def self.cycle_length(word_count)
|
|
61
|
+
return word_count unless configured?
|
|
62
|
+
|
|
63
|
+
chunk_sizes(word_count).sum { |size| size * repetitions }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Maps a step (already bounded within cycle_length) to a word index.
|
|
67
|
+
def self.index_for(word_count, step)
|
|
68
|
+
loop_info(word_count, step).index
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Full detail on where `step` falls: word index, the current loop's word
|
|
72
|
+
# range, which repeat pass it is, and how many total. A single "loop"
|
|
73
|
+
# spanning the whole list (shown once) when no beat is configured.
|
|
74
|
+
def self.loop_info(word_count, step)
|
|
75
|
+
unless configured?
|
|
76
|
+
return LoopInfo.new(index: step, chunk_start: 1, chunk_end: word_count, loop_number: 1, total_loops: 1)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
locate(word_count, step)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def self.locate(word_count, step)
|
|
83
|
+
offset = 0
|
|
84
|
+
chunk_sizes(word_count).each do |size|
|
|
85
|
+
span = size * repetitions
|
|
86
|
+
return locate_within(offset, size, step) if step < span
|
|
87
|
+
|
|
88
|
+
step -= span
|
|
89
|
+
offset += size
|
|
90
|
+
end
|
|
91
|
+
LoopInfo.new(index: 0, chunk_start: 1, chunk_end: word_count, loop_number: 1, total_loops: 1)
|
|
92
|
+
end
|
|
93
|
+
private_class_method :locate
|
|
94
|
+
|
|
95
|
+
def self.locate_within(offset, size, step)
|
|
96
|
+
LoopInfo.new(
|
|
97
|
+
index: offset + (step % size),
|
|
98
|
+
chunk_start: offset + 1,
|
|
99
|
+
chunk_end: offset + size,
|
|
100
|
+
loop_number: (step / size) + 1,
|
|
101
|
+
total_loops: repetitions
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
private_class_method :locate_within
|
|
105
|
+
|
|
106
|
+
def self.settings
|
|
107
|
+
return [nil, nil] unless configured?
|
|
108
|
+
|
|
109
|
+
parts = File.read(PATH).strip.split
|
|
110
|
+
[parts[0].to_i, parts[1].to_i]
|
|
111
|
+
end
|
|
112
|
+
private_class_method :settings
|
|
113
|
+
|
|
114
|
+
def self.chunk_sizes(word_count)
|
|
115
|
+
full, remainder = word_count.divmod(loop_size)
|
|
116
|
+
sizes = Array.new(full, loop_size)
|
|
117
|
+
sizes << remainder if remainder.positive?
|
|
118
|
+
sizes
|
|
119
|
+
end
|
|
120
|
+
private_class_method :chunk_sizes
|
|
121
|
+
end
|
data/lib/lexdrill/cli.rb
CHANGED
|
@@ -8,7 +8,10 @@ class Lexdrill::CLI
|
|
|
8
8
|
run_hook: %w[hook],
|
|
9
9
|
run_start: %w[start],
|
|
10
10
|
run_stop: %w[stop],
|
|
11
|
-
run_inspect: %w[inspect]
|
|
11
|
+
run_inspect: %w[inspect],
|
|
12
|
+
run_beat: %w[beat],
|
|
13
|
+
run_beat_alias: %w[polka waltz rock jazz jiga balkan samba],
|
|
14
|
+
run_format: %w[format]
|
|
12
15
|
}.freeze
|
|
13
16
|
|
|
14
17
|
def self.start(argv = ARGV)
|
|
@@ -48,6 +51,11 @@ class Lexdrill::CLI
|
|
|
48
51
|
drill start Resume drilling (undoes stop)
|
|
49
52
|
drill stop Pause drilling everywhere until `start`
|
|
50
53
|
drill inspect Show the active config/counter/toggle state
|
|
54
|
+
drill beat <2-8> [repetitions] Set the rhythm (repetitions defaults to 8)
|
|
55
|
+
drill beat none Disable the rhythm
|
|
56
|
+
drill polka|waltz|rock|jazz|jiga|balkan|samba [repetitions]
|
|
57
|
+
Shorthand for a fixed loop size (2 through 8, in order)
|
|
58
|
+
drill format simple|full Set the output style (simple is the default)
|
|
51
59
|
HELP
|
|
52
60
|
0
|
|
53
61
|
end
|
|
@@ -56,10 +64,17 @@ class Lexdrill::CLI
|
|
|
56
64
|
word = Lexdrill::WordList.next
|
|
57
65
|
return print_no_words(Lexdrill::WordList::PATH) unless word
|
|
58
66
|
|
|
59
|
-
puts
|
|
67
|
+
puts colored_line(word)
|
|
60
68
|
0
|
|
61
69
|
end
|
|
62
70
|
|
|
71
|
+
def colored_line(word)
|
|
72
|
+
text = Lexdrill::LineFormatter.format(word)
|
|
73
|
+
return text if Lexdrill::Format.simple?
|
|
74
|
+
|
|
75
|
+
Lexdrill::Colorizer.paint(text)
|
|
76
|
+
end
|
|
77
|
+
|
|
63
78
|
def print_no_words(path)
|
|
64
79
|
warn "drill: no words found in #{path}"
|
|
65
80
|
1
|
|
@@ -100,6 +115,61 @@ class Lexdrill::CLI
|
|
|
100
115
|
0
|
|
101
116
|
end
|
|
102
117
|
|
|
118
|
+
def run_beat
|
|
119
|
+
arg = argv[1]
|
|
120
|
+
return print_beat_usage unless arg
|
|
121
|
+
return clear_beat if arg == "none"
|
|
122
|
+
|
|
123
|
+
set_beat(arg.to_i, Lexdrill::Beat.repetitions_or_default(argv[2]))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def run_beat_alias
|
|
127
|
+
loop_size = Lexdrill::Beat::ALIASES.fetch(argv.first)
|
|
128
|
+
set_beat(loop_size, Lexdrill::Beat.repetitions_or_default(argv[1]))
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def set_beat(loop_size, repetitions)
|
|
132
|
+
return print_invalid_loop_size unless Lexdrill::Beat.valid_loop_size?(loop_size)
|
|
133
|
+
return print_invalid_repetitions unless repetitions.positive?
|
|
134
|
+
|
|
135
|
+
Lexdrill::Beat.set(loop_size, repetitions)
|
|
136
|
+
0
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def clear_beat
|
|
140
|
+
Lexdrill::Beat.clear
|
|
141
|
+
0
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def print_beat_usage
|
|
145
|
+
warn "usage: drill beat <#{Lexdrill::Beat::MIN_LOOP_SIZE}-#{Lexdrill::Beat::MAX_LOOP_SIZE}> " \
|
|
146
|
+
"<repetitions> | drill beat none"
|
|
147
|
+
1
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def print_invalid_loop_size
|
|
151
|
+
warn "drill: loop size must be between #{Lexdrill::Beat::MIN_LOOP_SIZE} and #{Lexdrill::Beat::MAX_LOOP_SIZE}"
|
|
152
|
+
1
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def print_invalid_repetitions
|
|
156
|
+
warn "drill: repetitions must be a positive number"
|
|
157
|
+
1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def run_format
|
|
161
|
+
mode = argv[1]
|
|
162
|
+
return print_format_usage unless Lexdrill::Format::VALID.include?(mode)
|
|
163
|
+
|
|
164
|
+
Lexdrill::Format.set(mode)
|
|
165
|
+
0
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def print_format_usage
|
|
169
|
+
warn "usage: drill format <#{Lexdrill::Format::VALID.join('|')}>"
|
|
170
|
+
1
|
|
171
|
+
end
|
|
172
|
+
|
|
103
173
|
def print_unknown_command(command)
|
|
104
174
|
warn "drill: unknown command #{command.inspect}"
|
|
105
175
|
print_help
|
data/lib/lexdrill/colorizer.rb
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Wraps text in
|
|
3
|
+
# Wraps text in an ANSI color code.
|
|
4
4
|
module Lexdrill::Colorizer
|
|
5
5
|
CODES = [31, 32, 33, 34, 35, 36, 91, 92, 93, 94, 95, 96].freeze
|
|
6
|
+
BLUE = 34
|
|
6
7
|
|
|
7
8
|
def self.paint(text)
|
|
8
|
-
|
|
9
|
+
wrap(text, CODES.sample)
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.paint_blue(text)
|
|
13
|
+
wrap(text, BLUE)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.wrap(text, code)
|
|
17
|
+
"\e[#{code}m#{text}\e[0m"
|
|
18
|
+
end
|
|
19
|
+
private_class_method :wrap
|
|
10
20
|
end
|
data/lib/lexdrill/config.rb
CHANGED
|
@@ -13,6 +13,10 @@ module Lexdrill::Config
|
|
|
13
13
|
ENV.fetch("LEXDRILL_PATH", nil) || dir_path || Dir.home
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def self.home_drill_path
|
|
17
|
+
File.join(Dir.home, FILENAME)
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
DRILL_PATH = File.join(base_path, FILENAME)
|
|
17
21
|
COUNTER_PATH = File.join(base_path, COUNTER_FILENAME)
|
|
18
22
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The starter list seeded into ~/.drill.txt on first run, when neither an
|
|
4
|
+
# LEXDRILL_PATH override nor a project-local .drill.txt exists yet.
|
|
5
|
+
module Lexdrill::DefaultWords
|
|
6
|
+
WORDS = [
|
|
7
|
+
"The map is not the territory",
|
|
8
|
+
"Respect for other people's model of the world",
|
|
9
|
+
"Mind and body are parts of the same system",
|
|
10
|
+
"You cannot not communicate",
|
|
11
|
+
"The meaning of your communication is the response you get",
|
|
12
|
+
"People operate out of the best choice available to them",
|
|
13
|
+
"Every behavior has a positive intention",
|
|
14
|
+
"People have all the resources they need to succeed",
|
|
15
|
+
"There is no failure only feedback",
|
|
16
|
+
"If what you are doing isn't working do something else",
|
|
17
|
+
"The person with the most flexibility controls the system",
|
|
18
|
+
"Choice is better than no choice",
|
|
19
|
+
"If one person can do something anyone can learn to do it",
|
|
20
|
+
"Modeling successful performance leads to excellence",
|
|
21
|
+
"All procedures should increase wholeness and choice",
|
|
22
|
+
"Individuals are not their behaviors",
|
|
23
|
+
"Resistance in a listener is a sign of a lack of flexibility in the communicator",
|
|
24
|
+
"We process all information through our five senses",
|
|
25
|
+
"Clean feedback is the breakfast of champions",
|
|
26
|
+
"Possible in the world is possible for me it is only a matter of how"
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
TEXT = "#{WORDS.join("\n")}\n".freeze
|
|
30
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Global display mode for `next`'s output: "simple" (the drill sign + word)
|
|
4
|
+
# or "full" (position + loop info). Lives at ~/.drill.format; defaults to
|
|
5
|
+
# "simple".
|
|
6
|
+
module Lexdrill::Format
|
|
7
|
+
PATH = File.join(Dir.home, ".drill.format")
|
|
8
|
+
SIMPLE = "simple"
|
|
9
|
+
FULL = "full"
|
|
10
|
+
VALID = [SIMPLE, FULL].freeze
|
|
11
|
+
|
|
12
|
+
def self.current
|
|
13
|
+
return SIMPLE unless File.exist?(PATH)
|
|
14
|
+
|
|
15
|
+
value = File.read(PATH).strip
|
|
16
|
+
VALID.include?(value) ? value : SIMPLE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.set(mode)
|
|
20
|
+
File.write(PATH, mode)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.simple?
|
|
24
|
+
current == SIMPLE
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/lexdrill/inspector.rb
CHANGED
|
@@ -11,6 +11,8 @@ module Lexdrill::Inspector
|
|
|
11
11
|
Words file: #{Lexdrill::WordList::PATH} (#{words_summary})
|
|
12
12
|
Counter file: #{Lexdrill::WordList::COUNTER_PATH} (value: #{counter_value})
|
|
13
13
|
Toggle: #{toggle_summary}
|
|
14
|
+
Beat: #{beat_summary}
|
|
15
|
+
Format: #{Lexdrill::Format.current}
|
|
14
16
|
LEXDRILL_PATH: #{ENV.fetch('LEXDRILL_PATH', '(not set)')}
|
|
15
17
|
REPORT
|
|
16
18
|
end
|
|
@@ -30,4 +32,10 @@ module Lexdrill::Inspector
|
|
|
30
32
|
|
|
31
33
|
"stopped (#{Lexdrill::Toggle::PATH})"
|
|
32
34
|
end
|
|
35
|
+
|
|
36
|
+
def self.beat_summary
|
|
37
|
+
return "not set (plain word-by-word)" unless Lexdrill::Beat.configured?
|
|
38
|
+
|
|
39
|
+
"loop #{Lexdrill::Beat.loop_size}, repeat #{Lexdrill::Beat.repetitions}"
|
|
40
|
+
end
|
|
33
41
|
end
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Formats a shown word
|
|
4
|
-
#
|
|
3
|
+
# Formats a shown word for display. In "simple" mode: the drill sign (in
|
|
4
|
+
# blue), a space, then the word (in a separately-picked random color), all
|
|
5
|
+
# on one line. In "full" mode (the default):
|
|
6
|
+
# "{counter}/{total}{SEPARATOR}[{loop_start}-{loop_end}]\n{word}" — counter
|
|
7
|
+
# is the word's own 1-based position in the list, re-derived through
|
|
8
|
+
# Lexdrill::Beat so it stays meaningful even when a rhythm repeats steps.
|
|
5
9
|
module Lexdrill::LineFormatter
|
|
10
|
+
SEPARATOR = "⟳"
|
|
11
|
+
|
|
6
12
|
def self.format(word)
|
|
13
|
+
return simple(word) if Lexdrill::Format.simple?
|
|
14
|
+
|
|
15
|
+
full(word)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.simple(word)
|
|
19
|
+
"#{Lexdrill::Colorizer.paint_blue(SEPARATOR)} #{Lexdrill::Colorizer.paint(word)}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.full(word)
|
|
7
23
|
total = Lexdrill::WordList.words.size
|
|
8
|
-
|
|
9
|
-
"#{
|
|
24
|
+
info = loop_info(total)
|
|
25
|
+
"#{info.index + 1}/#{total}#{SEPARATOR}[#{info.chunk_start}-#{info.chunk_end}]\n#{word}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.loop_info(total)
|
|
29
|
+
counter = Lexdrill::Counter.new(Lexdrill::WordList::COUNTER_PATH)
|
|
30
|
+
step_used = counter.value - 1
|
|
31
|
+
Lexdrill::Beat.loop_info(total, step_used)
|
|
10
32
|
end
|
|
11
33
|
end
|
data/lib/lexdrill/version.rb
CHANGED
data/lib/lexdrill/word_list.rb
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Reads vocabulary words/phrases from a `.drill.txt` file, one per line, and
|
|
4
|
-
# advances a persisted counter to show "the current word" each time.
|
|
4
|
+
# advances a persisted counter to show "the current word" each time. On a
|
|
5
|
+
# fresh install with no project-local or LEXDRILL_PATH-overridden list, seeds
|
|
6
|
+
# ~/.drill.txt with a default starter list instead of coming up empty.
|
|
5
7
|
class Lexdrill::WordList
|
|
6
8
|
PATH = Lexdrill::Config::DRILL_PATH
|
|
7
9
|
COUNTER_PATH = Lexdrill::Config::COUNTER_PATH
|
|
10
|
+
HOME_PATH = Lexdrill::Config.home_drill_path
|
|
8
11
|
|
|
9
12
|
def self.words
|
|
10
|
-
|
|
13
|
+
seed_default_at_home
|
|
14
|
+
@words ||= File.exist?(PATH) && File.readlines(PATH, encoding: "UTF-8").map(&:strip).reject(&:empty?)
|
|
11
15
|
@words ||= []
|
|
12
16
|
end
|
|
13
17
|
|
|
18
|
+
def self.seed_default_at_home
|
|
19
|
+
return if PATH != HOME_PATH || File.exist?(PATH)
|
|
20
|
+
|
|
21
|
+
File.write(PATH, Lexdrill::DefaultWords::TEXT, encoding: "UTF-8")
|
|
22
|
+
end
|
|
23
|
+
private_class_method :seed_default_at_home
|
|
24
|
+
|
|
14
25
|
def self.next
|
|
15
26
|
return nil if words.empty?
|
|
16
27
|
|
|
@@ -19,8 +30,9 @@ class Lexdrill::WordList
|
|
|
19
30
|
|
|
20
31
|
def self.take_index(size)
|
|
21
32
|
counter = Lexdrill::Counter.new(COUNTER_PATH)
|
|
22
|
-
|
|
33
|
+
cycle_length = Lexdrill::Beat.cycle_length(size)
|
|
34
|
+
step = counter.bounded_value(cycle_length)
|
|
23
35
|
counter.increment
|
|
24
|
-
|
|
36
|
+
Lexdrill::Beat.index_for(size, step)
|
|
25
37
|
end
|
|
26
38
|
end
|
data/lib/lexdrill.rb
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
require_relative "lexdrill/version"
|
|
4
4
|
require_relative "lexdrill/config"
|
|
5
5
|
require_relative "lexdrill/counter"
|
|
6
|
+
require_relative "lexdrill/beat"
|
|
7
|
+
require_relative "lexdrill/default_words"
|
|
6
8
|
require_relative "lexdrill/word_list"
|
|
7
9
|
require_relative "lexdrill/toggle"
|
|
8
10
|
require_relative "lexdrill/shell_snippet"
|
|
9
11
|
require_relative "lexdrill/inspector"
|
|
10
12
|
require_relative "lexdrill/colorizer"
|
|
13
|
+
require_relative "lexdrill/format"
|
|
11
14
|
require_relative "lexdrill/line_formatter"
|
|
12
15
|
require_relative "lexdrill/cli"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lexdrill
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Siarhei Kisliak
|
|
@@ -25,10 +25,13 @@ files:
|
|
|
25
25
|
- bin/drill
|
|
26
26
|
- lexdrill.gemspec
|
|
27
27
|
- lib/lexdrill.rb
|
|
28
|
+
- lib/lexdrill/beat.rb
|
|
28
29
|
- lib/lexdrill/cli.rb
|
|
29
30
|
- lib/lexdrill/colorizer.rb
|
|
30
31
|
- lib/lexdrill/config.rb
|
|
31
32
|
- lib/lexdrill/counter.rb
|
|
33
|
+
- lib/lexdrill/default_words.rb
|
|
34
|
+
- lib/lexdrill/format.rb
|
|
32
35
|
- lib/lexdrill/inspector.rb
|
|
33
36
|
- lib/lexdrill/line_formatter.rb
|
|
34
37
|
- lib/lexdrill/shell_snippet.rb
|