trogdoro / xiki

Emacs libs in ruby

This URL has Read+Write access

xiki / fc.rb
100644 226 lines (183 sloc) 4.904 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
class Fc
  extend ElMixin
 
  @@ask_in_reverse = false
 
  # Randomize rows and gray out all but top one
  def self.start
    # Get table
    @@top = point
    @@orig_top = point
    @@orig_lines = grab_lines
 
    # Replace with shuffled versions
    delete_region @@top, end_of_lines
    shuffle
    insert @@shuffled_lines.join("\n")
    insert "\n"
 
    clear_overlays
 
    # Make all but top be grayed
    goto_char @@top
 
    elvar.local_map_before_fc = current_local_map
    use_local_map elvar.fc_map
 
    ask_line
  end
 
  def self.correct
    # Ignore correct if they haven't seen answer yet
    return unless @@showed_answer
 
    @@showed_answer = false
 
    # Move top down one line
    goto_char @@top
    next_line
    @@top = point
 
    return if check_for_finished
 
    clear_overlays
    ask_line
 
  end
 
  def self.check_for_finished
    # We're done if there's nothing on this line
 
    if buffer_substring(point_at_bol, point_at_eol) =~ /^ *$/
      speak "You're finished", "Kathy"
      cancel
      return true
    end
    false
  end
 
  def self.cancel
    clear_overlays
    goto_char @@orig_top
    # TODO figure out how to restore old local map that was here
    use_local_map elvar.local_map_before_fc
 
  end
 
  def self.show_answer
    # If we haven't shown answer, show for first time
    unless @@showed_answer
      delete_overlays_on_line
      speak_question_or_answer 2
      @@showed_answer = true
    # They missed it (they have shown the answer)
    else
      clear_overlays
      # Delete line
      missed = thing_at_point(:line)
      delete_region point_at_bol, point_at_eol + 1
 
      # TODO Put line down after 2
      last_line = end_of_lines
      left_to_move = 2
      # Move down until we've gone 2 or are after end
      while( left_to_move > 0 && point < last_line )
        next_line
        left_to_move -= 1
      end
      insert missed
 
      # Put line to end
      goto_char end_of_lines
      insert missed
 
      ask_line
    end
  end
 
  def self.ask_in_reverse= to_this
    @@ask_in_reverse = to_this
  end
 
  def self.ask_line
    @@showed_answer = false
    goto_char @@top
    next_line
    gray_until_end
    gray_answer
    speak_question_or_answer 1
  end
 
  def self.repeat_question
    speak_question_or_answer 1
  end
 
  def self.delete_overlays_on_line
    os = overlays_in(point_at_bol, point_at_eol)
    return unless os
    os.each do |o|
      delete_overlay o
    end
  end
 
  def self.speak_question_or_answer q_or_a
    goto_char @@top
    thing_at_point(:line) =~ /(.+) ?\| ?(.+)/
    which_one = q_or_a == 1
    which_one = ! which_one if @@ask_in_reverse
    which_one ? speak($1) : speak($2, "Victoria")
  end
 
 
  def self.gray_answer
    goto_char @@top
    re_search_forward " | "
    unless @@ask_in_reverse
      overlay_put make_overlay(point, point_at_eol), :face, :fc_invisible
    else
      overlay_put make_overlay(point_at_bol, match_beginning(0)), :face, :fc_invisible
    end
  end
 
  def self.end_of_lines
    old = point
    re_search_forward /^$/
    r = point
    goto_char old
    r
  end
 
  def self.clear_overlays
 
    os = overlays_in(point_min, point_max)
    return unless os
    os.each do |o|
      delete_overlay o
    end
  end
 
  def self.gray_until_end
    top = point
 
    re_search_forward /^$/
    overlay_put make_overlay(top, end_of_lines), :face, :fc_invisible
  end
 
  def self.grab_lines
    buffer_substring(@@top, end_of_lines).split /\n/
  end
 
  def self.shuffle
    a = @@orig_lines.dup
    (a.size-1).downto(1) { |i|
        j = rand(i+1)
        a[i], a[j] = a[j], a[i] if i != j
    }
    @@shuffled_lines = a
  end
 
  def self.speak words, voice="Vicki"
    words.gsub! '"', '\"'
    words.gsub! '_', '-'
    do_applescript "say \"#{words}\" using \"#{voice}\""
  end
 
  def self.define_keys
 
    elvar.fc_map = make_sparse_keymap
    # Template > Defining 1 and 2 keys
    define_key(:fc_map, "1") { Fc.show_answer }
    define_key(:fc_map, "2") { Fc.correct }
    define_key(:fc_map, "3") { Fc.repeat_question }
    define_key(:fc_map, "0") { Fc.cancel }
 
    define_key(:fc_map, kbd("C-1")) { Fc.show_answer }
    define_key(:fc_map, kbd("C-2")) { Fc.correct }
    define_key(:fc_map, kbd("C-3")) { Fc.repeat_question }
    define_key(:fc_map, kbd("C-0")) { Fc.cancel }
 
# # Template > Defining a key
# Keys.DZ do
# # If 2 passed as prefix, do reverse
# Fc.ask_in_reverse = elvar.current_prefix_arg == 1
# Fc.start
# # TODO figure out how to save local map to restore it later
# # store this? current-local-map
# use_local_map elvar.fc_map
# end
 
  end
 
  # Define font
  def self.define_styles
    el4r_lisp_eval <<-'EOL'
(progn
(set-face-attribute (make-face 'fc-invisible) nil
:foreground "#ffffff")
)
EOL
  end
  def self.init
    Fc.define_styles
    Fc.define_keys
  end
end
Fc.init