yap-shell 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|