card.rb 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. # Copyright 2024 Henrique Paone
  2. #
  3. # This file is part of Tanki.
  4. #
  5. # Tanki is free software: you can redistribute it and/or modify it under the
  6. # terms of the GNU General Public License as published by the Free Software
  7. # Foundation, either version 3 of the License, or (at your option) any later
  8. # version.
  9. #
  10. # Tanki is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12. # PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License along with
  15. # Tanki. If not, see <https://www.gnu.org/licenses/>.
  16. require 'date'
  17. require_relative 'tui/tui.rb'
  18. require_relative 'error.rb'
  19. class Card
  20. include Tui
  21. include Error
  22. attr_reader :title, :prompt, :answer
  23. attr_writer :stage, :last_review
  24. Regexes = {
  25. # Everything after a # is ignore, \# is allowed
  26. :comment => /(?<!\\)#.*/,
  27. # The stage is an arbitrary number
  28. :stage => /^Stage:\s*\K\d+/,
  29. # Gets the date in the format year-month-day
  30. :last_review => /^LastReview:\s*\K\d{4}-\d{1,2}-\d{1,2}/,
  31. # Matches everything between two %. To get the answer, we apply this match
  32. # then check in the $' variable and to get the title we get until the first \n
  33. :prompt => /%\K(.*)\K%/m
  34. }
  35. def method_missing(m, *args, &block)
  36. show(false, *args) if m == :show_prompt
  37. show(true, *args) if m == :show_answer
  38. end
  39. def initialize(file)
  40. @file = File.new(file)
  41. @text = @file.read
  42. parse
  43. end
  44. def show(show_answer, amt)
  45. lines, cols = *IO.console.winsize
  46. cstart = lstart = margin = 5
  47. lend = lines - margin
  48. cend = cols - margin
  49. lbeg = cstart + 1
  50. IO.console.clear_screen
  51. draw_box(cstart, lstart, lend, cend)
  52. lstart += 1
  53. move_cursor(lstart, lbeg)
  54. print @file.path
  55. card_str = 'cards'
  56. card_str = 'card' if amt == 1
  57. print_line_before("#{ amt } #{ card_str } pending", lstart, cend - 1)
  58. lstart += 1
  59. draw_vline_inbox(cstart, cend, lstart)
  60. lstart += 3
  61. lstart = print_centered(@prompt, lstart, lbeg, cstart, cend - 1)
  62. lstart += ((lend - lstart) / 2) - 2
  63. print_centered(@answer, lstart, lbeg, cstart, cend - 1) if show_answer
  64. options = {
  65. right: 'r: Right',
  66. wrong: 'w: Wrong',
  67. quit: 'q: Quit',
  68. enter: '--ENTER--'
  69. }
  70. draw_vline_inbox(cstart, cend, lend - 2)
  71. move_cursor(lend - 1, lbeg)
  72. unless show_answer
  73. # Before asking to show the answer
  74. print options[:enter].center(cend - cstart - 1)
  75. else
  76. # After asking to show the answer
  77. print options[:right].center(cend - cstart - 1)
  78. move_cursor(lend - 1, lbeg)
  79. print options[:wrong]
  80. end
  81. print_line_before(options[:quit], lend - 1, cend - 1)
  82. move_cursor(lines, 1)
  83. end
  84. def parse
  85. text = @text.gsub(Regexes[:comment], '')
  86. last_review = text.scan(Regexes[:last_review]).first
  87. stage = text.scan(Regexes[:stage]).first
  88. text.gsub!("Stage: #{ stage }", '')
  89. text.gsub!("LastReview: #{ last_review }", '')
  90. # Note: prompt must be the last scan so we can fetch the answer using $'
  91. prompt = text.scan(Regexes[:prompt]).first
  92. raise ParsingError, Err_msgs[:parse ] % { file: @file.path } if prompt.nil?
  93. @stage = stage.nil? ? 0 : stage.to_i
  94. begin
  95. @last_review = last_review.nil? ? Date.today : Date.strptime(last_review, '%Y-%m-%d')
  96. rescue Date::Error
  97. raise BadValue, Err_msgs[:bad_date] % { file: @file }
  98. end
  99. @prompt = prompt.first
  100. @answer = $'
  101. end
  102. def write
  103. text = @text.split("\n")
  104. stage_idx = text.index do |line|
  105. line.match?(Regexes[:stage])
  106. end
  107. last_review_idx = text.index do |line|
  108. line.match?(Regexes[:last_review])
  109. end
  110. if stage_idx.nil?
  111. text << ""
  112. text << "# Values for internal tanki use, dont touch them unless you know what you're doing"
  113. text << "Stage: #{ @stage }"
  114. else
  115. text[stage_idx] = "Stage: #{ @stage }"
  116. end
  117. if last_review_idx.nil?
  118. text << "LastReview: #{ @last_review }"
  119. else
  120. text[last_review_idx] = "LastReview: #{ @last_review }"
  121. end
  122. File.open(@file.path, 'w').write(text.join("\n") << "\n")
  123. @file.close
  124. end
  125. def pending?
  126. Date.today >= @last_review + stage_dif
  127. end
  128. def check_syntax
  129. end
  130. def reset
  131. @stage = 0
  132. end
  133. def incr
  134. @stage += 1
  135. end
  136. def stage_dif
  137. dif = count = 0
  138. skip = false
  139. while count != @stage
  140. unless skip
  141. dif += 1
  142. skip = true
  143. else
  144. skip = false
  145. end
  146. count += 1
  147. end
  148. dif
  149. end
  150. end