aia 0.3.4 → 0.3.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.semver +6 -0
- data/CHANGELOG.md +16 -0
- data/README.md +165 -55
- data/Rakefile +2 -0
- data/justfile +167 -0
- data/lib/aia/cli.rb +228 -115
- data/lib/aia/config.rb +7 -0
- data/lib/aia/logging.rb +49 -12
- data/lib/aia/main.rb +46 -15
- data/lib/aia/prompt_processing.rb +208 -4
- data/lib/aia/tools/editor.rb +52 -0
- data/lib/aia/{external → tools}/mods.rb +108 -12
- data/lib/aia/{external → tools}/sgpt.rb +12 -7
- data/lib/aia/{external → tools}/subl.rb +32 -11
- data/lib/aia/tools/temp.md +97 -0
- data/lib/aia/tools/vim.rb +93 -0
- data/lib/aia/tools.rb +50 -0
- data/lib/aia/version.rb +5 -1
- data/lib/aia.rb +18 -3
- data/main.just +56 -0
- data/man/aia.1 +134 -0
- data/man/aia.1.md +107 -0
- metadata +87 -18
- data/lib/aia/configuration.rb +0 -39
- data/lib/aia/external/,keep +0 -0
- data/lib/aia/external/.irbrc +0 -11
- data/lib/aia/external/ag.rb +0 -103
- data/lib/aia/external/bat.rb +0 -189
- data/lib/aia/external/fzf.rb +0 -147
- data/lib/aia/external/glow.rb +0 -37
- data/lib/aia/external/rg.rb +0 -1163
- data/lib/aia/external/tool.rb +0 -73
- data/lib/aia/external.rb +0 -259
- data/lib/aia/external_two.rb +0 -43
@@ -5,14 +5,20 @@ module AIA::PromptProcessing
|
|
5
5
|
|
6
6
|
# Fetch the first argument which should be the prompt id
|
7
7
|
def get_prompt
|
8
|
-
prompt_id =
|
8
|
+
prompt_id = AIA.config.arguments.shift
|
9
9
|
|
10
10
|
# TODO: or maybe go to a generic search and select process
|
11
11
|
|
12
|
+
# TODO: if external options were provided but no prompt id
|
13
|
+
# then by pass prompt process and send the extra
|
14
|
+
# options to the backend. For example:
|
15
|
+
# aia -- --settings
|
16
|
+
# should send --settings to mods and nothing else
|
17
|
+
|
12
18
|
abort("Please provide a prompt id") unless prompt_id
|
13
19
|
|
14
20
|
search_for_a_matching_prompt(prompt_id) unless existing_prompt?(prompt_id)
|
15
|
-
edit_prompt if edit?
|
21
|
+
edit_prompt if AIA.config.edit?
|
16
22
|
end
|
17
23
|
|
18
24
|
|
@@ -178,8 +184,17 @@ module AIA::PromptProcessing
|
|
178
184
|
|
179
185
|
|
180
186
|
def edit_prompt
|
181
|
-
|
182
|
-
|
187
|
+
# FIXME: replace with the editor from the configuration
|
188
|
+
|
189
|
+
@editor = AIA::Subl.new(
|
190
|
+
file: @prompt.path
|
191
|
+
)
|
192
|
+
|
193
|
+
@editor.run # blocks until file is closed
|
194
|
+
|
195
|
+
@options[:edit?][0] = false # turn off the --edit switch
|
196
|
+
|
197
|
+
# reload the edited prompt
|
183
198
|
@prompt = PromptManager::Prompt.get(id: @prompt.id)
|
184
199
|
end
|
185
200
|
|
@@ -210,3 +225,192 @@ module AIA::PromptProcessing
|
|
210
225
|
end
|
211
226
|
end
|
212
227
|
|
228
|
+
|
229
|
+
|
230
|
+
__END__
|
231
|
+
|
232
|
+
# lib/aia/prompt_processing.rb
|
233
|
+
|
234
|
+
class AIA::PromptProcessing
|
235
|
+
KW_HISTORY_MAX = 5
|
236
|
+
|
237
|
+
def initialize(arguments, options)
|
238
|
+
@arguments = arguments
|
239
|
+
@options = options
|
240
|
+
@prompt = nil
|
241
|
+
end
|
242
|
+
|
243
|
+
def execute
|
244
|
+
get_prompt
|
245
|
+
process_prompt
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def get_prompt
|
251
|
+
prompt_id = @arguments.shift
|
252
|
+
abort("Please provide a prompt id") unless prompt_id
|
253
|
+
search_for_a_matching_prompt(prompt_id) unless existing_prompt?(prompt_id)
|
254
|
+
edit_prompt if edit?
|
255
|
+
end
|
256
|
+
|
257
|
+
def existing_prompt?(prompt_id)
|
258
|
+
@prompt = PromptManager::Prompt.get(id: prompt_id)
|
259
|
+
@prompt.keywords.each do |kw|
|
260
|
+
@prompt.parameters[kw] = Array(@prompt.parameters[kw])
|
261
|
+
end
|
262
|
+
true
|
263
|
+
rescue ArgumentError
|
264
|
+
false
|
265
|
+
end
|
266
|
+
|
267
|
+
def process_prompt
|
268
|
+
return if @prompt.keywords.empty?
|
269
|
+
replace_keywords
|
270
|
+
@prompt.build
|
271
|
+
@prompt.save
|
272
|
+
end
|
273
|
+
|
274
|
+
def replace_keywords
|
275
|
+
puts "ID: #{@prompt.id}"
|
276
|
+
show_prompt_without_comments
|
277
|
+
puts_instructions
|
278
|
+
@prompt.keywords.each do |kw|
|
279
|
+
value = keyword_value(kw, @prompt.parameters[kw])
|
280
|
+
update_keyword_history(kw, value) unless value.nil? || value.strip.empty?
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def puts_instructions
|
285
|
+
puts "\nPress up/down arrow to scroll through history."
|
286
|
+
puts "Type new input or edit the current input."
|
287
|
+
puts "Quit #{MY_NAME} with a CNTL-D or a CNTL-C"
|
288
|
+
puts
|
289
|
+
end
|
290
|
+
|
291
|
+
def update_keyword_history(kw, value)
|
292
|
+
params = @prompt.parameters[kw]
|
293
|
+
params.delete(value)
|
294
|
+
params << value
|
295
|
+
params.shift if params.size > KW_HISTORY_MAX
|
296
|
+
end
|
297
|
+
|
298
|
+
def keyword_value(kw, history_array)
|
299
|
+
Readline::HISTORY.clear
|
300
|
+
Array(history_array).each { |entry| Readline::HISTORY.push(entry) unless entry.nil? || entry.empty? }
|
301
|
+
puts "Parameter #{kw} ..."
|
302
|
+
begin
|
303
|
+
a_string = Readline.readline("\n-=> ", true)
|
304
|
+
rescue Interrupt
|
305
|
+
a_string = nil
|
306
|
+
end
|
307
|
+
abort("okay. Come back soon.") if a_string.nil?
|
308
|
+
a_string.empty? ? history_array.first : a_string
|
309
|
+
end
|
310
|
+
|
311
|
+
def search_for_a_matching_prompt(prompt_id)
|
312
|
+
found_prompts = PromptManager::Prompt.search(prompt_id)
|
313
|
+
handle_no_prompts_found(prompt_id) if found_prompts.empty?
|
314
|
+
prompt_id = found_prompts.size == 1 ? found_prompts.first : handle_multiple_prompts(found_prompts, prompt_id)
|
315
|
+
@prompt = PromptManager::Prompt.get(id: prompt_id)
|
316
|
+
end
|
317
|
+
|
318
|
+
def handle_no_prompts_found(prompt_id)
|
319
|
+
if edit?
|
320
|
+
create_prompt(prompt_id)
|
321
|
+
edit_prompt
|
322
|
+
else
|
323
|
+
abort_no_prompts_error(prompt_id)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def abort_no_prompts_error(prompt_id)
|
328
|
+
abort <<~EOS
|
329
|
+
|
330
|
+
No prompts were found for: #{prompt_id}
|
331
|
+
To create a prompt with this ID use the --edit option
|
332
|
+
like this:
|
333
|
+
#{MY_NAME} #{prompt_id} --edit
|
334
|
+
|
335
|
+
EOS
|
336
|
+
end
|
337
|
+
|
338
|
+
def handle_multiple_prompts(found_these, while_looking_for_this)
|
339
|
+
raise ArgumentError, "Argument is not an Array" unless found_these.is_a?(Array)
|
340
|
+
result = execute_fzf(found_these, while_looking_for_this)
|
341
|
+
abort unless result
|
342
|
+
result
|
343
|
+
end
|
344
|
+
|
345
|
+
def execute_fzf(found_these, while_looking_for_this)
|
346
|
+
fzf_options = build_fzf_options(while_looking_for_this)
|
347
|
+
temp_file = create_tempfile_with_entries(found_these)
|
348
|
+
selected = `cat #{temp_file.path} | fzf #{fzf_options}`.strip
|
349
|
+
temp_file.unlink
|
350
|
+
selected.empty? ? nil : selected
|
351
|
+
end
|
352
|
+
|
353
|
+
def build_fzf_options(search_term)
|
354
|
+
[
|
355
|
+
"--tabstop=2",
|
356
|
+
"--header='Prompt IDs which contain: #{search_term}\nPress ESC to cancel.'",
|
357
|
+
"--header-first",
|
358
|
+
"--prompt='Search term: '",
|
359
|
+
'--delimiter :',
|
360
|
+
"--preview 'cat $PROMPTS_DIR/{1}.txt'",
|
361
|
+
"--preview-window=down:50%:wrap"
|
362
|
+
].join(' ')
|
363
|
+
end
|
364
|
+
|
365
|
+
def create_tempfile_with_entries(entries)
|
366
|
+
temp_file = Tempfile.new('fzf-input')
|
367
|
+
temp_file.puts(entries)
|
368
|
+
temp_file.close
|
369
|
+
temp_file
|
370
|
+
end
|
371
|
+
|
372
|
+
def create_prompt(prompt_id)
|
373
|
+
@prompt = PromptManager::Prompt.create(id: prompt_id)
|
374
|
+
# Additional prompt config...
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
|
379
|
+
def edit_prompt
|
380
|
+
# FIXME: replace with the editor from the configuration
|
381
|
+
|
382
|
+
@editor = AIA::Subl.new(
|
383
|
+
file: @prompt.path
|
384
|
+
)
|
385
|
+
|
386
|
+
@editor.run # blocks until file is closed
|
387
|
+
|
388
|
+
@options[:edit?][0] = false # turn off the --edit switch
|
389
|
+
|
390
|
+
# reload the edited prompt
|
391
|
+
@prompt = PromptManager::Prompt.get(id: @prompt.id)
|
392
|
+
end
|
393
|
+
|
394
|
+
|
395
|
+
def show_prompt_without_comments
|
396
|
+
puts remove_comments.wrap(indent: 4)
|
397
|
+
end
|
398
|
+
|
399
|
+
def remove_comments
|
400
|
+
lines = @prompt.text.lines
|
401
|
+
.reject { |a_line| a_line.strip.start_with?('#') }
|
402
|
+
.drop_while(&:empty?)
|
403
|
+
logical_end_inx = lines.index("__END__")
|
404
|
+
lines = lines[0...logical_end_inx] if logical_end_inx
|
405
|
+
lines.join("\n")
|
406
|
+
end
|
407
|
+
|
408
|
+
def edit?
|
409
|
+
@options[:edit?] && @options[:edit?][0] == true
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
|
415
|
+
|
416
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# lib/aia/tools/editor.rb
|
2
|
+
# This is the default editor setup in the
|
3
|
+
# system environment variable EDITOR
|
4
|
+
|
5
|
+
|
6
|
+
class AIA::Editor < AIA::Tools
|
7
|
+
|
8
|
+
meta(
|
9
|
+
name: 'editor',
|
10
|
+
role: :editor,
|
11
|
+
desc: "Your default system $EDITOR",
|
12
|
+
url: "unknown",
|
13
|
+
install: "should already be installed",
|
14
|
+
)
|
15
|
+
|
16
|
+
DEFAULT_PARAMETERS = ""
|
17
|
+
|
18
|
+
attr_accessor :command
|
19
|
+
|
20
|
+
|
21
|
+
def initialize(file: "")
|
22
|
+
@file = file
|
23
|
+
|
24
|
+
discover_editor
|
25
|
+
|
26
|
+
build_command
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def discover_editor
|
31
|
+
editor = ENV['EDITOR'] # This might be nil
|
32
|
+
|
33
|
+
if editor.nil?
|
34
|
+
@name = "echo"
|
35
|
+
@description = "You have no default editor"
|
36
|
+
@install = "Set your system environment variable EDITOR"
|
37
|
+
else
|
38
|
+
@name = editor
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def build_command
|
44
|
+
@command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def run
|
49
|
+
`#{command}`
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -1,22 +1,118 @@
|
|
1
|
-
# lib/aia/
|
2
|
-
|
3
|
-
class AIA::
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
# lib/aia/tools/mods.rb
|
2
|
+
|
3
|
+
class AIA::Mods < AIA::Tools
|
4
|
+
|
5
|
+
meta(
|
6
|
+
name: 'mods',
|
7
|
+
role: :backend,
|
8
|
+
desc: 'AI on the command-line',
|
9
|
+
url: 'https://github.com/charmbracelet/mods',
|
10
|
+
install: 'brew install mods',
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
DEFAULT_PARAMETERS = [
|
15
|
+
"--no-limit" # no limit on input context
|
16
|
+
].join(' ').freeze
|
17
|
+
|
18
|
+
attr_accessor :command, :text, :files
|
19
|
+
|
20
|
+
|
21
|
+
def initialize(
|
22
|
+
text: "", # prompt text after keyword replacement
|
23
|
+
files: [] # context file paths (Array of Pathname)
|
24
|
+
)
|
25
|
+
|
26
|
+
@text = text
|
27
|
+
@files = files
|
28
|
+
|
29
|
+
build_command
|
9
30
|
end
|
10
31
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
32
|
+
|
33
|
+
def sanitize(input)
|
34
|
+
Shellwords.escape(input)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def build_command
|
39
|
+
parameters = DEFAULT_PARAMETERS.dup + " "
|
40
|
+
parameters += "-f " if AIA.config.markdown?
|
41
|
+
parameters += "-m #{AIA.config.model} " if AIA.config.model
|
42
|
+
parameters += AIA.config.extra
|
43
|
+
@command = "mods #{parameters} "
|
44
|
+
@command += sanitize(@text)
|
45
|
+
|
46
|
+
# context = @files.join(' ')
|
47
|
+
#
|
48
|
+
# unless context.empty?
|
49
|
+
# if @files.size > 1
|
50
|
+
# # FIXME: This syntax breaks mods which does not know how
|
51
|
+
# # to read the temporary file descriptor created
|
52
|
+
# # by the shell
|
53
|
+
# @command += " <(cat #{context})"
|
54
|
+
# else
|
55
|
+
# @command += " < #{context}"
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
|
59
|
+
@command
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def run
|
64
|
+
case @files.size
|
65
|
+
when 0
|
66
|
+
@result = `#{build_command}`
|
67
|
+
when 1
|
68
|
+
@result = `#{build_command} < #{@files.first}`
|
69
|
+
else
|
70
|
+
create_temp_file_with_contexts
|
71
|
+
run_mods_with_temp_file
|
72
|
+
clean_up_temp_file
|
73
|
+
end
|
74
|
+
|
75
|
+
@result
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Create a temporary file that concatenates all contexts,
|
80
|
+
# to be used as STDIN for the 'mods' utility
|
81
|
+
def create_temp_file_with_contexts
|
82
|
+
@temp_file = Tempfile.new('mods-context')
|
83
|
+
|
84
|
+
@files.each do |file|
|
85
|
+
content = File.read(file)
|
86
|
+
@temp_file.write(content)
|
87
|
+
@temp_file.write("\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
@temp_file.close
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Run 'mods' with the temporary file as STDIN
|
95
|
+
def run_mods_with_temp_file
|
96
|
+
command = "#{build_command} < #{@temp_file.path}"
|
97
|
+
@result = `#{command}`
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Clean up the temporary file after use
|
102
|
+
def clean_up_temp_file
|
103
|
+
@temp_file.unlink if @temp_file
|
15
104
|
end
|
16
105
|
end
|
17
106
|
|
18
107
|
__END__
|
19
108
|
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
##########################################################
|
114
|
+
|
115
|
+
|
20
116
|
GPT on the command line. Built for pipelines.
|
21
117
|
|
22
118
|
Usage:
|
@@ -1,12 +1,17 @@
|
|
1
|
-
# lib/aia/
|
1
|
+
# lib/aia/tools/sgpt.rb
|
2
|
+
|
3
|
+
class AIA::Sgpt < AIA::Tools
|
4
|
+
|
5
|
+
meta(
|
6
|
+
name: 'sgpt',
|
7
|
+
role: :backend,
|
8
|
+
desc: "shell-gpt",
|
9
|
+
url: "https://github.com/TheR1D/shell_gpt",
|
10
|
+
install: "pip install shell-gpt",
|
11
|
+
)
|
2
12
|
|
3
|
-
class AIA::External::Sgpt < AIA::External::Tool
|
4
13
|
def initialize
|
5
|
-
|
6
|
-
@role = :backend
|
7
|
-
@desc = "shell-gpt"
|
8
|
-
@url = "https://github.com/TheR1D/shell_gpt"
|
9
|
-
@install = "pip install shell-gpt"
|
14
|
+
# TODO: something
|
10
15
|
end
|
11
16
|
end
|
12
17
|
|
@@ -1,17 +1,38 @@
|
|
1
|
-
# lib/aia/
|
2
|
-
|
3
|
-
class AIA::
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
# lib/aia/tools/subl.rb
|
2
|
+
|
3
|
+
class AIA::Subl < AIA::Tools
|
4
|
+
|
5
|
+
meta(
|
6
|
+
name: 'subl',
|
7
|
+
role: :editor,
|
8
|
+
desc: "Sublime Text Editor",
|
9
|
+
url: "https://www.sublimetext.com/",
|
10
|
+
install: "echo 'Download from website'",
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
DEFAULT_PARAMETERS = [
|
15
|
+
"--new-window", # Open a new window
|
16
|
+
"--wait", # Wait for the files to be closed before returning
|
17
|
+
].join(' ')
|
18
|
+
|
19
|
+
attr_accessor :command
|
20
|
+
|
21
|
+
|
22
|
+
def initialize(file: "")
|
23
|
+
@file = file
|
24
|
+
|
25
|
+
build_command
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def build_command
|
30
|
+
@command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
|
10
31
|
end
|
11
32
|
|
12
33
|
|
13
|
-
def
|
14
|
-
`#{
|
34
|
+
def run
|
35
|
+
`#{command}`
|
15
36
|
end
|
16
37
|
end
|
17
38
|
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# lib/aia/tools.rb
|
2
|
+
|
3
|
+
```ruby
|
4
|
+
require 'hashie'
|
5
|
+
|
6
|
+
module AIA
|
7
|
+
class Tools
|
8
|
+
@subclasses = {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :subclasses, :metadata
|
12
|
+
|
13
|
+
def inherited(subclass)
|
14
|
+
@subclasses[subclass.name.split('::').last.downcase] = subclass
|
15
|
+
subclass.instance_variable_set(:@metadata, Jashie::Mash.new)
|
16
|
+
end
|
17
|
+
|
18
|
+
def meta
|
19
|
+
@metadata ||= Jashie::Mash.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def define_metadata(&block)
|
23
|
+
meta.instance_eval(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def search_for(name: nil, role: nil)
|
27
|
+
return subclasses[name.downcase] if name
|
28
|
+
return subclasses.values.select { |subclass| subclass.meta.role == role } if role
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.method_missing(name, *args, &block)
|
33
|
+
@metadata.public_send(name, *args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.respond_to_missing?(method_name, include_private = false)
|
37
|
+
@metadata.respond_to?(method_name) || super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
# lib/aia/tools/mods.rb
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require_relative 'tools'
|
47
|
+
|
48
|
+
module AIA
|
49
|
+
class Mods < Tools
|
50
|
+
DEFAULT_PARAMETERS = "--no-limit".freeze
|
51
|
+
|
52
|
+
attr_accessor :command, :extra_options, :text, :files
|
53
|
+
|
54
|
+
define_metadata do
|
55
|
+
role :backend
|
56
|
+
desc 'AI on the command-line'
|
57
|
+
url 'https://github.com/charmbracelet/mods'
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(extra_options: "", text: "", files: [])
|
61
|
+
@extra_options = extra_options
|
62
|
+
@text = text
|
63
|
+
@files = files
|
64
|
+
build_command
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_command
|
68
|
+
parameters = DEFAULT_PARAMETERS.dup + " "
|
69
|
+
parameters += "-f " if ::AIA.config.markdown?
|
70
|
+
parameters += "-m #{AIA.config.model} " if ::AIA.config.model
|
71
|
+
parameters += @extra_options
|
72
|
+
@command = "mods #{parameters}"
|
73
|
+
@command += %Q["#{@text}"]
|
74
|
+
|
75
|
+
@files.each { |f| @command += " < #{f}" }
|
76
|
+
|
77
|
+
@command
|
78
|
+
end
|
79
|
+
|
80
|
+
def run
|
81
|
+
`#{@command}`
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# Example usage:
|
89
|
+
# mods_class = AIA::Tools.search_for(name: 'mods')
|
90
|
+
# mods_instance = mods_class.new(text: "Hello, mods!")
|
91
|
+
# result = mods_instance.run
|
92
|
+
|
93
|
+
# backend_tools = AIA::Tools.search_for(role: :backend)
|
94
|
+
```
|
95
|
+
|
96
|
+
Note: The `Jashie::Mash` class is assumed to behave like `Hashie::Mash` (or similar) in providing a flexible object for storing metadata. You'll need to define `Jashie::Mash` or import a library that provides a similar functionality to match this example.
|
97
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# lib/aia/tools/vim.rb
|
2
|
+
|
3
|
+
class AIA::Vim < AIA::Tools
|
4
|
+
|
5
|
+
meta(
|
6
|
+
name: 'vim',
|
7
|
+
role: :editor,
|
8
|
+
desc: "Vi IMproved (VIM)",
|
9
|
+
url: "https://www.vim.org",
|
10
|
+
install: "brew install vim",
|
11
|
+
)
|
12
|
+
|
13
|
+
DEFAULT_PARAMETERS = [
|
14
|
+
" ", # no parameters
|
15
|
+
].join(' ')
|
16
|
+
|
17
|
+
attr_accessor :command
|
18
|
+
|
19
|
+
|
20
|
+
def initialize(file: "")
|
21
|
+
@file = file
|
22
|
+
|
23
|
+
build_command
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def build_command
|
28
|
+
@command = "#{meta.name} #{DEFAULT_PARAMETERS} #{@file}"
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def run
|
33
|
+
# Using 'system' instead of backticks becuase
|
34
|
+
# with the back ticks vim was complaining that it
|
35
|
+
# was not connected to a terminal.
|
36
|
+
system command
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
__END__
|
41
|
+
|
42
|
+
VIM - Vi IMproved 9.0 (2022 Jun 28, compiled Sep 30 2023 05:45:56)
|
43
|
+
|
44
|
+
Usage: vim [arguments] [file ..] edit specified file(s)
|
45
|
+
or: vim [arguments] - read text from stdin
|
46
|
+
or: vim [arguments] -t tag edit file where tag is defined
|
47
|
+
or: vim [arguments] -q [errorfile] edit file with first error
|
48
|
+
|
49
|
+
Arguments:
|
50
|
+
-- Only file names after this
|
51
|
+
-v Vi mode (like "vi")
|
52
|
+
-e Ex mode (like "ex")
|
53
|
+
-E Improved Ex mode
|
54
|
+
-s Silent (batch) mode (only for "ex")
|
55
|
+
-d Diff mode (like "vimdiff")
|
56
|
+
-y Easy mode (like "evim", modeless)
|
57
|
+
-R Readonly mode (like "view")
|
58
|
+
-Z Restricted mode (like "rvim")
|
59
|
+
-m Modifications (writing files) not allowed
|
60
|
+
-M Modifications in text not allowed
|
61
|
+
-b Binary mode
|
62
|
+
-l Lisp mode
|
63
|
+
-C Compatible with Vi: 'compatible'
|
64
|
+
-N Not fully Vi compatible: 'nocompatible'
|
65
|
+
-V[N][fname] Be verbose [level N] [log messages to fname]
|
66
|
+
-D Debugging mode
|
67
|
+
-n No swap file, use memory only
|
68
|
+
-r List swap files and exit
|
69
|
+
-r (with file name) Recover crashed session
|
70
|
+
-L Same as -r
|
71
|
+
-T <terminal> Set terminal type to <terminal>
|
72
|
+
--not-a-term Skip warning for input/output not being a terminal
|
73
|
+
--ttyfail Exit if input or output is not a terminal
|
74
|
+
-u <vimrc> Use <vimrc> instead of any .vimrc
|
75
|
+
--noplugin Don't load plugin scripts
|
76
|
+
-p[N] Open N tab pages (default: one for each file)
|
77
|
+
-o[N] Open N windows (default: one for each file)
|
78
|
+
-O[N] Like -o but split vertically
|
79
|
+
+ Start at end of file
|
80
|
+
+<lnum> Start at line <lnum>
|
81
|
+
--cmd <command> Execute <command> before loading any vimrc file
|
82
|
+
-c <command> Execute <command> after loading the first file
|
83
|
+
-S <session> Source file <session> after loading the first file
|
84
|
+
-s <scriptin> Read Normal mode commands from file <scriptin>
|
85
|
+
-w <scriptout> Append all typed commands to file <scriptout>
|
86
|
+
-W <scriptout> Write all typed commands to file <scriptout>
|
87
|
+
-x Edit encrypted files
|
88
|
+
--startuptime <file> Write startup timing messages to <file>
|
89
|
+
--log <file> Start logging to <file> early
|
90
|
+
-i <viminfo> Use <viminfo> instead of .viminfo
|
91
|
+
--clean 'nocompatible', Vim defaults, no plugins, no viminfo
|
92
|
+
-h or --help Print Help (this message) and exit
|
93
|
+
--version Print version information and exit
|