slideck 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +555 -0
- data/README.md +475 -0
- data/exe/slideck +5 -0
- data/lib/slideck/alignment.rb +201 -0
- data/lib/slideck/cli.rb +268 -0
- data/lib/slideck/converter.rb +88 -0
- data/lib/slideck/errors.rb +61 -0
- data/lib/slideck/loader.rb +45 -0
- data/lib/slideck/margin.rb +345 -0
- data/lib/slideck/metadata.rb +153 -0
- data/lib/slideck/metadata_converter.rb +95 -0
- data/lib/slideck/metadata_defaults.rb +84 -0
- data/lib/slideck/metadata_parser.rb +188 -0
- data/lib/slideck/metadata_wrapper.rb +66 -0
- data/lib/slideck/parser.rb +139 -0
- data/lib/slideck/presenter.rb +272 -0
- data/lib/slideck/renderer.rb +326 -0
- data/lib/slideck/runner.rb +152 -0
- data/lib/slideck/tracker.rb +167 -0
- data/lib/slideck/transformer.rb +42 -0
- data/lib/slideck/version.rb +5 -0
- data/lib/slideck.rb +30 -0
- metadata +203 -0
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slideck
|
4
|
+
# Responsible for parsing metadata in YAML format
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class MetadataParser
|
8
|
+
# The symbolize names parameter
|
9
|
+
#
|
10
|
+
# @return [Symbol]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
SYMBOLIZE_NAMES_PARAMETER = :symbolize_names
|
14
|
+
private_constant :SYMBOLIZE_NAMES_PARAMETER
|
15
|
+
|
16
|
+
# The permitted classes parameter
|
17
|
+
#
|
18
|
+
# @return [Symbol]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
PERMITTED_CLASSES_PARAMETER = :permitted_classes
|
22
|
+
private_constant :PERMITTED_CLASSES_PARAMETER
|
23
|
+
|
24
|
+
# The whitelist classes parameter
|
25
|
+
#
|
26
|
+
# @return [Symbol]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
WHITELIST_CLASSES_PARAMETER = :whitelist_classes
|
30
|
+
private_constant :WHITELIST_CLASSES_PARAMETER
|
31
|
+
|
32
|
+
# Create a MetadataParser instance
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# MetadataParser.new(YAML, symbolize_names: true, permitted_classes: [])
|
36
|
+
#
|
37
|
+
# @param [YAML] yaml_parser
|
38
|
+
# the YAML parser
|
39
|
+
# @param [Boolean] symbolize_names
|
40
|
+
# whether or not to symobolize names
|
41
|
+
# @param [Array<Object>] permitted_classes
|
42
|
+
# the classes allowed to be deserialized
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def initialize(yaml_parser, symbolize_names: nil, permitted_classes: nil)
|
46
|
+
@yaml_parser = yaml_parser
|
47
|
+
@symbolize_names = symbolize_names
|
48
|
+
@permitted_classes = permitted_classes
|
49
|
+
end
|
50
|
+
|
51
|
+
# Parse metadata from content
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# parser.parse("align: center\nfooter: footer content")
|
55
|
+
#
|
56
|
+
# @param [String] content
|
57
|
+
# the content to parse metadata from
|
58
|
+
#
|
59
|
+
# @return [Hash{String, Symbol => Object}]
|
60
|
+
# the deserialized metadata
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def parse(content)
|
64
|
+
parse_method = select_parse_method
|
65
|
+
parse_params = parse_method_params(parse_method)
|
66
|
+
arguments = parser_arguments(parse_params)
|
67
|
+
options = parser_options(parse_params)
|
68
|
+
metadata = @yaml_parser.send(parse_method, content, *arguments, **options)
|
69
|
+
|
70
|
+
return metadata if symbolize_names?(options)
|
71
|
+
|
72
|
+
@symbolize_names ? symbolize_keys(metadata) : metadata
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# Select metadata parse method
|
78
|
+
#
|
79
|
+
# @return [Symbol]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
def select_parse_method
|
83
|
+
@yaml_parser.respond_to?(:safe_load) ? :safe_load : :load
|
84
|
+
end
|
85
|
+
|
86
|
+
# Parse method parameters
|
87
|
+
#
|
88
|
+
# @param [Symbol] parse_method
|
89
|
+
# the parse method name
|
90
|
+
#
|
91
|
+
# @return [Array<Symbol>]
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
def parse_method_params(parse_method)
|
95
|
+
@yaml_parser.method(parse_method).parameters.map(&:last)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Generate parser arguments
|
99
|
+
#
|
100
|
+
# @param [Array<Symbol>] parse_method_params
|
101
|
+
# the parse method parameters
|
102
|
+
#
|
103
|
+
# @return [Array<Object>]
|
104
|
+
#
|
105
|
+
# @api private
|
106
|
+
def parser_arguments(parse_method_params)
|
107
|
+
return [] unless parse_method_params.include?(WHITELIST_CLASSES_PARAMETER)
|
108
|
+
|
109
|
+
[@permitted_classes]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Generate parser options
|
113
|
+
#
|
114
|
+
# @param [Array<Symbol>] parse_method_params
|
115
|
+
# the parse method parameters
|
116
|
+
#
|
117
|
+
# @return [Hash{Symbol => Object}]
|
118
|
+
#
|
119
|
+
# @api private
|
120
|
+
def parser_options(parse_method_params)
|
121
|
+
{}.tap do |opts|
|
122
|
+
if parse_method_params.include?(PERMITTED_CLASSES_PARAMETER)
|
123
|
+
opts[:permitted_classes] = @permitted_classes
|
124
|
+
end
|
125
|
+
|
126
|
+
if parse_method_params.include?(SYMBOLIZE_NAMES_PARAMETER)
|
127
|
+
opts[:symbolize_names] = @symbolize_names
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Check whether the YAML parser can symbolize names or not
|
133
|
+
#
|
134
|
+
# @param [Hash{Symbol => Object}] parse_options
|
135
|
+
# the parse method options
|
136
|
+
#
|
137
|
+
# @return [Boolean]
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
def symbolize_names?(parse_options)
|
141
|
+
parse_options.key?(:symbolize_names)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Symbolize metadata keys
|
145
|
+
#
|
146
|
+
# @param [Object] object
|
147
|
+
# the object with keys to symbolize
|
148
|
+
#
|
149
|
+
# @return [Hash{Symbol => Object}]
|
150
|
+
#
|
151
|
+
# @api private
|
152
|
+
def symbolize_keys(object)
|
153
|
+
case object
|
154
|
+
when Hash then symbolize_hash_keys(object)
|
155
|
+
when Array then symbolize_array_hashes(object)
|
156
|
+
else object
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Symbolize hash keys
|
161
|
+
#
|
162
|
+
# @param [Hash] object
|
163
|
+
# the hash object with keys to symbolize
|
164
|
+
#
|
165
|
+
# @return [Hash{Symbol => Object}]
|
166
|
+
#
|
167
|
+
# @api private
|
168
|
+
def symbolize_hash_keys(object)
|
169
|
+
object.each_with_object({}) do |(key, val), new_hash|
|
170
|
+
new_hash[key.to_sym] = symbolize_keys(val)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Symbolize array hash values
|
175
|
+
#
|
176
|
+
# @param [Array] object
|
177
|
+
# the array object with hash values to symbolize
|
178
|
+
#
|
179
|
+
# @return [Array<Object>]
|
180
|
+
#
|
181
|
+
# @api private
|
182
|
+
def symbolize_array_hashes(object)
|
183
|
+
object.each_with_object([]) do |val, new_array|
|
184
|
+
new_array << symbolize_keys(val)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end # MetadataParser
|
188
|
+
end # Slideck
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slideck
|
4
|
+
# Responsible for wrapping parsed global and slide metadata
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class MetadataWrapper
|
8
|
+
# Create a MetadataWrapper instance
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# MetadataWrapper.new(metadata, metadata_converter, metadata_defaults)
|
12
|
+
#
|
13
|
+
# @param [Slideck::Metadata] metadata
|
14
|
+
# the metadata initialiser
|
15
|
+
# @param [Slideck::MetadataConverter] metadata_converter
|
16
|
+
# the metadata converter
|
17
|
+
# @param [Slideck::MetadataDefaults] metadata_defaults
|
18
|
+
# the metadata defaults
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
def initialize(metadata, metadata_converter, metadata_defaults)
|
22
|
+
@metadata = metadata
|
23
|
+
@metadata_converter = metadata_converter
|
24
|
+
@metadata_defaults = metadata_defaults
|
25
|
+
end
|
26
|
+
|
27
|
+
# Wrap parsed global and slide metadata
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# metadata_wrapper.wrap({metadata: {}, slides: []})
|
31
|
+
#
|
32
|
+
# @param [Hash{Symbol => Hash, String}] deck
|
33
|
+
# the deck of parsed metadata and slides
|
34
|
+
#
|
35
|
+
# @return [Array<Slideck::Metadata, Hash>]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def wrap(deck)
|
39
|
+
[
|
40
|
+
build_metadata(deck[:metadata], @metadata_defaults),
|
41
|
+
deck[:slides].map do |slide|
|
42
|
+
{
|
43
|
+
content: slide[:content],
|
44
|
+
metadata: build_metadata(slide[:metadata], {})
|
45
|
+
}
|
46
|
+
end
|
47
|
+
]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Build metadata
|
53
|
+
#
|
54
|
+
# @param [Hash{Symbol => Object}] custom_metadata
|
55
|
+
# the custom metadata
|
56
|
+
# @param [#merge] defaults
|
57
|
+
# the defaults to merge with
|
58
|
+
#
|
59
|
+
# @return [Slideck::Metadata]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def build_metadata(custom_metadata, defaults)
|
63
|
+
@metadata.from(@metadata_converter, custom_metadata, defaults)
|
64
|
+
end
|
65
|
+
end # MetadataWrapper
|
66
|
+
end # Slideck
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slideck
|
4
|
+
# Responsible for extracting metadata and slides from content
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Parser
|
8
|
+
# The pattern to detect metadata configuration
|
9
|
+
#
|
10
|
+
# @return [Regexp]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
METADATA_PATTERN = /^\s*:?[^:]+:[^:]+/.freeze
|
14
|
+
private_constant :METADATA_PATTERN
|
15
|
+
|
16
|
+
# The pattern to detect slide separator
|
17
|
+
#
|
18
|
+
# @return [Regexp]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
SLIDE_SEPARATOR = /\n?-{3,}([^\n]*)\n/.freeze
|
22
|
+
private_constant :SLIDE_SEPARATOR
|
23
|
+
|
24
|
+
# The pattern to match entire lines
|
25
|
+
#
|
26
|
+
# @return [Regexp]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
LINE_PATTERN = /^[^\n]+$/.freeze
|
30
|
+
private_constant :LINE_PATTERN
|
31
|
+
|
32
|
+
# Create a Parser instance
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# Parser.new(StringScanner, Slideck::MetadataParser)
|
36
|
+
#
|
37
|
+
# @param [StringScanner] string_scanner
|
38
|
+
# the content scanner
|
39
|
+
# @param [Slideck::MetadataParser] metadata_parser
|
40
|
+
# the metadata parser
|
41
|
+
#
|
42
|
+
# @api public
|
43
|
+
def initialize(string_scanner, metadata_parser)
|
44
|
+
@string_scanner = string_scanner
|
45
|
+
@metadata_parser = metadata_parser
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parse metadata and slides from content
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# parser.parse("align: center\n---\nSlide1\n---\nSlide2\n---")
|
52
|
+
#
|
53
|
+
# @param [String] content
|
54
|
+
# the content to parse slides from
|
55
|
+
#
|
56
|
+
# @return [Hash{Symbol => Hash, Array<String>}]
|
57
|
+
# the metadata and slides content
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
def parse(content)
|
61
|
+
scanner = @string_scanner.new(content)
|
62
|
+
slides = split_into_slides(scanner)
|
63
|
+
metadata = extract_metadata(slides.first && slides.first[:content])
|
64
|
+
|
65
|
+
{metadata: metadata, slides: metadata.empty? ? slides : slides[1..-1]}
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Split content into slides
|
71
|
+
#
|
72
|
+
# @param [StringScanner] scanner
|
73
|
+
# the slides content scanner
|
74
|
+
#
|
75
|
+
# @return [Array<String>]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
def split_into_slides(scanner)
|
79
|
+
slides, slide, slide_metadata = [], [], {}
|
80
|
+
|
81
|
+
until scanner.eos?
|
82
|
+
if scanner.scan(SLIDE_SEPARATOR)
|
83
|
+
slides = add_slide(slides, slide.join, slide_metadata)
|
84
|
+
slide_metadata = extract_metadata(scanner[1])
|
85
|
+
slide.clear
|
86
|
+
elsif scanner.scan(LINE_PATTERN)
|
87
|
+
slide << scanner.matched
|
88
|
+
else
|
89
|
+
slide << scanner.getch
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
add_slide(slides, slide.join.chomp, slide_metadata)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Add a slide to slides
|
97
|
+
#
|
98
|
+
# @param [Array<String>] slides
|
99
|
+
# the slides array
|
100
|
+
# @param [String] slide
|
101
|
+
# the slide to add to slides
|
102
|
+
# @param [Hash{String, Symbol => Object}] slide_metadata
|
103
|
+
# the slide metadata
|
104
|
+
#
|
105
|
+
# @return [Array<Hash{Symbol => Hash, String}>]
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
def add_slide(slides, slide, slide_metadata)
|
109
|
+
return slides if slide.empty?
|
110
|
+
|
111
|
+
slides + [{content: slide, metadata: slide_metadata}]
|
112
|
+
end
|
113
|
+
|
114
|
+
# Extract metadata from a slide
|
115
|
+
#
|
116
|
+
# @param [String, nil] slide
|
117
|
+
#
|
118
|
+
# @return [Hash]
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
def extract_metadata(slide)
|
122
|
+
return {} if slide.nil? || !metadata_given?(slide)
|
123
|
+
|
124
|
+
@metadata_parser.parse(slide)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Check whether or not metadata is given
|
128
|
+
#
|
129
|
+
# @param [String] content
|
130
|
+
# the slide content to check
|
131
|
+
#
|
132
|
+
# @return [Boolean]
|
133
|
+
#
|
134
|
+
# @api private
|
135
|
+
def metadata_given?(content)
|
136
|
+
!(content.lines.first =~ METADATA_PATTERN).nil?
|
137
|
+
end
|
138
|
+
end # Parser
|
139
|
+
end # Slideck
|
@@ -0,0 +1,272 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slideck
|
4
|
+
# Responsible for presenting slides
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Presenter
|
8
|
+
# Terminal screen size change signal
|
9
|
+
#
|
10
|
+
# @return [String]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
TERM_SCREEN_SIZE_CHANGE_SIG = "WINCH"
|
14
|
+
private_constant :TERM_SCREEN_SIZE_CHANGE_SIG
|
15
|
+
|
16
|
+
# Create a Presenter
|
17
|
+
#
|
18
|
+
# @param [TTY::Reader] reader
|
19
|
+
# the keyboard input reader
|
20
|
+
# @param [Slideck::Renderer] renderer
|
21
|
+
# the slides renderer
|
22
|
+
# @param [Slideck::Tracker] tracker
|
23
|
+
# the tracker for slides
|
24
|
+
# @param [TTY::Screen] screen
|
25
|
+
# the terminal screen size
|
26
|
+
# @param [IO] output
|
27
|
+
# the output stream for the slides
|
28
|
+
# @param [Proc] reloader
|
29
|
+
# the metadata and slides reloader
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
def initialize(reader, renderer, tracker, screen, output, &reloader)
|
33
|
+
@reader = reader
|
34
|
+
@renderer = renderer
|
35
|
+
@tracker = tracker
|
36
|
+
@screen = screen
|
37
|
+
@output = output
|
38
|
+
@reloader = reloader
|
39
|
+
@stop = false
|
40
|
+
@buffer = []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Reload presentation
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# presenter.reload
|
47
|
+
#
|
48
|
+
# @return [Slideck::Presenter]
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def reload
|
52
|
+
@metadata, @slides = *@reloader.()
|
53
|
+
@tracker = @tracker.resize(@slides.size)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# Start presentation
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# presenter.start
|
61
|
+
#
|
62
|
+
# @return [void]
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
def start
|
66
|
+
reload
|
67
|
+
@reader.subscribe(self)
|
68
|
+
hide_cursor
|
69
|
+
subscribe_to_screen_resize { resize.render }
|
70
|
+
|
71
|
+
until @stop
|
72
|
+
render
|
73
|
+
@reader.read_keypress
|
74
|
+
end
|
75
|
+
ensure
|
76
|
+
show_cursor
|
77
|
+
end
|
78
|
+
|
79
|
+
# Stop presentation
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# presenter.stop
|
83
|
+
#
|
84
|
+
# @return [Slideck::Presenter]
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
def stop
|
88
|
+
@stop = true
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Render presentation on cleared screen
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# presenter.render
|
96
|
+
#
|
97
|
+
# @return [void]
|
98
|
+
#
|
99
|
+
# @api public
|
100
|
+
def render
|
101
|
+
clear_screen
|
102
|
+
render_slide
|
103
|
+
end
|
104
|
+
|
105
|
+
# Clear terminal screen
|
106
|
+
#
|
107
|
+
# @return [void]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
def clear_screen
|
111
|
+
@output.print @renderer.clear
|
112
|
+
end
|
113
|
+
|
114
|
+
# Render the current slide
|
115
|
+
#
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
def render_slide
|
120
|
+
@output.print @renderer.render(
|
121
|
+
@metadata,
|
122
|
+
@slides[@tracker.current],
|
123
|
+
@tracker.current + 1,
|
124
|
+
@tracker.total)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Hide cursor
|
128
|
+
#
|
129
|
+
# @return [void]
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
def hide_cursor
|
133
|
+
@output.print @renderer.cursor.hide
|
134
|
+
end
|
135
|
+
|
136
|
+
# Show cursor
|
137
|
+
#
|
138
|
+
# @return [void]
|
139
|
+
#
|
140
|
+
# @api private
|
141
|
+
def show_cursor
|
142
|
+
@output.print @renderer.cursor.show
|
143
|
+
end
|
144
|
+
|
145
|
+
# Subscribe to the terminal screen size change signal
|
146
|
+
#
|
147
|
+
# @param [Proc] resizer
|
148
|
+
# the presentation resizer
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
def subscribe_to_screen_resize(&resizer)
|
154
|
+
return if @screen.windows?
|
155
|
+
|
156
|
+
Signal.trap(TERM_SCREEN_SIZE_CHANGE_SIG, &resizer)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Resize presentation
|
160
|
+
#
|
161
|
+
# @return [Slideck::Presenter]
|
162
|
+
#
|
163
|
+
# @api private
|
164
|
+
def resize
|
165
|
+
@renderer = @renderer.resize(@screen.width, @screen.height)
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Handle a keypress event
|
170
|
+
#
|
171
|
+
# @param [TTY::Reader::KeyEvent] event
|
172
|
+
# the key event
|
173
|
+
#
|
174
|
+
# @return [void]
|
175
|
+
#
|
176
|
+
# @api private
|
177
|
+
def keypress(event)
|
178
|
+
case event.value
|
179
|
+
when "n", "l" then keyright
|
180
|
+
when "p", "h" then keyleft
|
181
|
+
when "f", "^" then go_to_first
|
182
|
+
when "t", "$" then go_to_last
|
183
|
+
when "g" then go_to_slide
|
184
|
+
when /\d/ then add_to_buffer(event.value)
|
185
|
+
when "r" then keyctrl_l
|
186
|
+
when "q" then keyctrl_x
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Navigate to the next slide
|
191
|
+
#
|
192
|
+
# @return [void]
|
193
|
+
#
|
194
|
+
# @api private
|
195
|
+
def keyright(*)
|
196
|
+
@tracker = @tracker.next
|
197
|
+
end
|
198
|
+
alias keyspace keyright
|
199
|
+
alias keypage_down keyright
|
200
|
+
|
201
|
+
# Navigate to the previous slide
|
202
|
+
#
|
203
|
+
# @return [void]
|
204
|
+
#
|
205
|
+
# @api private
|
206
|
+
def keyleft(*)
|
207
|
+
@tracker = @tracker.previous
|
208
|
+
end
|
209
|
+
alias keybackspace keyleft
|
210
|
+
alias keypage_up keyleft
|
211
|
+
|
212
|
+
# Reload presentation
|
213
|
+
#
|
214
|
+
# @return [void]
|
215
|
+
#
|
216
|
+
# @api private
|
217
|
+
def keyctrl_l(*)
|
218
|
+
reload
|
219
|
+
end
|
220
|
+
|
221
|
+
# Exit presentation
|
222
|
+
#
|
223
|
+
# @return [void]
|
224
|
+
#
|
225
|
+
# @api private
|
226
|
+
def keyctrl_x(*)
|
227
|
+
clear_screen
|
228
|
+
stop
|
229
|
+
end
|
230
|
+
alias keyescape keyctrl_x
|
231
|
+
|
232
|
+
# Navigate to the fist slide
|
233
|
+
#
|
234
|
+
# @return [void]
|
235
|
+
#
|
236
|
+
# @api private
|
237
|
+
def go_to_first
|
238
|
+
@tracker = @tracker.first
|
239
|
+
end
|
240
|
+
|
241
|
+
# Navigate to the last slide
|
242
|
+
#
|
243
|
+
# @return [void]
|
244
|
+
#
|
245
|
+
# @api private
|
246
|
+
def go_to_last
|
247
|
+
@tracker = @tracker.last
|
248
|
+
end
|
249
|
+
|
250
|
+
# Navigate to a given slide
|
251
|
+
#
|
252
|
+
# @return [void]
|
253
|
+
#
|
254
|
+
# @api private
|
255
|
+
def go_to_slide
|
256
|
+
@tracker = @tracker.go_to(@buffer.join.to_i - 1)
|
257
|
+
@buffer.clear
|
258
|
+
end
|
259
|
+
|
260
|
+
# Add to the input buffer
|
261
|
+
#
|
262
|
+
# @param [String] input_key
|
263
|
+
# the input key
|
264
|
+
#
|
265
|
+
# @return [void]
|
266
|
+
#
|
267
|
+
# @api private
|
268
|
+
def add_to_buffer(input_key)
|
269
|
+
@buffer += [input_key]
|
270
|
+
end
|
271
|
+
end # Presenter
|
272
|
+
end # Slideck
|