-
Notifications
You must be signed in to change notification settings - Fork 1
/
screencast-mode.el
820 lines (735 loc) · 31.9 KB
/
screencast-mode.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
;;; screencast.el --- demonstrate the capabilities of Emacs
;; Copyright (C) 2009 ESBEN Andreasen <[email protected]>
;; Authors: Esben Andreasen <[email protected]>
;; Version: 1.1
;; Keywords: demo screencast
;; This file is not an official part of Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, you can either send email to this
;; program's maintainer or write to: The Free Software Foundation,
;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
;;; Commentary:
;; This file allows you to create video-like sessions, which
;; demonstrates the capabilities of Emacs.
;;; Usage:
;; Install this file to an appropriate directory in your load-path,
;; and add these expressions to your ~/.emacs
;; (auto-load 'screencast "screencast")
;; Try it out by evaluating (screencast-screencast-producer) and (screencast-screencast-user)
;; Your own screencast files should have a (require 'screencast)
;;; Conventions:
;; PRODUCER : creates a screencast
;; USER : sees a screencast
;; producer sections in this document contains variables which the producer
;; should modify as need be, and functions to be called during the creation of a
;; screencast
;;; Change-log:
;; 1.0: core functionality
;; 1.1: PRODUCER ADDITIONS:
;; public variables which contain information about the current screencast
;; ability to change last-command and last-command-char
;; ability to use let and flet, while still outputting command descriptions
;; ability to create blinking sections to move the attention towards those
;; ability to show the region as if transient-mark-mode was on
;;
;; split the screencasts for the producer into a basic and an advanced
;; voice synthesizing of typed text. Requires festival to be installed.
;; global speed control
;; typed strings in screencasts can not contain tabs and newlines
;;; Code:
(defconst screencast-message-buffer-name "*Screencast Messages*"
"The name of the buffer to put messages from the screencast in")
(defconst screencast-version 1.1 "The version number of the screencast-mode")
(defconst screencast-speed-relation-speech-type 18.0
"When this is correctly adjusted, speech and typing should end
at the same time. Lower values means faster speech.")
;;;; BEGIN USER VARIABLES
(defvar screencast-use-message-buffer t "Should the message buffer be used at all?")
(defvar screencast-pause-length 2 "The length of a pause ('p) in the screencast")
(defvar screencast-pause-char-length 0.12
"The time between each typed character in the function `screencast-insert-with-delay'")
(defvar screencast-pause-command-length 3
"The time between the announcement of the function call, and the call itself.")
(defvar screencast-speech nil "If non-nil, slowly typed strings are read aloud")
(defvar screencast-speed 1.0 "How fast the screencast should be. Higher values equals higher speed. This can not be changed _during_ the screencast.")
;;;; BEGIN PRODUCER VARIABLES
;; these variables should be changed as needed by the producer
(defvar screencast-dont-print-list '(
progn
let
flet
save-excursion
save-window-excursion
i
screencast-producer-insert-with-delay
screencast-producer-set-last-command
screencast-producer-set-last-char
screencast-producer-new-buffer
screencast-producer-show-region
screencast-producer-blink-regions)
"A list of lists of function names which aren't printed as
being evaluated in the messages, this includes all producer
functions by default")
(defvar screencast-producer-blink-time 0.5
"The time a blink lasts.")
;; variables which can be read during run-time to obtain information about the
;; current screencast
(defvar screencast-producer-nopause nil
"Variable to be used for producer functions if they are using
pauses, they should deactivate the pause if this variable is non-nil.")
(defvar screencast-producer-command-buffer nil
"Variable to be used for producer functions if they are using
need the current command-buffer.")
(defvar screencast-producer-step-number 0
"Variable to be used for producer functions if they need to
know the current step number.
This is a _COPY_ of the value the screencast uses!")
(defvar screencast-producer-beginat 0
"Variable to be used for producer functions if they need to
know where the screencast is supposed to be using pauses at")
;;;; END PRODUCER VARIABLES
;;;; BEGIN MODE
(defvar screencast-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'screencast-goto-step)
map)
"Keymap for `screencast-mode'."
)
(define-derived-mode screencast-mode nil "screencast"
"Major mode for viewing screencasts."
(auto-fill-mode 1)
)
;;;; END MODE
;;;; BEGIN PRODUCER FUNCTIONS
(defun screencast-producer-insert-with-delay (string)
"Screencast producer function. _i_nserts STRING with a delay between each character.
See `screencast-insert-with-delay' for more details."
(let ((screencast-speech nil))
(screencast-insert-with-delay string screencast-producer-nopause)))
(defalias 'i 'screencast-producer-insert-with-delay
"Short name for `screencast-producer-insert-with-delay'.
This is chosen as it improves readability a lot in the screencast-source.")
(defun screencast-producer-set-last-command (f last)
"Sets the last-command to LAST before evaluating F.
Also prints the info about F, like it would have done normally."
(screencast-producer-show-command (car f))
(eval-with-last f last)
)
(defun eval-with-last (f last)
(eval (list 'progn
;; wtf? that's the only way it works (lines can be permuted!)
'(setq last-command last)
'(setq this-command last)
f)))
(defun screencast-producer-set-last-char (char f)
"Sets the last-command to CHAR before evaluating F.
Also prints the info about F, like it would have done normally."
(screencast-producer-show-command (car f))
(eval (list 'progn
'(setq last-command-char (string-to-char char))
f)))
(defun screencast-producer-show-command (command)
"Shows the COMMAND, and how it can be called in the message-buffer."
(pop-to-buffer (get-buffer screencast-message-buffer-name))
(screencast-show-command command
screencast-producer-step-number
screencast-producer-command-buffer)
(pop-to-buffer (get-buffer screencast-producer-command-buffer)))
(defun screencast-producer-new-buffer (list command-buffer-name)
"Screencast producer function. Creates an new screencast with
COMMAND-BUFFER-NAME as the command-buffer. The message-buffer
remains the same. Once the inner screencast ends, the original
command-buffer regains its status.
IMPORTANT:
You are responsible for killing the `COMMAND-BUFFER'
before the outermost screencast ends, otherwise you'll receive
the modified buffer the next time you run the outermost
screencast."
;; we want to start an 'inner screencast', but the current buffer is the
;; command-buffer, and the expected starting buffer is the
;; screencast-message-buffer
(if screencast-message-buffer
(pop-to-buffer (get-buffer screencast-message-buffer-name))
)
(screencast-internal list
(get-buffer command-buffer-name)
screencast-producer-beginat)
)
(defun screencast-producer-show-region (beg end)
"Marks the currently active region as if transient mark mode was on."
(unless screencast-producer-nopause
(let ((overlay (make-overlay beg end)))
(overlay-put overlay 'face (cons beg end))
;; unless there's a LOT of regions, the blinks will be synchronous
(run-with-timer screencast-pause-length nil 'delete-overlay overlay)
)
(sit-for screencast-pause-length)
)
)
(defun screencast-producer-blink-regions (regions)
"The REGIONS will blink.
A region is a pair: (beg . end)."
(unless screencast-producer-nopause
(dotimes (n 5)
(dolist (region regions)
(let ((overlay (make-overlay (car region) (cdr region))))
(overlay-put overlay 'face 'region)
;; unless there's a LOT of regions, the blinks will be synchronous
(run-with-timer screencast-producer-blink-time nil 'delete-overlay overlay))
)
(sit-for (* 2 screencast-producer-blink-time))
)))
;;;; END PRODUCER FUNCTIONS
;;;; BEGIN CORE
(defun make-region-clickable (beg end action &optional key)
"Makes the chosen region clickable, executing chosen action.
Default key is [mouse-1]."
(let ((map (make-sparse-keymap))
(keyc (if key
key
[mouse-1]))
)
(define-key map keyc action)
(put-text-property
beg
end
'keymap map))
)
(defun screencast-fontify-step-region ()
"Fontifies regions with step-references.
To be called immediately after functions which put step-numbers
in the message-buffer. Will fontify from the beginning of the
line with the step number to the end of the buffer."
(save-excursion
(goto-char (point-max))
(let ((beg (search-backward-regexp "^Step [[:digit:]]+:" (point-min))))
(screencast-put-shadow-and-make-clickable beg (point-max))
)))
(defun screencast-put-shadow-and-make-clickable (beg end)
"The region between BEG and END becomes shadowed and clickable.
`screencast-goto-step' is evalled when clicked"
(add-text-properties beg (- end 0)
(list
'face 'shadow
'mouse-face 'highlight
'help-echo "mouse-1: continue from this step"
))
(make-region-clickable beg (- end 0) 'screencast-goto-step))
(defun screencast-get-step ()
"Returns the step-number of a step-reference region.
If not in step-reference region, returns nil"
(if
;; check if we are at a step-reference region
(save-excursion
(goto-char (line-end-position))
(or
;; first line
(search-backward-regexp "^Step [[:digit:]]+:" (line-beginning-position) t)
;; second line
(search-backward-regexp "^ Callable with:" (line-beginning-position) t)))
;; get the step number
(save-excursion
(search-backward-regexp "^Step \\([[:digit:]]+\\):")
(let ((beg (match-beginning 1))
(end (match-end 1)))
(string-to-number
(buffer-substring-no-properties beg end))))
;; not in step-reference region
nil))
(defun repeat-string (s n)
(apply 'concat (make-list n s)))
(defun screencast-make-break (nopause)
(screencast-newline-only-once)
(newline)
(screencast-line)
(newline)
(screencast-pause-maybe nopause)
(screencast-pause-maybe nopause)
)
(defun screencast-pause-maybe (nopause &optional length)
"Pauses the program, unless NOPAUSE is non-nil.
If length is nil, a default pause LENGTH is used."
(unless nopause
(let ((l (if length
length
screencast-pause-length)))
(sit-for l))))
(defun n-first (n list)
"The n first elements of a list."
(loop for x in list repeat n collect x))
(defun buffer-recreate (buffer-name)
"Kills the buffer with BUFFER-NAME, and recreates it."
(let ((buffer (get-buffer buffer-name)))
(when buffer
(when (buffer-file-name buffer)
(save-excursion
(set-buffer buffer)
(unless (let ((start (substring-no-properties buffer-name 0 1)))
(or (string= start " ") (string= start "*")))
(save-buffer)))
(kill-buffer buffer-name)))
(get-buffer-create buffer-name))
)
(defun screencast-goto-step (&optional arg)
"Restarts the screencast at the chosen ARG step. Default is the first step."
(interactive "p")
(let ((step (if (not (= 1 arg))
arg
(screencast-get-step)))
;; bug? using (point), standing at point max gives nil values!
(list (get-text-property (point-min) 'screencast-list))
(name (get-text-property (point-min) 'screencast-command-buffer-name)))
;; (print step)
;; (print list)
;; (print name)
(screencast list name
-1 ; we just ran the screencast, so version should be no problem
(if step
(- step 1) ; the command just before!
0))
))
(defun screencast-newline-only-once ()
"Inserts a newline at point if, and only if the current line is nonempty."
(unless (= (line-beginning-position) (line-end-position))
(newline))
)
(defun screencast-make-region-clickable (beg end action &optional key)
"Makes the chosen region clickable, executing chosen action.
Default key is [mouse-1]."
(let ((map (make-sparse-keymap))
(keyc (if key
key
[mouse-1]))
)
(define-key map keyc action)
(put-text-property
beg
end
'keymap map))
)
(defun screencast-show-command (com step command-buffer)
"Inserts the STEP number and key-binding for a command, COM."
(screencast-newline-only-once)
(insert "Step " (number-to-string step) ": `" (symbol-name com) "'")
(newline)
(insert " Callable with: ")
(insert (where-is-return com command-buffer))
(screencast-fontify-step-region)
(newline)
)
(defun screencast-line (&optional length)
(let ((l (if length
length
25)))
(screencast-newline-only-once)
(insert (repeat-string "-" l))
(center-line)
(newline)
))
(defun screencast-header ()
(screencast-newline-only-once)
(newline)
(screencast-line 50)
(newline))
(defun screencast-speech-start (string nopause)
"Starts the speech-synthesizer with STRING, unless NOPAUSE is nonnil.
Also requires `screencast-speech' to be non-nil.
The speech speed depends on the typing speed (`screencast-speed-relation-speech-type')."
(when (and (not nopause) screencast-speech)
(let* ((duration (concat
"-b \"(Parameter.set 'Duration_Stretch "
(number-to-string (* screencast-pause-char-length
screencast-speed-relation-speech-type)) ")\""))
(tosay (replace-regexp-in-string "'" "'\"'\"'" string))
(say (concat "-b '(SayText \"" tosay "\")'"))
)
(save-window-excursion
(shell-command
(concat "festival " duration " " say "&"))
))))
(defun screencast-speech-wait-for (nopause)
"Blocks until the speech synthesizer is done speaking."
(when (and (not nopause) screencast-speech)
(shell-command "while [ `pgrep festival` ] ; do sleep 0.1; done;")
(sit-for 0.1)) ; needed
)
(defun screencast-insert-string-with-delay (string &optional nopause)
(let ((string (screencast-strip-newlines-and-normalize-whitespace string)))
(screencast-speech-start string nopause)
(let ((l (string-to-list string)))
(dolist (c l)
(insert c)
;; simple filling. If the char position equals fill-column. The
;; whole word is moved to the next line.
(when (and (= (- (line-end-position) (line-beginning-position)) fill-column))
(search-backward " ")
(insert "\n ") ; two space indentation as the previous space is moved too
(end-of-line) ; ?
)
(screencast-pause-maybe nopause screencast-pause-char-length)))
(screencast-speech-wait-for nopause)
)
)
(defun screencast-insert-with-delay (to-insert &optional nopause)
"Inserts STRINGS with a delay between each character.
If NOPAUSE is non-nil, the delay will be 0.
The pause between each character is given by `screencast-pause-char-length'."
(cond
((eq nil to-insert))
((symbolp to-insert)
(screencast-insert-special-symbol to-insert))
((stringp to-insert)
(screencast-insert-string-with-delay to-insert nopause))
((listp to-insert)
(progn
(screencast-insert-with-delay (car to-insert) nopause)
(screencast-insert-with-delay (cdr to-insert) nopause)
))
)
)
(defun screencast-strip-newlines-and-normalize-whitespace (string)
"Replaces all newlines and tabs in STRING by a single
whitespace, also collapses multiple whitespaces."
(replace-regexp-in-string "[ ]+" " " (replace-regexp-in-string "\n" " " string)))
(defalias 'screencast 'screencast-producer-screencast "Renaming for simplicity")
(defun screencast-producer-screencast (list command-buffer-name
version &optional beginat init)
"Prints and evaluates a list, LIST, of strings and functions in a tempo humans can follow.
The strings in LIST is printed to the screencast-message-buffer.
Functions are evaluated in the buffer named COMMAND-BUFFER-NAME.
VERSION is the version of screencast-mode the screencast is
written for, older versions of screencast-mode might not support
everything in newer screencasts.
The first BEGINAT elements of the list will be done without
delays.
INIT is a list of functions to be evaluated in the message-buffer
prior to the first message"
(when (> version screencast-version)
(error
(concat "The version of the screencast (" (number-to-string
version) ") is newer than the version of the screencast-mode
itself (" (number-to-string screencast-version) "). You might still be able
to run the screencast successfully though, just change the
screencasts version number to try it out.")))
;; preparations:
(let* (
;; speed adjustments
(screencast-pause-length (/ screencast-pause-length
screencast-speed))
(screencast-pause-char-length (/
screencast-pause-char-length
screencast-speed))
(screencast-pause-command-length (/
screencast-pause-command-length
screencast-speed))
;; buffers
(message-buffer (if screencast-use-message-buffer (buffer-recreate screencast-message-buffer-name)))
(command-buffer (if (or (not screencast-use-message-buffer)
(string= command-buffer-name
screencast-message-buffer-name)
message-buffer)
(buffer-recreate command-buffer-name)))
;; numbers
(screencast-step-number 0)
(beginat (if beginat
beginat
0)))
(delete-other-windows)
(if screencast-use-message-buffer
(progn (split-window-horizontally)
(switch-to-buffer message-buffer)
(pop-to-buffer message-buffer)
)
(switch-to-buffer command-buffer)
(pop-to-buffer command-buffer)
)
(display-buffer command-buffer)
(screencast-mode)
(toggle-read-only 0)
;; evaluate all the functions of init
(dolist (f init)
(eval f))
;; show
(screencast-internal list command-buffer beginat)
;; save the arguments in the buffer
(add-text-properties (point-min) (point-max)
(list 'screencast-list list
'screencast-command-buffer-name command-buffer-name))
(toggle-read-only 1)
)
)
(defun screencast-insert-special-symbol (c)
(cond
((eq 's c) ; step
(screencast-newline-only-once)
(insert "Step " (number-to-string screencast-step-number) ":")
(screencast-fontify-step-region)
)
((eq 'l c) ; line
(screencast-line))
((eq 'n c) ; newline
(newline))
((eq 'p c) ; pause
(screencast-pause-maybe nopause))
((eq 'b c) ; break
(screencast-make-break nopause)
)
(t
(error (concat "Screencast-internal encountered an error: Unknown symbol: " (symbol-name c)))))
)
(defun screencast-internal (list command-buffer beginat)
"The internal version of screencast, refer to the documentation string
there."
;; producer variables
(setq screencast-producer-command-buffer command-buffer)
(setq screencast-producer-beginat beginat)
;; make sure we are visiting the file in case it is needed (e.g. compile!)
(save-excursion
(set-buffer command-buffer)
(unless (buffer-file-name)
(set-visited-file-name (buffer-name))
))
;; for each element in the list
(dolist (c list)
(let ((nopause
(if (>= screencast-step-number beginat)
nil
t))
)
;; producer variables
(setq screencast-producer-nopause nopause)
(setq screencast-producer-step-number screencast-step-number)
(cond
((symbolp c)
;; special symbols
(if screencast-use-message-buffer
(screencast-insert-special-symbol c)
)
)
((listp c)
;; function
(progn
(unless (member (car c) screencast-dont-print-list) ; these need no print
(if screencast-use-message-buffer
(screencast-show-command (car c) screencast-step-number command-buffer)
)
)
(unless nopause
(screencast-pause-maybe nopause screencast-pause-command-length) ; pause
)
(if (member (car c) '(let flet))
(progn
;; we want the environment - but also to print the commands!
(eval (list (car c) ; the members above
(cadr c) ;the lets of flets
'(screencast-internal (cddr c) command-buffer beginat))) ;the rest
)
;; evaluate standard
(progn
;; save excursion style which allows for inner screencasts
(pop-to-buffer command-buffer)
(eval c)
(if screencast-use-message-buffer
(pop-to-buffer screencast-message-buffer-name)
)
)
)
(if screencast-use-message-buffer
(pop-to-buffer screencast-message-buffer-name) ; needed to regain real focus!
)
))
((stringp c)
;; it's a string - instert it.
(if screencast-use-message-buffer
(screencast-insert-with-delay c nopause)
))
(t
(error (concat "I don't know what to do with element:" c)))
)
(setq screencast-step-number (+ 1 screencast-step-number)) ; inc the step number
)
)
)
(defun where-is-return (definition buffer)
"A modification of where-is, which returns the message-string instead of printing it.
Also skips the removes name from the output.
BUFFER is the buffer to call where-is in."
(save-excursion
(set-buffer buffer)
(let ((func (indirect-function definition))
(defs nil)
(return-string ""))
;; In DEFS, find all symbols that are aliases for DEFINITION.
(mapatoms (lambda (symbol)
(and (fboundp symbol)
(not (eq symbol definition))
(eq func (condition-case ()
(indirect-function symbol)
(error symbol)))
(push symbol defs))))
;; Look at all the symbols--first DEFINITION,
;; then its aliases.
(dolist (symbol (cons definition defs))
(let* ((remapped (command-remapping symbol))
(keys (where-is-internal
symbol overriding-local-map nil nil remapped))
(keys (mapconcat 'key-description keys ", "))
string)
(setq string
(if t
(if (> (length keys) 0)
(if remapped
(format "%s (%s) (remapped from %s)"
keys remapped symbol)
(format "%s" keys))
(format "M-x %s RET" symbol))
(if (> (length keys) 0)
(if remapped
(format "%s is remapped to %s which is on %s"
symbol remapped keys)
(format "%s is on %s" symbol keys))
;; If this is the command the user asked about,
;; and it is not on any key, say so.
;; For other symbols, its aliases, say nothing
;; about them unless they are on keys.
(if (eq symbol definition)
(format "%s is not on any key" symbol)))))
(when string
(unless (eq symbol definition)
(setq return-string (concat return-string ";\n its alias "))) ;
(setq return-string (concat return-string string)))))
return-string)))
;;;; END CORE
;;;; BEGIN DOCUMENTATION
(defconst screencast-screencast-text-producer
'(
"Hello, this is the screencast for creating your own
screencasts." n
"If you create a list (first argument) of strings, each
string will be typed to the message buffer (this buffer), at
a human-readable pace." n
"If you put a 'p in the list, a pause will be inserted. " p
p p p p "See?" p p
l
"(The above line was inserted instantly with the symbol 'l)"
n
"(Blank lines can be inserted using the 'n symbol, newlines
in strings are removed)" n n n
"All of the above is combined in the symbol 'b, which creates
a break in the screencast. This could be used between two
different sections for instance." b
"You can also put functions in the list, these will be
evaluated in the command-buffer (second argument)." n
"The function is written as a list, with the function name
first, and the arguments after that, e.g. '(backward-char
2)." n n p
"Each time a function is evaluated, a message is displayed in
the message buffer, using the where-is function." n
"In addition to this a step-number is displayed, this
step-number corresponds to the functions position in the
list." n
"Let's try out some functions:" n
"((insert \"THIS IS AN INSERTION\n\") will be evaluated)" p
(insert "THIS IS AN INSERTION\n")
"You can call the special function `screencast-producer-insert-with-delay', aliased to `i' to insert with delay in the command-buffer."n
(i
"this is also an insertion, but it is done at typing speed")
"Hmm.." p p "let's delete the line we just typed in the
command buffer [[(kill-whole-line 1)]]"
(kill-whole-line 1)
"Notice the keybindings which are displayed." b
"The fourth (optional) argument given to the screencast
function is the step-number to start using pauses, and output
to the message buffer at, e.g. it is a fast-forward. Which is
_very_ nice when producing a screencast." n
"These step-numbers can also be printed separately in the
message-buffer using the 's symbol in the list." n s n
"See?" b
"Once you have finished a screencast and want it published,
you can record it as a video (.ogv) using
`screencast-record'."n
"As a part of the recording - the
font-size (`screencast-record-font') is changed, as well as
the fill-column variable (`screencast-record-fill-column')
for improved readability on a video."n
"As a consequence, you should _never_ use fill-paragraph and
the like, to get a nicely formatted source-file."n
"But the Emacs community will benefit the most if you publish
the screencast file itself - so please do!"n
"You can publish it at
http://www.emacswiki.org/emacs/ScreencastSources" b
"This screencast should cover the basic options for creating
a screencast, and can be seen in the constant
`screencast-screencast-text-producer'."n
"A screencast covering the more advanced functions of
screencast is available in the function
`screencast-screencast-producer-advanced'." b
"Happy screencasting!" )
"The text the screencast-screencast-producer is based upon")
(defconst screencast-screencast-text-user '(
"Hello, welcome to the screencast for viewing screencasts in
screencast mode."n
"Screencasts are like movies, they type some explanatory
text (like this), and executes functions in order to show you
the capabilities of different tools in Emacs."n
"Once a screencast has finished, you can move the cursor to
an executed function and press RET or MOUSE-1 to review the
screencast from that step."n
"Alternatively you can use the numeric prefix argument to
pinpoint the step to begin at."n
"If no prefix argument is given, and point isn't at an
executed function, the screencast is restarted from the first
step." ))
(defconst screencast-screencast-text-producer-advanced
'(
"This screencast covers the advanced functions of screencast-mode."n
"Please read the documentation for the functions as well."n
"Regarding the functions and variables in this file:"n
"You, as a producer, are supposed to be using the functions starting with `screencast-producer-' (and `screencast' itself ofcourse), they are tailored for ease of use. The others are for internal use - and there's no guarantee they are stable throughout versions."
b
"It is possible to use multiple command-buffers:"
(screencast-producer-new-buffer
'((i "I'm a new command-buffer"))
"new-command-buffer")
(progn (kill-buffer "new-command-buffer"))
"It is done via the function `screencast-producer-new-buffer' which takes a list and a buffer - almost like the screencast function itself. "
b
"If you don't want to document everything you do, for instance moving the cursor, you can put the functions you want to \"hide\" inside a `progn'."
b
"If you need temporary variables or functions (for instance when you need to override a function which uses the mini-buffer), you can just put in a `let' or `flet'"
b
"If you need to modify the last-command-char (for self-insert-commands) or the last-command (for continued killing) there's also support for that:"n
"Use `screencast-producer-set-last-char' or `screencast-producer-set-last-command'"
"The text the screencast-screencast-producer-advanced is based upon"))
(defun screencast-screencast-producer-advanced(&optional arg)
"Displays the screencast for creating advanced screencasts."
(interactive "P")
(apply (if arg
'screencast-record
'screencast)
screencast-screencast-text-producer-advanced "screencast-screencast-producer" 1.1 ()))
(defun screencast-screencast-producer(&optional arg)
"Displays the screencast for creating screencasts."
(interactive "P")
(apply (if arg
'screencast-record
'screencast)
screencast-screencast-text-producer "screencast-screencast-producer" 1 ()))
(defun screencast-screencast-user(&optional arg)
"Displays the screencast for using screencasts."
(interactive "P")
(apply (if arg
'screencast-record
'screencast)
screencast-screencast-text-user "screencast-screencast-user" 1 ()))
;;;; END DOCUMENTATION
(provide 'screencast)
;;; screencast.el ends here