lexdrill 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ee9e8bd1de6b7fc437375184394a0ce42d61d9648320e6a31e83bf575cfc885
4
- data.tar.gz: 27836a51638dbd08eb53a1d6f6808d94a0fb27c8e4b93cd831e96c2f5b0abe64
3
+ metadata.gz: 0510a355aeb50c560e27a73fd9ab70350c8e5c326d5dbd0ad43138e849b0bd2f
4
+ data.tar.gz: 529f2a86af2ec0b735c3147bd412fe82d276f6d434e6a074deefb650270818eb
5
5
  SHA512:
6
- metadata.gz: cb860ea6fb40050205abbbdc2078d1a3e5b4f624629bb1b769a33c7bd1de3e22452d65265017cd0e7597bde5d934b04c568e96ab8f2643678392dfe86a8e2dc6
7
- data.tar.gz: edbe4b9f27ced36534b9f3816840feb9216728288077af785292b12015d765db0c96170a0f8f79dc9182926323b3404517abd237ff51b47747901fb4e93632a7
6
+ metadata.gz: d9168c8d3218c457b6cf08662254d7b69f6adaef33cb1962a1dbcf4a0243c653bffbd9a74580e5cd7dbdcce9118fe0406b221d72f42b7347525a3a0adc93ee20
7
+ data.tar.gz: 552834f01e378765ddf7549410ad964dc254c8c286bc34605f765661f68fb232100003dedad70c18fe025e8215cdba250d0c37f0a60338f235647f3335bb1eee
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # lexdrill
2
2
 
3
- lexdrill prints a vocabulary word or phrase on demand, tracking how often each one has been shown.
3
+ The `lexdrill` gem installs a `drill` command that prints a vocabulary word or
4
+ phrase on demand, tracking how often each one has been shown.
4
5
 
5
6
  ## Installation
6
7
 
@@ -8,7 +9,7 @@ lexdrill prints a vocabulary word or phrase on demand, tracking how often each o
8
9
  gem install lexdrill
9
10
  ```
10
11
 
11
- ### `lexdrill: command not found` after install?
12
+ ### `drill: command not found` after install?
12
13
 
13
14
  This happens when the gem's executable directory isn't on your `PATH` — common with a
14
15
  plain system Ruby (no rbenv/rvm). Fix it in one step:
@@ -27,3 +28,123 @@ source ~/.zshrc
27
28
 
28
29
  Using an rbenv-managed Ruby? Run `rbenv rehash` instead. Using rvm? You shouldn't hit
29
30
  this — rvm keeps gem executable directories on `PATH` automatically.
31
+
32
+ ## Usage
33
+
34
+ Create a `.drill.txt` file — one word or phrase per line — in your home directory,
35
+ or in a specific project directory to give that project its own list:
36
+
37
+ ```
38
+ apple
39
+ banana
40
+ cherry
41
+ ```
42
+
43
+ Run `drill next` to print the current word and advance to the next one.
44
+ There are two output styles (`drill format simple|full`, `full` is the
45
+ default):
46
+
47
+ **full** — `counter/total⟳[loop_start-loop_end]` on one line, the word on
48
+ the next, in a randomly-picked color:
49
+ ```
50
+ 1/6⟳[1-3]
51
+ apple
52
+ ```
53
+ (word 1 of 6 total; currently in the loop spanning words 1-3)
54
+
55
+ **simple** — three drill signs (always blue), then the word on its own
56
+ line in a separately-picked random color:
57
+ ```
58
+ ⟳⟳⟳
59
+ apple
60
+ ```
61
+
62
+ ### Shell integration (one-time setup)
63
+
64
+ Add one line to your shell's rc file so the current word prints automatically
65
+ before each prompt. This is a **one-time step** — the line stays in your rc file
66
+ and takes effect in every new shell session from then on; you never need to run it
67
+ again by hand.
68
+
69
+ Add it near the **end** of the file, after anything that sets up your `PATH`
70
+ (rvm/rbenv init, Homebrew, etc.) — otherwise the shell may not know where
71
+ `drill` lives yet when this line runs. Guarding it with `command -v` also
72
+ means it never errors, even on a machine/session where `drill` isn't on
73
+ `PATH` for some reason.
74
+
75
+ **zsh** — add to `~/.zshrc`:
76
+ ```zsh
77
+ if command -v drill >/dev/null 2>&1; then
78
+ eval "$(drill hook zsh)"
79
+ fi
80
+ ```
81
+
82
+ **bash** — add to `~/.bashrc`:
83
+ ```bash
84
+ if command -v drill >/dev/null 2>&1; then
85
+ eval "$(drill hook bash)"
86
+ fi
87
+ ```
88
+
89
+ Then open a new shell (or `source ~/.zshrc` / `source ~/.bashrc`) to pick it up.
90
+
91
+ #### Hook not firing in new terminal windows/tabs (rvm users)?
92
+
93
+ Run `drill inspect` first — if it shows `Toggle: enabled` and a valid words
94
+ file, the tool itself is fine and the problem is that the hook function never
95
+ got registered in that session.
96
+
97
+ A common cause with rvm: rvm's installer sometimes puts its actual
98
+ PATH-loading line (`[[ -s "$HOME/.rvm/scripts/rvm" ]] && source
99
+ "$HOME/.rvm/scripts/rvm"`) in `~/.zlogin` (zsh) or `~/.bash_profile` (bash).
100
+ Those files only run for **login shells** — but many terminal emulators
101
+ (e.g. kitty) open new windows/tabs as **non-login** interactive shells, which
102
+ only source `~/.zshrc`/`~/.bashrc`. So rvm's gemset `bin/` directory (where
103
+ `drill` lives) never makes it onto `PATH` in those sessions, even though
104
+ everything looks correctly configured.
105
+
106
+ **Fix:** move that line into `~/.zshrc` / `~/.bashrc` (before the `drill`
107
+ hook block above, so it runs first) instead of relying on it only being in
108
+ `~/.zlogin` / `~/.bash_profile`. It's safe to leave it in both places.
109
+
110
+ ### Rhythm (`beat`)
111
+
112
+ By default `next` just advances one word at a time. You can instead have it
113
+ repeat loops of consecutive words — e.g. a loop of 3 words shown twice each
114
+ before moving on:
115
+
116
+ ```bash
117
+ drill beat 3 2 # loop size 3, repeat each loop 2 times
118
+ ```
119
+
120
+ `drill beat none` turns it back off (plain word-by-word again). This is a
121
+ **global** setting — it applies everywhere, independent of which project's
122
+ `.drill.txt` is currently active.
123
+
124
+ There are also named shortcuts for common loop sizes, one word/phrase apart:
125
+
126
+ | Loop size | Alias |
127
+ |-----------|----------|
128
+ | 2 | `polka` |
129
+ | 3 | `waltz` |
130
+ | 4 | `rock` |
131
+ | 5 | `jazz` |
132
+ | 6 | `jiga` |
133
+ | 7 | `balkan` |
134
+ | 8 | `samba` |
135
+
136
+ `drill waltz 16` is shorthand for `drill beat 3 16`. Repetitions default to
137
+ `8` if you leave them off — `drill jazz` alone is `drill beat 5 8`, and
138
+ `drill beat 4` alone is `drill beat 4 8`.
139
+
140
+ ### Commands
141
+
142
+ | Command | What it does |
143
+ |---|---|
144
+ | `drill next` | Print the current word and advance |
145
+ | `drill start` / `drill stop` | Pause/resume the automatic per-prompt hook (doesn't affect manual `next`) |
146
+ | `drill inspect` | Show the active `.drill.txt`/`.drill.counter` paths, word count, counter value, toggle, and beat state |
147
+ | `drill hook zsh\|bash` | Print the shell integration snippet (used above) |
148
+ | `drill beat <2-8> <repetitions>` / `drill beat none` | Set or disable the rhythm |
149
+ | `drill polka\|waltz\|rock\|jazz\|jiga\|balkan\|samba <repetitions>` | Shorthand for a fixed loop size (see table above) |
150
+ | `drill format simple\|full` | Set the output style (`full` is the default) |
data/lexdrill.gemspec CHANGED
@@ -23,6 +23,6 @@ Gem::Specification.new do |spec|
23
23
  Dir["lib/**/*.rb"] + Dir["bin/*"] + %w[README.md LICENSE.txt lexdrill.gemspec Gemfile]
24
24
  end
25
25
  spec.bindir = "bin"
26
- spec.executables = ["lexdrill"]
26
+ spec.executables = ["drill"]
27
27
  spec.require_paths = ["lib"]
28
28
  end
@@ -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
@@ -4,7 +4,14 @@ class Lexdrill::CLI
4
4
  COMMANDS = {
5
5
  print_version: %w[version --version -v],
6
6
  print_help: %w[help --help -h],
7
- run_next: %w[next]
7
+ run_next: %w[next],
8
+ run_hook: %w[hook],
9
+ run_start: %w[start],
10
+ run_stop: %w[stop],
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]
8
15
  }.freeze
9
16
 
10
17
  def self.start(argv = ARGV)
@@ -34,12 +41,21 @@ class Lexdrill::CLI
34
41
 
35
42
  def print_help
36
43
  puts <<~HELP
37
- lexdrill #{Lexdrill::VERSION} — vocabulary drilling in your terminal
44
+ drill #{Lexdrill::VERSION} — vocabulary drilling in your terminal
38
45
 
39
46
  Usage:
40
- lexdrill version Print the gem version
41
- lexdrill help Show this help
42
- lexdrill next Print the current word and advance
47
+ drill version Print the gem version
48
+ drill help Show this help
49
+ drill next Print the current word and advance
50
+ drill hook <zsh|bash> Print the shell integration snippet
51
+ drill start Resume drilling (undoes stop)
52
+ drill stop Pause drilling everywhere until `start`
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 (full is the default)
43
59
  HELP
44
60
  0
45
61
  end
@@ -48,17 +64,114 @@ class Lexdrill::CLI
48
64
  word = Lexdrill::WordList.next
49
65
  return print_no_words(Lexdrill::WordList::PATH) unless word
50
66
 
51
- puts word
67
+ puts colored_line(word)
52
68
  0
53
69
  end
54
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
+
55
78
  def print_no_words(path)
56
- warn "lexdrill: no words found in #{path}"
79
+ warn "drill: no words found in #{path}"
80
+ 1
81
+ end
82
+
83
+ def run_hook
84
+ shell = argv[1]
85
+ return print_hook_usage unless shell
86
+
87
+ print_hook_snippet(shell)
88
+ end
89
+
90
+ def print_hook_usage
91
+ warn "usage: drill hook <zsh|bash>"
92
+ 1
93
+ end
94
+
95
+ def print_hook_snippet(shell)
96
+ puts Lexdrill::ShellSnippet.for(shell)
97
+ 0
98
+ rescue ArgumentError => error
99
+ warn "drill: #{error.message}"
100
+ 1
101
+ end
102
+
103
+ def run_start
104
+ Lexdrill::Toggle.start
105
+ 0
106
+ end
107
+
108
+ def run_stop
109
+ Lexdrill::Toggle.stop
110
+ 0
111
+ end
112
+
113
+ def run_inspect
114
+ puts Lexdrill::Inspector.report
115
+ 0
116
+ end
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('|')}>"
57
170
  1
58
171
  end
59
172
 
60
173
  def print_unknown_command(command)
61
- warn "lexdrill: unknown command #{command.inspect}"
174
+ warn "drill: unknown command #{command.inspect}"
62
175
  print_help
63
176
  1
64
177
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Wraps text in an ANSI color code.
4
+ module Lexdrill::Colorizer
5
+ CODES = [31, 32, 33, 34, 35, 36, 91, 92, 93, 94, 95, 96].freeze
6
+ BLUE = 34
7
+
8
+ def self.paint(text)
9
+ wrap(text, CODES.sample)
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
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Global display mode for `next`'s output: "full" (position + loop info) or
4
+ # "simple" (just the word). Lives at ~/.drill.format; defaults to "full".
5
+ module Lexdrill::Format
6
+ PATH = File.join(Dir.home, ".drill.format")
7
+ SIMPLE = "simple"
8
+ FULL = "full"
9
+ VALID = [SIMPLE, FULL].freeze
10
+
11
+ def self.current
12
+ return FULL unless File.exist?(PATH)
13
+
14
+ value = File.read(PATH).strip
15
+ VALID.include?(value) ? value : FULL
16
+ end
17
+
18
+ def self.set(mode)
19
+ File.write(PATH, mode)
20
+ end
21
+
22
+ def self.simple?
23
+ current == SIMPLE
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Builds a human-readable snapshot of lexdrill's current config/state, for
4
+ # `drill inspect` — which files are active, how many words, the counter
5
+ # value, and whether drilling is currently stopped.
6
+ module Lexdrill::Inspector
7
+ def self.report
8
+ <<~REPORT
9
+ drill #{Lexdrill::VERSION}
10
+
11
+ Words file: #{Lexdrill::WordList::PATH} (#{words_summary})
12
+ Counter file: #{Lexdrill::WordList::COUNTER_PATH} (value: #{counter_value})
13
+ Toggle: #{toggle_summary}
14
+ Beat: #{beat_summary}
15
+ Format: #{Lexdrill::Format.current}
16
+ LEXDRILL_PATH: #{ENV.fetch('LEXDRILL_PATH', '(not set)')}
17
+ REPORT
18
+ end
19
+
20
+ def self.words_summary
21
+ return "missing" unless File.exist?(Lexdrill::WordList::PATH)
22
+
23
+ "#{Lexdrill::WordList.words.size} word(s)"
24
+ end
25
+
26
+ def self.counter_value
27
+ Lexdrill::Counter.new(Lexdrill::WordList::COUNTER_PATH).value
28
+ end
29
+
30
+ def self.toggle_summary
31
+ return "enabled" if Lexdrill::Toggle.enabled?
32
+
33
+ "stopped (#{Lexdrill::Toggle::PATH})"
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
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Formats a shown word for display. In "simple" mode: three drill signs in
4
+ # blue, then the word on its own line in a separately-picked random color.
5
+ # 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.
9
+ module Lexdrill::LineFormatter
10
+ SEPARATOR = "⟳"
11
+ SIMPLE_HEADER = SEPARATOR * 3
12
+
13
+ def self.format(word)
14
+ return simple(word) if Lexdrill::Format.simple?
15
+
16
+ full(word)
17
+ end
18
+
19
+ def self.simple(word)
20
+ "#{Lexdrill::Colorizer.paint_blue(SIMPLE_HEADER)}\n#{Lexdrill::Colorizer.paint(word)}"
21
+ end
22
+
23
+ def self.full(word)
24
+ total = Lexdrill::WordList.words.size
25
+ info = loop_info(total)
26
+ "#{info.index + 1}/#{total}#{SEPARATOR}[#{info.chunk_start}-#{info.chunk_end}]\n#{word}"
27
+ end
28
+
29
+ def self.loop_info(total)
30
+ counter = Lexdrill::Counter.new(Lexdrill::WordList::COUNTER_PATH)
31
+ step_used = counter.value - 1
32
+ Lexdrill::Beat.loop_info(total, step_used)
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generates the zsh/bash shell integration snippet for `drill hook`.
4
+ module Lexdrill::ShellSnippet
5
+ ZSH = <<~SNIPPET
6
+ drill_precmd() {
7
+ [[ -f "$HOME/.drill.disabled" ]] && return
8
+ command drill next 2>/dev/null
9
+ }
10
+ if [[ -z "${precmd_functions[(r)drill_precmd]}" ]]; then
11
+ precmd_functions+=(drill_precmd)
12
+ fi
13
+ SNIPPET
14
+
15
+ BASH = <<~SNIPPET
16
+ drill_precmd() {
17
+ [ -f "$HOME/.drill.disabled" ] && return
18
+ command drill next 2>/dev/null
19
+ }
20
+ case ";${PROMPT_COMMAND:-};" in
21
+ *";drill_precmd;"*) ;;
22
+ *) PROMPT_COMMAND="drill_precmd;${PROMPT_COMMAND}" ;;
23
+ esac
24
+ SNIPPET
25
+
26
+ def self.for(shell_name)
27
+ case shell_name.to_s
28
+ when "zsh" then ZSH
29
+ when "bash" then BASH
30
+ else
31
+ raise ArgumentError, "unsupported shell #{shell_name.inspect} (expected \"zsh\" or \"bash\")"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ # Global pause/resume switch for the shell hook, independent of which
6
+ # project's .drill.txt is active. Enabled by default; the marker file's
7
+ # presence means stopped.
8
+ module Lexdrill::Toggle
9
+ PATH = File.join(Dir.home, ".drill.disabled")
10
+
11
+ def self.enabled?
12
+ !File.exist?(PATH)
13
+ end
14
+
15
+ def self.start
16
+ FileUtils.rm_f(PATH)
17
+ end
18
+
19
+ def self.stop
20
+ File.write(PATH, "")
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lexdrill
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -19,8 +19,9 @@ class Lexdrill::WordList
19
19
 
20
20
  def self.take_index(size)
21
21
  counter = Lexdrill::Counter.new(COUNTER_PATH)
22
- index = counter.bounded_value(size)
22
+ cycle_length = Lexdrill::Beat.cycle_length(size)
23
+ step = counter.bounded_value(cycle_length)
23
24
  counter.increment
24
- index
25
+ Lexdrill::Beat.index_for(size, step)
25
26
  end
26
27
  end
data/lib/lexdrill.rb CHANGED
@@ -3,5 +3,12 @@
3
3
  require_relative "lexdrill/version"
4
4
  require_relative "lexdrill/config"
5
5
  require_relative "lexdrill/counter"
6
+ require_relative "lexdrill/beat"
6
7
  require_relative "lexdrill/word_list"
8
+ require_relative "lexdrill/toggle"
9
+ require_relative "lexdrill/shell_snippet"
10
+ require_relative "lexdrill/inspector"
11
+ require_relative "lexdrill/colorizer"
12
+ require_relative "lexdrill/format"
13
+ require_relative "lexdrill/line_formatter"
7
14
  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.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Siarhei Kisliak
@@ -15,19 +15,26 @@ description: lexdrill prints a vocabulary word or phrase on demand, tracking how
15
15
  email:
16
16
  - kislak7@gmail.com
17
17
  executables:
18
- - lexdrill
18
+ - drill
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
22
  - Gemfile
23
23
  - LICENSE.txt
24
24
  - README.md
25
- - bin/lexdrill
25
+ - bin/drill
26
26
  - lexdrill.gemspec
27
27
  - lib/lexdrill.rb
28
+ - lib/lexdrill/beat.rb
28
29
  - lib/lexdrill/cli.rb
30
+ - lib/lexdrill/colorizer.rb
29
31
  - lib/lexdrill/config.rb
30
32
  - lib/lexdrill/counter.rb
33
+ - lib/lexdrill/format.rb
34
+ - lib/lexdrill/inspector.rb
35
+ - lib/lexdrill/line_formatter.rb
36
+ - lib/lexdrill/shell_snippet.rb
37
+ - lib/lexdrill/toggle.rb
31
38
  - lib/lexdrill/version.rb
32
39
  - lib/lexdrill/word_list.rb
33
40
  homepage: https://github.com/kislak/lexdrill
File without changes