slideck 0.1.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 +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
|