yap-shell 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.ruby-version +1 -1
- data/.travis.yml +11 -0
- data/Gemfile.travis +8 -0
- data/README.md +9 -11
- data/addons/history/history.rb +1 -0
- data/addons/history_search/history_search.rb +21 -17
- data/bin/yap +47 -55
- data/bin/yap-dev +0 -1
- data/lib/yap/configuration.rb +25 -0
- data/lib/yap/shell/builtins/alias.rb +16 -0
- data/lib/yap/shell/commands.rb +15 -3
- data/lib/yap/shell/evaluation/shell_expansions.rb +10 -10
- data/lib/yap/shell/evaluation.rb +29 -4
- data/lib/yap/shell/execution/context.rb +3 -2
- data/lib/yap/shell/execution/file_system_command_execution.rb +9 -17
- data/lib/yap/shell/repl.rb +2 -5
- data/lib/yap/shell/version.rb +1 -1
- data/lib/yap/shell.rb +8 -2
- data/lib/yap/world.rb +23 -18
- data/lib/yap.rb +52 -7
- data/spec/features/aliases_spec.rb +78 -0
- data/spec/features/environment_variables_spec.rb +69 -0
- data/spec/features/filesystem_commands_spec.rb +61 -0
- data/spec/features/first_time_spec.rb +45 -0
- data/spec/features/grouping_spec.rb +81 -0
- data/spec/features/line_editing_spec.rb +166 -0
- data/spec/features/range_spec.rb +35 -0
- data/spec/features/redirection_spec.rb +225 -0
- data/spec/features/repetition_spec.rb +118 -0
- data/spec/features/shell_expansions_spec.rb +127 -0
- data/spec/spec_helper.rb +162 -0
- data/spec/support/matchers/have_not_printed.rb +30 -0
- data/spec/support/matchers/have_printed.rb +30 -0
- data/spec/support/very_soon.rb +9 -0
- data/spec/support/yap_spec_dsl.rb +240 -0
- data/yap-shell.gemspec +4 -2
- metadata +69 -8
data/lib/yap.rb
CHANGED
@@ -1,17 +1,62 @@
|
|
1
|
-
require
|
1
|
+
require "term/ansicolor"
|
2
|
+
require "tins"
|
3
|
+
require "byebug"
|
4
|
+
require "pry"
|
5
|
+
require "treefell"
|
6
|
+
require 'optparse'
|
2
7
|
|
3
8
|
module Yap
|
4
9
|
require 'yap/configuration'
|
5
10
|
require 'yap/shell'
|
6
11
|
require 'yap/world'
|
7
12
|
|
8
|
-
def self.
|
13
|
+
def self.parse_cli_args_for_configuration(args, configuration)
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.on('-h', '--help', 'Prints this help') do
|
16
|
+
puts opts
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('--skip-first-time', 'Disables creating ~/.yap directory on shell startup') do
|
21
|
+
configuration.skip_first_time = true
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on('--no-addons', 'Disables auto-loading addons on shell startup') do
|
25
|
+
configuration.use_addons = false
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on('--no-history', 'Disables auto-loading or saving history') do
|
29
|
+
configuration.use_history = false
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on('--no-rcfiles', 'Disables auto-loading rcfiles on shell startup') do
|
33
|
+
configuration.use_rcfiles = false
|
34
|
+
end
|
35
|
+
end.parse!(args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.run_shell(argv)
|
9
39
|
Treefell['shell'].puts "#{self}.#{__callee__} booting shell"
|
10
|
-
addons = [
|
11
|
-
World::Addons.load_directories(configuration.addon_paths),
|
12
|
-
World::Addons.load_rcfiles(configuration.rcfiles)
|
13
|
-
].flatten
|
14
40
|
|
15
|
-
|
41
|
+
parse_cli_args_for_configuration(argv, configuration)
|
42
|
+
|
43
|
+
addons_loaded = []
|
44
|
+
if configuration.use_addons?
|
45
|
+
Treefell['shell'].puts "#{self}.#{__callee__} loading addons"
|
46
|
+
addons_loaded.concat \
|
47
|
+
World::Addons.load_directories(configuration.addon_paths)
|
48
|
+
else
|
49
|
+
Treefell['shell'].puts "#{self}.#{__callee__} skipping addons"
|
50
|
+
end
|
51
|
+
|
52
|
+
if configuration.use_rcfiles?
|
53
|
+
Treefell['shell'].puts "#{self}.#{__callee__} loading rcfiles"
|
54
|
+
addons_loaded.concat \
|
55
|
+
World::Addons.load_rcfiles(configuration.rcfiles)
|
56
|
+
else
|
57
|
+
Treefell['shell'].puts "#{self}.#{__callee__} skipping rcfiles"
|
58
|
+
end
|
59
|
+
|
60
|
+
Shell::Impl.new(addons: addons_loaded).repl
|
16
61
|
end
|
17
62
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Aliases', type: :feature do
|
4
|
+
before do
|
5
|
+
type "alias foo='echo bar'"
|
6
|
+
enter
|
7
|
+
expect { output }.to have_printed(/Setting alias foo done/)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'sets them' do
|
11
|
+
type 'alias | grep foo'
|
12
|
+
enter
|
13
|
+
expect { output }.to have_printed(/alias foo='echo bar'/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'executes them' do
|
17
|
+
type 'foo'
|
18
|
+
enter
|
19
|
+
expect { output }.to have_printed(/bar\n/)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'unsets them' do
|
23
|
+
type 'unalias foo'
|
24
|
+
enter
|
25
|
+
expect { output }.to have_printed(/Removing alias foo done\n/)
|
26
|
+
|
27
|
+
type 'alias | grep foo'
|
28
|
+
enter
|
29
|
+
expect(output).to_not match(/alias foo='echo bar'/)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'conditionals' do
|
33
|
+
before do
|
34
|
+
type "alias fail='non-existent-command'"
|
35
|
+
enter
|
36
|
+
type "alias pass='echo pass'"
|
37
|
+
enter
|
38
|
+
clear_all_output
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'supports logical AND: &&' do
|
42
|
+
type "pass && pass"
|
43
|
+
enter
|
44
|
+
expect { output }.to have_printed(/pass.*\n.*pass/m)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'supports logical OR: &&' do
|
48
|
+
type "fail || pass"
|
49
|
+
enter
|
50
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
51
|
+
expect { output }.to have_printed(/pass/m)
|
52
|
+
clear_all_output
|
53
|
+
|
54
|
+
type "echo $?"
|
55
|
+
enter
|
56
|
+
expect { output }.to have_printed(/0/m)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'can combine logical AND and OR' do
|
60
|
+
type "(pass && fail) || pass"
|
61
|
+
enter
|
62
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
63
|
+
expect { output }.to have_printed(/pass.*\n.*pass/m)
|
64
|
+
clear_all_output
|
65
|
+
|
66
|
+
type "(pass || fail) && pass"
|
67
|
+
enter
|
68
|
+
expect { error_output }.to have_not_printed(/yap: command not found: non-existent-command/m)
|
69
|
+
expect { output }.to have_printed(/pass.*\n.*pass/m)
|
70
|
+
clear_all_output
|
71
|
+
|
72
|
+
type "(fail && pass) && pass"
|
73
|
+
enter
|
74
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
75
|
+
expect { output }.to have_not_printed(/pass.*\n.*pass/m)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Environment variables', type: :feature do
|
4
|
+
it 'sets and gets them with: NAME=value' do
|
5
|
+
type 'FOO=foobarbaz'
|
6
|
+
enter
|
7
|
+
|
8
|
+
type 'echo $FOO'
|
9
|
+
enter
|
10
|
+
expect { output }.to have_printed('foobarbaz')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can set multiple on a single line: NAME1=value1 NAME2=value2 etc' do
|
14
|
+
type 'A=b B=c C=d'
|
15
|
+
enter
|
16
|
+
clear_all_output
|
17
|
+
|
18
|
+
type 'echo $A $B $C'
|
19
|
+
enter
|
20
|
+
expect { output }.to have_printed('b c d')
|
21
|
+
clear_all_output
|
22
|
+
|
23
|
+
type 'echo $A$B$C'
|
24
|
+
enter
|
25
|
+
expect { output }.to have_printed('bcd')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'expands env vars inside of double quotes' do
|
29
|
+
type 'BAR=foobarbaz'
|
30
|
+
enter
|
31
|
+
|
32
|
+
type %|echo "BAR is $BAR"|
|
33
|
+
enter
|
34
|
+
expect { output }.to have_printed('BAR is foobarbaz')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not expand env vars inside of single quotes' do
|
38
|
+
type 'BAR=foobarbaz'
|
39
|
+
enter
|
40
|
+
|
41
|
+
type %|echo 'BAR is $BAR'|
|
42
|
+
enter
|
43
|
+
expect { output }.to have_printed('BAR is $BAR')
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'setting env vars for a single statement' do
|
47
|
+
it 'makes the env var available to the statement' do
|
48
|
+
type 'BAZ=baz echo $BAZ'
|
49
|
+
enter
|
50
|
+
expect { output }.to have_printed('baz')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not keep the env var around for the next statement' do
|
54
|
+
type 'BAZ=baz echo $BAZ'
|
55
|
+
enter
|
56
|
+
clear_all_output
|
57
|
+
|
58
|
+
type 'echo $BAZ'
|
59
|
+
enter
|
60
|
+
expect { output }.to have_printed('$BAZ')
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can set multiple env vars for a statement' do
|
64
|
+
type %|FOO=foo BAR='is the' BAZ="fastest pineapple" echo $FOO $BAR $BAZ|
|
65
|
+
enter
|
66
|
+
expect { output }.to have_printed('foo is the fastest pineapple')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Filesystem commands', type: :feature do
|
4
|
+
it 'runs filesystem commands' do
|
5
|
+
touch 'bar.txt'
|
6
|
+
type 'ls .'
|
7
|
+
enter
|
8
|
+
|
9
|
+
expect { output }.to have_printed("bar.txt")
|
10
|
+
|
11
|
+
type 'echo "hello there"'
|
12
|
+
enter
|
13
|
+
expect { output }.to have_printed("hello there\n")
|
14
|
+
clear_all_output
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'pipes filesystem commands' do
|
18
|
+
type "echo 'food' | sed -e 's/o/_/g'"
|
19
|
+
enter
|
20
|
+
expect { output }.to have_printed(/^f__d\n/m)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'conditionals' do
|
24
|
+
it 'supports logical AND: &&' do
|
25
|
+
type "echo foo && echo bar"
|
26
|
+
enter
|
27
|
+
expect { output }.to have_printed(/foo.*\n.*bar/m)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'supports logical OR: &&' do
|
31
|
+
type "non-existent-command || echo bar"
|
32
|
+
enter
|
33
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
34
|
+
expect { output }.to have_printed(/bar/m)
|
35
|
+
clear_all_output
|
36
|
+
|
37
|
+
type "echo $?"
|
38
|
+
enter
|
39
|
+
expect { output }.to have_printed(/0/m)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can combine logical AND and OR' do
|
43
|
+
type "(echo foo && non-existent-command) || echo bar"
|
44
|
+
enter
|
45
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
46
|
+
expect { output }.to have_printed(/foo.*\n.*bar/m)
|
47
|
+
clear_all_output
|
48
|
+
|
49
|
+
type "(echo foo || non-existent-command) && echo bar"
|
50
|
+
enter
|
51
|
+
expect { error_output }.to have_not_printed(/yap: command not found: non-existent-command/m)
|
52
|
+
expect { output }.to have_printed(/foo.*\n.*bar/m)
|
53
|
+
clear_all_output
|
54
|
+
|
55
|
+
type "(non-existent-command && echo foo) && echo bar"
|
56
|
+
enter
|
57
|
+
expect { error_output }.to have_printed(/yap: command not found: non-existent-command/m)
|
58
|
+
expect { output }.to have_not_printed(/foo.*\n.*bar/m)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Running Yap for the first time', type: :feature, forks: true do
|
4
|
+
before do
|
5
|
+
# do not pass in --skip-first-time
|
6
|
+
set_yap_command_line_arguments \
|
7
|
+
'--no-history', '--no-addons', '--no-rcfiles'
|
8
|
+
|
9
|
+
turn_on_debug_log(debug: 'editor')
|
10
|
+
reinitialize_shell
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'tells the user it has been initialized' do
|
14
|
+
home_dir = tmp_dir.to_s
|
15
|
+
message = <<-EOT.gsub(/^\s*\|/, '').chomp
|
16
|
+
|Yap directory not found: #{home_dir}/.yap
|
17
|
+
|
|
18
|
+
|Initializing yap for the first time:
|
19
|
+
|
|
20
|
+
| Creating #{home_dir}/.yap done
|
21
|
+
| Creating default #{home_dir}/.yap/yaprc done
|
22
|
+
|
|
23
|
+
|To tweak yap take a look at #{home_dir}/.yap/yaprc.
|
24
|
+
|
|
25
|
+
|Reloading shell
|
26
|
+
EOT
|
27
|
+
expect { output }.to have_printed(message)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'creates a $HOME/.yap/ directory for yap things to go' do
|
31
|
+
expect { output }.to have_printed('Reloading shell')
|
32
|
+
|
33
|
+
dot_yap_dir = tmp_dir.join('.yap').to_s
|
34
|
+
expect(Dir.exist?(dot_yap_dir)).to be(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'creates a default .yap/yaprc rcfile' do
|
38
|
+
expect { output }.to have_printed('Reloading shell')
|
39
|
+
|
40
|
+
yaprc = tmp_dir.join('.yap/yaprc').to_s
|
41
|
+
templaterc = yap_dir.join('rcfiles/yaprc')
|
42
|
+
expect(File.exist?(yaprc)).to be(true)
|
43
|
+
expect(IO.read(yaprc)).to eq(IO.read(templaterc))
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Grouping commands', type: :feature do
|
4
|
+
before do
|
5
|
+
write_executable_script 'pass', <<-SCRIPT.strip_heredoc
|
6
|
+
|#!/bin/sh
|
7
|
+
|echo pass $1
|
8
|
+
|exit 0
|
9
|
+
SCRIPT
|
10
|
+
|
11
|
+
write_executable_script 'fail', <<-SCRIPT.strip_heredoc
|
12
|
+
|#!/bin/sh
|
13
|
+
|echo fail $1
|
14
|
+
|exit 1
|
15
|
+
SCRIPT
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'using parentheses' do
|
19
|
+
it 'works with: (command1 && command2) || command3' do
|
20
|
+
type '(./pass 1 && ./fail 2) || ./pass 3'
|
21
|
+
enter
|
22
|
+
expect { output }.to have_printed(/pass 1.*fail 2.*pass 3/m)
|
23
|
+
clear_all_output
|
24
|
+
|
25
|
+
type '(./fail 1 && ./pass 2) || ./pass 3'
|
26
|
+
enter
|
27
|
+
expect { output }.to have_printed(/fail 1.*pass 3/m)
|
28
|
+
expect { output }.to have_not_printed(/pass 2/m)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'works with: (command1 && command2 && command3) || command4' do
|
32
|
+
type '(./pass 1 && ./fail 2 && ./pass 3) || ./pass 4'
|
33
|
+
enter
|
34
|
+
expect { output }.to have_printed(/pass 1.*fail 2.*pass 4/m)
|
35
|
+
expect { output }.to have_not_printed(/pass 1.*fail 2.*pass 3.*pass 4/m)
|
36
|
+
clear_all_output
|
37
|
+
|
38
|
+
type '(./fail 1 && ./pass 2 && ./pass 3) || ./pass 4'
|
39
|
+
enter
|
40
|
+
expect { output }.to have_printed(/fail 1.*pass 4/m)
|
41
|
+
expect { output }.to have_not_printed(/pass 2.*pass 3/m)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'works with: (command1 || command2) && command4' do
|
45
|
+
type '(./fail 1 || ./pass 2) && ./pass 3'
|
46
|
+
enter
|
47
|
+
expect { output }.to have_printed(/fail 1.*pass 2.*pass 3/m)
|
48
|
+
|
49
|
+
type '(./pass 1 || ./fail 2) && ./pass 3'
|
50
|
+
enter
|
51
|
+
expect { output }.to have_printed(/pass 1.*pass 3/m)
|
52
|
+
expect { output }.to have_not_printed(/fail 2/m)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'works with: (command1 && command2) && command4' do
|
56
|
+
type '(./fail 1 && ./pass 2) && ./pass 3'
|
57
|
+
enter
|
58
|
+
expect { output }.to have_printed(/fail 1/m)
|
59
|
+
expect { output }.to have_not_printed(/.*pass 2.*pass 3/m)
|
60
|
+
clear_all_output
|
61
|
+
|
62
|
+
type '(./pass 1 && ./fail 2) && ./pass 3'
|
63
|
+
enter
|
64
|
+
expect { output }.to have_printed(/pass 1.*fail 2/m)
|
65
|
+
expect { output }.to have_not_printed(/pass 3/m)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'works with: (command1 || command2) || command4' do
|
69
|
+
type '(./fail 1 || ./pass 2) || ./pass 3'
|
70
|
+
enter
|
71
|
+
expect { output }.to have_printed(/fail 1.*pass 2/m)
|
72
|
+
expect { output }.to have_not_printed(/pass 3/m)
|
73
|
+
|
74
|
+
type '(./pass 1 || ./fail 2) || ./pass 3'
|
75
|
+
enter
|
76
|
+
expect { output }.to have_printed(/pass 1/m)
|
77
|
+
expect { output }.to have_not_printed(/fail 2.*pass 3/m)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Line editing', type: :feature do
|
4
|
+
let(:left_arrow) { [?\e, ?[, ?D].join }
|
5
|
+
let(:right_arrow) { [?\e, ?[, ?C].join }
|
6
|
+
let(:backspace){ [?\C-?].join }
|
7
|
+
let(:delete){ [?\e, ?[, ?3, ?~].join }
|
8
|
+
|
9
|
+
it 'Left/Right arrow keys move cursor one position left/right' do
|
10
|
+
# cursor is right the 'o'
|
11
|
+
type 'echo hli'
|
12
|
+
|
13
|
+
# let's fix this
|
14
|
+
type left_arrow
|
15
|
+
type left_arrow
|
16
|
+
type 'e'
|
17
|
+
|
18
|
+
type right_arrow
|
19
|
+
type right_arrow
|
20
|
+
type 'copter'
|
21
|
+
enter
|
22
|
+
expect { output }.to have_printed('helicopter')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'Backspace deletes one character left of the cursor, moving the cursor with it' do
|
26
|
+
type 'echo hello worfd'
|
27
|
+
type left_arrow
|
28
|
+
type backspace
|
29
|
+
type 'l'
|
30
|
+
enter
|
31
|
+
expect { output }.to have_printed('hello world')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'Delete deletes the character under the cursor, leaving the cursor where it is' do
|
35
|
+
type 'echo hello world'
|
36
|
+
6.times { type left_arrow }
|
37
|
+
6.times { type delete }
|
38
|
+
enter
|
39
|
+
expect { output }.to have_printed('hello')
|
40
|
+
expect { output }.to have_not_printed('world')
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'line navigation (default key bindings)' do
|
44
|
+
it 'Ctrl-a moves to beginning of line' do
|
45
|
+
type 'o hello world'
|
46
|
+
type ?\C-a
|
47
|
+
type 'ech'
|
48
|
+
enter
|
49
|
+
expect { output }.to have_printed('hello world')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'Ctrl-e moves to end of line' do
|
53
|
+
type 'o hello'
|
54
|
+
type ?\C-a
|
55
|
+
type 'ech'
|
56
|
+
type ?\C-e
|
57
|
+
type ' world'
|
58
|
+
enter
|
59
|
+
expect { output }.to have_printed('hello world')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'Ctrl-b moves backward one line at a time' do
|
63
|
+
type 'echo hello ld'
|
64
|
+
type ?\C-b
|
65
|
+
type 'wor'
|
66
|
+
enter
|
67
|
+
expect { output }.to have_printed(/^hello world/)
|
68
|
+
clear_all_output
|
69
|
+
|
70
|
+
type 'echo hello world' #, ?\C-b, ?\C-b, 'foo'].join
|
71
|
+
type ?\C-b
|
72
|
+
type ?\C-b
|
73
|
+
type 'foo '
|
74
|
+
enter
|
75
|
+
expect { output }.to have_printed(/^foo hello world/)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'Ctrl-f moves forward one word at a time' do
|
79
|
+
type 'echo hello world'
|
80
|
+
type ?\C-a
|
81
|
+
type ?\C-f
|
82
|
+
type 'bob says '
|
83
|
+
enter
|
84
|
+
expect { output }.to have_printed('bob says hello world')
|
85
|
+
clear_all_output
|
86
|
+
|
87
|
+
type 'echo hello world'
|
88
|
+
type ?\C-a
|
89
|
+
type ?\C-f
|
90
|
+
type ?\C-f
|
91
|
+
type 'foo '
|
92
|
+
enter
|
93
|
+
expect { output }.to have_printed('hello foo world')
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'Ctrl-k kills text forward from the cursor position' do
|
97
|
+
type 'echo hello world'
|
98
|
+
type ?\C-b
|
99
|
+
type ?\C-k
|
100
|
+
enter
|
101
|
+
expect { output }.to have_printed('hello')
|
102
|
+
clear_all_output
|
103
|
+
|
104
|
+
type 'echo hello world'
|
105
|
+
type ?\C-b
|
106
|
+
type ?\C-b
|
107
|
+
type ?\C-k
|
108
|
+
type 'foo'
|
109
|
+
enter
|
110
|
+
expect { output }.to have_printed('foo')
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'Ctrl-y does not insert when there is no killed text' do
|
114
|
+
type 'echo "hello world"'
|
115
|
+
type left_arrow
|
116
|
+
type ?\C-y
|
117
|
+
enter
|
118
|
+
expect { output }.to have_printed('hello world')
|
119
|
+
clear_all_output
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'Ctrl-y inserts the last killed text where the cursor is' do
|
123
|
+
type 'echo hello world'
|
124
|
+
type ?\C-b
|
125
|
+
type ?\C-k
|
126
|
+
type 'delightful '
|
127
|
+
type ?\C-y
|
128
|
+
enter
|
129
|
+
expect { output }.to have_printed('hello delightful world')
|
130
|
+
clear_all_output
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'Ctrl-w deletes a word backwards, adding it to the kill ring' do
|
134
|
+
type 'echo hello world'
|
135
|
+
type ?\C-w
|
136
|
+
enter
|
137
|
+
expect { output }.to have_printed('hello')
|
138
|
+
clear_all_output
|
139
|
+
|
140
|
+
type 'echo hello world'
|
141
|
+
type ?\C-w
|
142
|
+
type ?\C-w
|
143
|
+
type 'nope'
|
144
|
+
enter
|
145
|
+
expect { output }.to have_printed('nope')
|
146
|
+
expect { output }.to have_not_printed('hello world')
|
147
|
+
|
148
|
+
type 'echo '
|
149
|
+
type ?\C-y
|
150
|
+
enter
|
151
|
+
expect { output }.to have_printed('hello')
|
152
|
+
expect { output }.to have_not_printed('world')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'Ctrl-u deletes from the cursor to the beginning of the line, adding to the killing as ring' do
|
156
|
+
type 'echo hello world'
|
157
|
+
type ?\C-u
|
158
|
+
type 'echo '
|
159
|
+
type ?\C-y
|
160
|
+
enter
|
161
|
+
expect { output }.to have_printed('echo hello world')
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Ranges', type: :feature do
|
4
|
+
describe 'line repetition: (M..N): statement' do
|
5
|
+
it 'runs the line N times' do
|
6
|
+
type '(0..2) : echo foo'
|
7
|
+
enter
|
8
|
+
expect { output }.to have_printed(/(.*foo){3}/m)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'line repetition w/parameter: (M..N) as n: statement' do
|
13
|
+
it 'runs the line N times supplying an index' do
|
14
|
+
type '(0..2) as n: echo foo $n'
|
15
|
+
enter
|
16
|
+
expect { output }.to have_printed(/foo 0.*\n.*foo 1.*\n.*foo 2/m)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'block repetition: (M..N) { statement } ; echo bar' do
|
21
|
+
it 'runs the block N times' do
|
22
|
+
type 'echo baz; (0..2) { echo foo } ; echo bar'
|
23
|
+
enter
|
24
|
+
expect { output }.to have_printed(/baz.*\n(.*foo){3}.*\n.*bar/m)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'block repetition w/parameter: (M..N) { |n| statement }' do
|
29
|
+
it 'runs the block N times supplying an index' do
|
30
|
+
type 'echo baz ; (0..2) { |n| echo foo $n } ; echo bar'
|
31
|
+
enter
|
32
|
+
expect { output }.to have_printed(/baz.*\n.*foo 0.*\n.*foo 1.*\n.*foo 2.*\n.*bar/m)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|