Class: AIA::Prompt

Inherits:
Object
  • Object
show all
Includes:
DynamicContent, UserQuery
Defined in:
lib/aia/prompt.rb

Defined Under Namespace

Classes: Fake

Constant Summary collapse

KW_HISTORY_MAX =
5
COMMENT_SIGNAL =
'#'
DIRECTIVE_SIGNAL =
"//"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from UserQuery

#ask_question_with_reline

Methods included from DynamicContent

#render_env, #render_erb

Constructor Details

#initialize(build: true) ⇒ Prompt

setting build: false supports unit testing.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/aia/prompt.rb', line 33

def initialize(build: true)
  if AIA.config.role.empty?
    @role = nil
  else
    @role = (AIA.config.roles_dir + "#{AIA.config.role}.txt").read
  end

  get_prompt
  
  @prompt_text_before_role = @prompt.text.dup

  unless @role.nil?
    @prompt.text.prepend @role
  end

  if build
    @prompt.text = render_erb(@prompt.text)   if AIA.config.erb?
    @prompt.text = render_env(@prompt.text)   if AIA.config.shell?
    process_prompt 
  end

  AIA.config.directives = @prompt.directives
end

Instance Attribute Details

#promptObject (readonly)

Returns the value of attribute prompt.



30
31
32
# File 'lib/aia/prompt.rb', line 30

def prompt
  @prompt
end

Instance Method Details

#create_prompt(prompt_id) ⇒ Object



224
225
226
227
228
# File 'lib/aia/prompt.rb', line 224

def create_prompt(prompt_id)
  @prompt = PromptManager::Prompt.create(id: prompt_id)
  # TODO: consider a configurable prompt template
  #       ERB ???
end

#edit_promptObject



231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/aia/prompt.rb', line 231

def edit_prompt
  # FIXME: replace with the editor from the configuration
  
  @editor   = AIA::Subl.new(
                file: @prompt.path
              )
  
  @editor.run # blocks until file is closed

  AIA.config[:edit?] = false # turn off the --edit switch

  # reload the edited prompt
  @prompt = PromptManager::Prompt.get(id: @prompt.id)
end

#existing_prompt?(prompt_id) ⇒ Boolean

Check if a prompt with the given id already exists. If so, use it.

Returns:

  • (Boolean)


77
78
79
80
81
82
# File 'lib/aia/prompt.rb', line 77

def existing_prompt?(prompt_id)
  @prompt = PromptManager::Prompt.get(id: prompt_id)
  true
rescue ArgumentError
  false
end

#get_promptObject

Fetch the first argument which should be the prompt id



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/aia/prompt.rb', line 59

def get_prompt
  prompt_id = AIA.config.arguments.shift

  unless prompt_id
    if AIA.config.extra.empty?
      abort("Please provide a prompt id") 
    else
      @prompt = Fake.new
      return
    end
  end

  search_for_a_matching_prompt(prompt_id) unless existing_prompt?(prompt_id)
  edit_prompt if AIA.config.edit?
end

#handle_multiple_prompts(found_these, while_looking_for_this) ⇒ Object

Raises:

  • (ArgumentError)


201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/aia/prompt.rb', line 201

def handle_multiple_prompts(found_these, while_looking_for_this)
  raise ArgumentError, "Argument is not an Array" unless found_these.is_a?(Array)

  # Create an instance of AIA::Fzf with appropriate parameters
  fzf_instance = AIA::Fzf.new(
    list:       found_these,
    directory:  AIA.config.prompts_dir, # Assuming this is the correct directory
    query:      while_looking_for_this,
    subject:    'Prompt IDs',
    prompt:     'Select one: '
  )

  # Run the fzf instance and get the selected result
  result = fzf_instance.run

  exit unless result

  result
end

#keyword_value(kw, history_array) ⇒ Object

query the user for a value to the keyword allow the reuse of the previous value shown as the default

FIXME: Ruby v3.3.0 drops readline in favor or reline

internally it redirects "require 'readline'" to Reline
puts lipstick on the pig so that you can continue to
use the Readline namespace


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
# File 'lib/aia/prompt.rb', line 147

def keyword_value(kw, history_array)
  setup_reline_history
  
  default = history_array.last

  Array(history_array).each { |entry| Reline::HISTORY.push(entry) unless entry.nil? || entry.empty? }

  puts "Parameter #{kw} ..."

  if default&.empty?
    user_prompt = "\n-=> "
  else
    user_prompt = "\n(#{default}) -=> "
  end

  a_string = ask_question_with_reline(user_prompt)

  if a_string.nil?
    puts "okay. Come back soon."
    exit
  end

  puts
  a_string.empty? ? default : a_string
end

#process_promptObject

Process the prompt’s associated keywords and parameters



86
87
88
89
90
91
92
# File 'lib/aia/prompt.rb', line 86

def process_prompt
  unless @prompt.keywords.empty?
    replace_keywords
    @prompt.build
    save(@prompt_text_before_role)
  end
end

#remove_commentsObject

removes comments and directives



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/aia/prompt.rb', line 253

def remove_comments
  lines           = @prompt.text
                      .split("\n")
                      .reject{|a_line| 
                        a_line.strip.start_with?('#') ||
                        a_line.strip.start_with?('//')
                      }

  # Remove empty lines at the start of the prompt
  #
  lines = lines.drop_while(&:empty?)

  # Drop all the lines at __END__ and after
  #
  logical_end_inx = lines.index("__END__")

  if logical_end_inx
    lines[0...logical_end_inx] # NOTE: ... means to not include last index
  else
    lines
  end.join("\n") 
end

#replace_keywordsObject



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
# File 'lib/aia/prompt.rb', line 103

def replace_keywords
  puts
  puts "ID: #{@prompt.id}"
  
  show_prompt_without_comments

  puts "\nPress up/down arrow to scroll through history."
  puts "Type new input or edit the current input."
  puts  "Quit #{MY_NAME} with a CNTL-D or a CNTL-C"
  puts
  @prompt.keywords.each do |kw|
    value = keyword_value(kw, @prompt.parameters[kw])
    
    unless value.nil? || value.strip.empty?
      value_inx = @prompt.parameters[kw].index(value)
      
      if value_inx
        @prompt.parameters[kw].delete_at(value_inx)
      end

      # The most recent value for this kw will always be
      # in the last position
      @prompt.parameters[kw] << value
      @prompt.parameters[kw].shift if @prompt.parameters[kw].size > KW_HISTORY_MAX
    end
  end
end

#save(original_text) ⇒ Object



95
96
97
98
99
100
# File 'lib/aia/prompt.rb', line 95

def save(original_text)
  temp_text     = @prompt.text
  @prompt.text  = original_text
  @prompt.save
  @prompt.text  = temp_text
end

#search_for_a_matching_prompt(prompt_id) ⇒ Object

Search for a prompt with a matching id or keyword



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/aia/prompt.rb', line 175

def search_for_a_matching_prompt(prompt_id)
  # TODO: using the rgfzf version of the search_proc should only
  #       return a single prompt_id
  found_prompts = PromptManager::Prompt.search(prompt_id)

  if found_prompts.empty?
    if AIA.config.edit?
      create_prompt(prompt_id)
      edit_prompt
    else
      abort <<~EOS
        
        No prompts where found for: #{prompt_id}
        To create a prompt with this ID use the --edit option
        like this:
          #{MY_NAME} #{prompt_id} --edit

      EOS
    end
  else    
    prompt_id     = 1 == found_prompts.size ? found_prompts.first : handle_multiple_prompts(found_prompts, prompt_id)
    @prompt       = PromptManager::Prompt.get(id: prompt_id)
  end
end

#setup_reline_history(max_history_size = 5) ⇒ Object

Function to setup the Reline history with a maximum depth



133
134
135
136
# File 'lib/aia/prompt.rb', line 133

def setup_reline_history(max_history_size=5)
  Reline::HISTORY.clear
  # Reline::HISTORY.max_size = max_history_size
end

#show_prompt_without_commentsObject



247
248
249
# File 'lib/aia/prompt.rb', line 247

def show_prompt_without_comments
  puts remove_comments.wrap(indent: 4)
end