@@ -5,6 +5,7 @@ require 'date'
55require 'sqlite3'
66require 'fileutils'
77require 'gruff'
8+ require 'readline'
89
910require_relative '../lib/oss_stats/log'
1011require_relative '../lib/oss_stats/config/meeting_stats'
@@ -46,33 +47,64 @@ def prompt_yes_no(question)
4647end
4748
4849def prompt_team_or_q ( teams )
49- # it's length, not length-1 because we add one for <other>
50- max_num = teams . length
50+ # Setup readline completion with team names
51+ all_options = teams + %w{ other finish f abort }
52+
53+ comp = proc do |s |
54+ # Case-insensitive completion
55+ all_options . select { |opt | opt . downcase . start_with? ( s . downcase ) }
56+ end
57+
58+ Readline . completion_append_character = nil
59+ Readline . completion_proc = comp
60+
61+ # Make readline case-insensitive
62+ if Readline . respond_to? ( :completion_case_fold= )
63+ Readline . completion_case_fold = true
64+ end
65+
66+ # Remove space from word break characters so "Chef Client" is treated as one
67+ # word
68+ if Readline . respond_to? ( :completer_word_break_characters= )
69+ original_word_break = Readline . completer_word_break_characters
70+ Readline . completer_word_break_characters = original_word_break . delete ( ' ' )
71+ end
72+
5173 loop do
52- log . info ( "Choose a team that was present:\n " )
53- ( teams + [ '<Other>' ] ) . each_with_index do |team , idx |
54- log . info ( " [#{ idx } ] #{ team } " )
74+ log . info (
75+ 'Choose a team that was present (type to search, TAB to complete):' ,
76+ )
77+ teams . each do |team |
78+ log . info ( " - #{ team } " )
5579 end
56- log . info ( ' [q] <quit>' )
57- print "\n Team?> "
58- response = gets . strip . downcase
59- return false if response == 'q'
60- begin
61- i = Integer ( response )
62- if i < max_num
63- return teams [ i ]
64- end
80+ log . info ( "\n - other (for a team not in the list)" )
81+ log . info ( ' - abort (to quit without saving)' )
82+ log . info ( ' - [f]inish (to save)' )
83+ log . info ( '' )
84+ response = Readline . readline ( 'Team?> ' , true )
6585
66- if i == max_num
67- print 'Team name: '
68- response = gets . strip
69- return response
70- end
86+ # Handle Ctrl-C or Ctrl-D
87+ return false if response . nil?
88+
89+ response = response . strip
90+ return false if %w{ f finish } . include? ( response . downcase )
91+
92+ exit ( 0 ) if response . downcase == 'abort'
7193
72- log . error ( "Invalid response: #{ response } " )
73- rescue ArgumentError
74- log . error ( "Invalid response: #{ response } " )
94+ # Check if it's an exact match for a known team (case-insensitive)
95+ matched_team = teams . find { |t | t . downcase == response . downcase }
96+ return matched_team if matched_team
97+
98+ if response . downcase == 'other'
99+ print 'Team name: '
100+ new_team = gets . strip
101+ return new_team unless new_team . empty?
102+
103+ log . error ( 'Team name cannot be empty' )
104+ next
75105 end
106+
107+ log . error ( 'Please enter a valid options' )
76108 end
77109end
78110
@@ -94,28 +126,28 @@ def collect_team_data(meeting_date)
94126 )
95127 confirm = prompt_yes_no ( 'Is that correct?' )
96128 end
97- if confirm
98- missing_teams . each do |mt |
99- team_data [ mt ] = {
100- 'present' => false ,
101- 'current_work' => false ,
102- 'build_status' => '' ,
103- 'fix_pointers' => '-' ,
104- 'extra' => '-' ,
105- }
106- end
107- break
108- else
109- next
129+ next unless confirm
130+
131+ missing_teams . each do |mt |
132+ team_data [ mt ] = {
133+ 'present' => false ,
134+ 'current_work' => false ,
135+ 'build_status' => '' ,
136+ 'fix_pointers' => '-' ,
137+ 'extra' => '-' ,
138+ }
110139 end
140+ break
141+
111142 end
112143
113144 if team_data [ team ]
114- if prompt_yes_no ( "WARNING: #{ team } data already input - overwrite?" )
115- log . info ( "OK, overwriting data for #{ team } on #{ meeting_date } " )
116- else
145+ unless prompt_yes_no ( "WARNING: #{ team } data already input - overwrite?" )
117146 next
118147 end
148+
149+ log . info ( "OK, overwriting data for #{ team } on #{ meeting_date } " )
150+
119151 end
120152
121153 log . info ( "\n Team: #{ team } " )
212244def format_build_status ( status )
213245 return ':x:' if status . nil? || status . strip . empty?
214246
215- if %w{ red green } . include? ( status )
216- status = "main:#{ status } "
217- end
247+ status = "main:#{ status } " if %w{ red green } . include? ( status )
218248 status . gsub ( 'red' , ' :red_circle:' ) . gsub ( 'green' , ' :white_check_mark:' )
219249end
220250
@@ -354,7 +384,7 @@ OptionParser.new do |opts|
354384 options [ :date ] =
355385 begin
356386 Date . parse ( v )
357- rescue
387+ rescue StandardError
358388 nil
359389 end
360390 end
0 commit comments