emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/subed 3e99c6cb6f 22/22: Merge branch 'derived-mode' into m


From: ELPA Syncer
Subject: [nongnu] elpa/subed 3e99c6cb6f 22/22: Merge branch 'derived-mode' into main
Date: Tue, 1 Feb 2022 14:06:13 -0500 (EST)

branch: elpa/subed
commit 3e99c6cb6f8767c240a6b67abed8c034517e0ff0
Merge: f69c3e09f2 94c28993b7
Author: Sacha Chua <sacha@sachachua.com>
Commit: Sacha Chua <sacha@sachachua.com>

    Merge branch 'derived-mode' into main
---
 Makefile                   |   25 +-
 NEWS.org                   |   17 +
 README.org                 |   56 +-
 subed/subed-ass.el         |  359 +--
 subed/subed-autoloads.el   |  107 +
 subed/subed-common.el      |  395 ++-
 subed/subed-mpv.el         |   45 +-
 subed/subed-srt.el         |  418 +---
 subed/subed-vtt.el         |  396 +--
 subed/subed.el             |  150 +-
 tests/test-subed-ass.el    |  215 +-
 tests/test-subed-common.el | 5698 ++++++++++++++++++++++----------------------
 tests/test-subed-mpv.el    |    4 +-
 tests/test-subed-srt.el    | 2906 +++++++++++-----------
 tests/test-subed-vtt.el    |  534 +++--
 tests/undercover-init.el   |    4 +
 16 files changed, 5721 insertions(+), 5608 deletions(-)

diff --git a/Makefile b/Makefile
index 5b5873a80f..672406686f 100644
--- a/Makefile
+++ b/Makefile
@@ -4,17 +4,33 @@
 
 clean:
        find . -name "*.elc" -delete
+       rm -f coverage/.*.json
 
-test:
+test: test-coverage package-lint checkdoc
+
+test-coverage:
+       mkdir -p coverage
+       UNDERCOVER_FORCE=true emacs -batch -L . -f package-initialize -f 
buttercup-run-discover
+
+test-only:
        emacs -batch -f package-initialize -L . -f buttercup-run-discover
+
+package-lint:
        emacs --no-init-file -f package-initialize --batch \
                  --eval "(require 'package-lint)" \
              --file package-lint-batch-and-exit \
              ./subed/subed.el
+checkdoc:
        emacs --quick --batch --eval "(checkdoc-file \"subed/subed.el\")"
        emacs --quick --batch --eval "(checkdoc-file \"subed/subed-config.el\")"
        emacs --quick --batch --eval "(checkdoc-file \"subed/subed-mpv.el\")"
        emacs --quick --batch --eval "(checkdoc-file \"subed/subed-srt.el\")"
+       emacs --quick --batch --eval "(checkdoc-file \"subed/subed-vtt.el\")"
+       emacs --quick --batch --eval "(checkdoc-file \"subed/subed-ass.el\")"
+
+autoloads:
+       emacs --quick --batch --eval "(progn (setq generated-autoload-file 
(expand-file-name \"subed-autoloads.el\" \"subed\") backup-inhibited t) \
+       (update-directory-autoloads \"./subed\"))"
 
 test-compile:
        emacs --quick --batch --eval "(progn (add-to-list 'load-path 
(expand-file-name \"subed\" default-directory)) \
@@ -27,6 +43,13 @@ test-compile:
                                             (byte-compile-file 
\"subed/subed-mpv.el\"))"
        emacs --quick --batch --eval "(progn (add-to-list 'load-path 
(expand-file-name \"subed\" default-directory)) \
                                             (byte-compile-file 
\"subed/subed-srt.el\"))"
+       emacs --quick --batch --eval "(progn (add-to-list 'load-path 
(expand-file-name \"subed\" default-directory)) \
+                                            (byte-compile-file 
\"subed/subed-vtt.el\"))"
+       emacs --quick --batch --eval "(progn (add-to-list 'load-path 
(expand-file-name \"subed\" default-directory)) \
+                                            (byte-compile-file 
\"subed/subed-ass.el\"))"
        emacs --quick --batch --eval "(progn (add-to-list 'load-path 
(expand-file-name \"subed\" default-directory)) \
                                             (byte-compile-file 
\"subed/subed-debug.el\"))"
        make clean
+
+test-emacs:
+       emacs -Q -L ./subed --eval "(require 'subed)"
diff --git a/NEWS.org b/NEWS.org
new file mode 100644
index 0000000000..c82e5ff09f
--- /dev/null
+++ b/NEWS.org
@@ -0,0 +1,17 @@
+* subed news
+** Version 1.0.1 - 2022-02-01 - Sacha Chua
+
+Added obsolete function aliases in case people are calling
+format-specific functions in their code.
+
+** Version 1.0.0 - 2022-01-02 - Sacha Chua
+
+Format-specific modes are now initialized with =(subed-srt-mode)=,
+=(subed-vtt-mode)=, or =(subed-ass-mode)= instead of the corresponding
+=(subed-vtt--init)= functions.
+
+I implemented the format-specific functions with =cl-defmethod=, so if
+you have any code that refers to functions like
+=subed-vtt--timestamp-to-msecs=, you will need to change your code to
+use generic functions such as =subed-timestamp-to-msecs=.
+
diff --git a/README.org b/README.org
index 005b762d8c..5dc51c4016 100644
--- a/README.org
+++ b/README.org
@@ -10,6 +10,23 @@ corresponding video with [[https://mpv.io/][mpv]].  At the 
moment, the only supp
 SubRip ( ~.srt~), WebVTT ( ~.vtt~ ), and Advanced SubStation Alpha ( ~.ass~, 
experimental ).
 
 [[file:https://raw.githubusercontent.com/rndusr/subed/master/screenshot.jpg]]
+** Important change in v1.0.0
+
+~subed~ now uses ~subed-srt-mode~, ~subed-vtt-mode~, and
+~subed-ass-mode~ instead of directly using ~subed-mode~. These modes
+should be automatically associated with the ~.vtt~, ~.srt~, and ~.ass~
+extensions. If the generic ~subed-mode~ is loaded instead of the 
format-specific mode,
+you may get an error such as:
+
+#+begin_example
+Error in post-command-hook (subed--post-command-handler): 
(cl-no-applicable-method subed--subtitle-id)
+#+end_example
+
+If you set ~auto-mode-alist~ manually in your config, please make sure
+you associate extensions the appropriate format-specific mode instead
+of ~subed-mode~. The specific backend functions (ex:
+~subed-srt--jump-to-subtitle-id~) are also deprecated in favor of
+using generic functions such as ~subed-jump-to-subtitle-id~.
 
 ** Features
    - Quickly jump to next (~M-n~) and previous (~M-p~) subtitle text.
@@ -55,7 +72,7 @@ SubRip ( ~.srt~), WebVTT ( ~.vtt~ ), and Advanced SubStation 
Alpha ( ~.ass~, exp
      time is adjusted, and how much time to leave between subtitles.
 
 *** mpv integration (optional)
-   - Open videos with ~C-c C-v~ or automatically when entering subed-mode if 
the
+   - Open videos with ~C-c C-v~ or automatically when opening a subtitle file 
if the
      video file is named like the subtitle file but with a video extension
      (e.g. ~.mkv~ or ~.avi~).
    - Subtitles are automatically reloaded in mpv when the buffer is saved.
@@ -77,7 +94,7 @@ SubRip ( ~.srt~), WebVTT ( ~.vtt~ ), and Advanced SubStation 
Alpha ( ~.ass~, exp
      key is pressed).
 
 ** Installation
-
+*** Installing the subed package from NonGNU Elpa
 ~subed~ is now on [[https://elpa.nongnu.org/nongnu/subed.html][NonGNU ELPA]].  
On Emacs 28 and later, you can install it with ~M-x package-install~ ~subed~.
 
 To install it on Emacs 27 or earlier, add the following to your Emacs 
configuration file:
@@ -87,18 +104,36 @@ To install it on Emacs 27 or earlier, add the following to 
your Emacs configurat
 #+end_src
 
 Use ~M-x eval-buffer~ to run the code, and then use ~M-x package-install~ 
~subed~.
+*** Manual installation
 
-If that doesn't work, you can install it manually.  For example, copy 
~subed/*.el~ to
+If that doesn't work, you can install it manually. To install from the main 
branch:
 
-~$HOME/.emacs.d/elisp/~ and add ~$HOME/.emacs.d/elisp/~ to your ~load-path~.
+#+begin_src sh :eval no
+git clone https://github.com/sachac/subed.git
+#+end_src
 
-Here's some sample code for manual installation:
+This will create a =subed= directory with the code.  Then you can add
+the following to your Emacs configuration (typically
+=~/.config/emacs-init.el=, =~/.emacs.d/init.el=, or =~/.emacs=; you
+can create this file if it doesn't exist yet):
 
 #+begin_src emacs-lisp
-(add-to-list 'load-path "~/.emacs.d/elisp")
-(require 'subed)
+;; Note the reference to the subed subdirectory
+(add-to-list 'load-path "/path/to/subed/subed")
+(require 'subed-autoloads)
 #+end_src
 
+and reload your configuration with =M-x eval-buffer= or restart Emacs.
+
+If you want to try a branch (ex: =derived-mode=), you can use the
+following command inside the =subed= directory:
+
+#+begin_src sh :eval no
+git checkout branchname
+#+end_src
+
+*** use-package configuration
+
 Here's an example setup if you use use-package:
 
 #+BEGIN_SRC emacs-lisp
@@ -115,7 +150,12 @@ Here's an example setup if you use use-package:
   (add-hook 'subed-mode-hook (lambda () (setq-local fill-column 40))))
 #+END_SRC
 
-~C-h f subed-mode~ should get you started.
+** Getting started
+
+~C-h f subed-mode~ should get you started. This is the parent mode for
+~subed-srt-mode~, ~subed-vtt-mode~, and ~subed-ass-mode~. When
+manually loading a mode, use those specific format modes instead of
+~subed-mode~.
 
 ** Contributions
    Contributions would be really appreciated! subed conforms to the 
[[https://reuse.software/spec/][REUSE
diff --git a/subed/subed-ass.el b/subed/subed-ass.el
index b2b0d9372d..15b4e9e5b6 100644
--- a/subed/subed-ass.el
+++ b/subed/subed-ass.el
@@ -27,6 +27,7 @@
 
 ;;; Code:
 
+(require 'subed)
 (require 'subed-config)
 (require 'subed-debug)
 (require 'subed-common)
@@ -47,11 +48,12 @@
 (defconst subed-ass--regexp-start 
"\\(?:Dialogue\\|Comment\\|Picture\\|Sound\\|Movie\\|Command\\): [0-9]+,")
 (defconst subed-ass--regexp-separator "\n")
 
-(defun subed-ass--timestamp-to-msecs (time-string)
+(cl-defmethod subed--timestamp-to-msecs (time-string &context (major-mode 
subed-ass-mode))
   "Find HH:MM:SS.MS pattern in TIME-STRING and convert it to milliseconds.
-Return nil if TIME-STRING doesn't match the pattern."
+Return nil if TIME-STRING doesn't match the pattern.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (string-match subed-ass--regexp-timestamp time-string)
+    (when (string-match subed--regexp-timestamp time-string)
       (let ((hours (string-to-number (or (match-string 2 time-string) "0")))
             (mins  (string-to-number (match-string 3 time-string)))
             (secs  (string-to-number (match-string 4 time-string)))
@@ -61,29 +63,26 @@ Return nil if TIME-STRING doesn't match the pattern."
            (* (truncate secs) 1000)
            (truncate msecs))))))
 
-(defun subed-ass--msecs-to-timestamp (msecs)
-  "Convert MSECS to string in the format H:MM:SS.CS."
+(cl-defmethod subed--msecs-to-timestamp (msecs &context (major-mode 
subed-ass-mode))
+  "Convert MSECS to string in the format H:MM:SS.CS.
+Use the format-specific function for MAJOR-MODE."
   ;; We need to wrap format-seconds in save-match-data because it does regexp
   ;; stuff and we need to preserve our own match-data.
   (concat (save-match-data (format-seconds "%h:%02m:%02s" (/ msecs 1000)))
           "." (format "%02d" (/ (mod msecs 1000) 10))))
 
-(defun subed-ass--subtitle-id ()
-  "Return the ID of the subtitle at point or nil if there is no ID."
+(cl-defmethod subed--subtitle-id (&context (major-mode subed-ass-mode))
+  "Return the ID of the subtitle at point or nil if there is no ID.
+Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (when (subed-ass--jump-to-subtitle-id)
-      (when (looking-at subed-ass--regexp-timestamp)
-        (match-string 0)))))
+    (when (and (subed--jump-to-subtitle-time-start)
+               (looking-at subed--regexp-timestamp))
+      (match-string 0))))
 
-(defun subed-ass--subtitle-id-max ()
-  "Return the ID of the last subtitle or nil if there are no subtitles."
-  (save-excursion
-    (goto-char (point-max))
-    (subed-ass--subtitle-id)))
-
-(defun subed-ass--subtitle-id-at-msecs (msecs)
+(cl-defmethod subed--subtitle-id-at-msecs (msecs &context (major-mode 
subed-ass-mode))
   "Return the ID of the subtitle at MSECS milliseconds.
-Return nil if there is no subtitle at MSECS."
+Return nil if there is no subtitle at MSECS.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (save-excursion
       (goto-char (point-min))
@@ -91,76 +90,38 @@ Return nil if there is no subtitle at MSECS."
              (only-hours (truncate (/ secs 3600)))
              (only-mins  (truncate (/ (- secs (* only-hours 3600)) 60))))
         ;; Move to first subtitle in the relevant hour
-        (when (re-search-forward (format "\\(%s\\|\\`\\)%02d:" 
subed-ass--regexp-separator only-hours) nil t)
+        (when (re-search-forward (format "\\(%s\\|\\`\\)%02d:" 
subed--regexp-separator only-hours) nil t)
           (beginning-of-line)
           ;; Move to first subtitle in the relevant hour and minute
           (re-search-forward (format "\\(\n\n\\|\\`\\)%02d:%02d" only-hours 
only-mins) nil t)))
       ;; Move to first subtitle that starts at or after MSECS
       (catch 'subtitle-id
-        (while (<= (or (subed-ass--subtitle-msecs-start) -1) msecs)
+        (while (<= (or (subed-subtitle-msecs-start) -1) msecs)
           ;; If stop time is >= MSECS, we found a match
-          (let ((cur-sub-end (subed-ass--subtitle-msecs-stop)))
+          (let ((cur-sub-end (subed-subtitle-msecs-stop)))
             (when (and cur-sub-end (>= cur-sub-end msecs))
-              (throw 'subtitle-id (subed-ass--subtitle-id))))
-          (unless (subed-ass--forward-subtitle-id)
+              (throw 'subtitle-id (subed-subtitle-id))))
+          (unless (subed--forward-subtitle-id)
             (throw 'subtitle-id nil)))))))
 
-(defun subed-ass--subtitle-msecs-start (&optional sub-id)
-  "Subtitle start time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-ass--jump-to-subtitle-time-start sub-id)
-                       (when (looking-at subed-ass--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-ass--timestamp-to-msecs timestamp))))
-
-(defun subed-ass--subtitle-msecs-stop (&optional sub-id)
-  "Subtitle stop time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-ass--jump-to-subtitle-time-stop sub-id)
-                       (when (looking-at subed-ass--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-ass--timestamp-to-msecs timestamp))))
-
-(defun subed-ass--subtitle-text (&optional sub-id)
-  "Return subtitle's text or an empty string.
-If SUB-ID is not given, use subtitle on point."
-  (or (save-excursion
-        (let ((beg (subed-ass--jump-to-subtitle-text sub-id))
-              (end (subed-ass--jump-to-subtitle-end sub-id)))
-          (when (and beg end)
-            (buffer-substring beg end))))
-      ""))
-
-(defun subed-ass--subtitle-relative-point ()
-  "Point relative to subtitle's ID or nil if ID can't be found."
-  (let ((start-point (save-excursion
-                       (when (subed-ass--jump-to-subtitle-id)
-                         (point)))))
-    (when start-point
-      (- (point) start-point))))
-
 ;;; Traversing
 
-(defun subed-ass--jump-to-subtitle-id (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-id (&context (major-mode subed-ass-mode) 
&optional sub-id)
   "Move to the ID of a subtitle and return point.
 If SUB-ID is not given, focus the current subtitle's ID.
 Return point or nil if no subtitle ID could be found.
-ASS doesn't use IDs, so we use the starting timestamp instead."
-  (interactive)
+ASS doesn't use IDs, so we use the starting timestamp instead.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (if (stringp sub-id)
         (let* ((orig-point (point))
-               (find-ms (subed-ass--timestamp-to-msecs sub-id))
-               (regex (concat "^\\(?:" subed-ass--regexp-start "\\)\\(" 
subed-ass--regexp-timestamp "\\)"))
+               (find-ms (subed--timestamp-to-msecs sub-id))
+               (regex (concat "^\\(?:" subed-ass--regexp-start "\\)\\(" 
subed--regexp-timestamp "\\)"))
                done)
           (goto-char (point-min))
           (while (not done)
             (if (re-search-forward regex nil t)
-                (when (= (subed-ass--timestamp-to-msecs (match-string 1)) 
find-ms)
+                (when (= (subed-timestamp-to-msecs (match-string 1)) find-ms)
                   (setq done 'found)
                   (goto-char (match-beginning 1)))
               (setq done 'not-found)
@@ -169,78 +130,61 @@ ASS doesn't use IDs, so we use the starting timestamp 
instead."
             (beginning-of-line)
             (point)))
       (end-of-line)
-      (let* ((regex (concat "^\\(?:" subed-ass--regexp-start "\\)\\(" 
subed-ass--regexp-timestamp "\\)"))
+      (let* ((regex (concat "^\\(?:" subed-ass--regexp-start "\\)\\(" 
subed--regexp-timestamp "\\)"))
              (match-found (re-search-backward regex nil t)))
-        (when (or match-found (re-search-forward regex nil t))           ;; 
maybe at the beginning?
+        (when (or match-found (re-search-forward regex nil t)) ;; maybe at the 
beginning?
           (goto-char (match-beginning 0))
           (point))))))
 
-(defun subed-ass--jump-to-subtitle-id-at-msecs (msecs)
-  "Move point to the ID of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-ass--subtitle-id-at-msecs'."
-  (let ((current-sub-id (subed-ass--subtitle-id))
-        (target-sub-id (subed-ass--subtitle-id-at-msecs msecs)))
-    (when (and target-sub-id current-sub-id (not (equal target-sub-id 
current-sub-id)))
-      (subed-ass--jump-to-subtitle-id target-sub-id))))
-
-(defun subed-ass--jump-to-subtitle-text-at-msecs (msecs)
-  "Move point to the text of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-ass--subtitle-id-at-msecs'."
-  (when (subed-ass--jump-to-subtitle-id-at-msecs msecs)
-    (subed-ass--jump-to-subtitle-text)))
-
-(defun subed-ass--jump-to-subtitle-time-start (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-start (&context (major-mode 
subed-ass-mode) &optional sub-id)
   "Move point to subtitle's start time.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if no start time could be found."
-  (interactive)
+Return point or nil if no start time could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (subed-ass--jump-to-subtitle-id sub-id)
-      (when (re-search-forward subed-ass--regexp-timestamp (line-end-position) 
t)
+    (when (subed-jump-to-subtitle-id sub-id)
+      (when (re-search-forward subed--regexp-timestamp (line-end-position) t)
         (goto-char (match-beginning 0))
         (point)))))
 
-(defun subed-ass--jump-to-subtitle-time-stop (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-stop (&context (major-mode 
subed-ass-mode) &optional sub-id)
   "Move point to subtitle's stop time.
-If SUB-ID is not given, use subtitle on point.
-Return point or nil if no stop time could be found."
-  (interactive)
+If SUB-ID is not given, use subtitle on point.  Return point or
+nil if no stop time could be found.  Use the format-specific
+function for MAJOR-MODE."
   (save-match-data
-    (when (subed-ass--jump-to-subtitle-id sub-id)
-      (re-search-forward (concat "\\(?:" subed-ass--regexp-timestamp "\\),") 
(point-at-eol) t)
-      (when (looking-at subed-ass--regexp-timestamp)
+    (when (subed-jump-to-subtitle-id sub-id)
+      (re-search-forward (concat "\\(?:" subed--regexp-timestamp "\\),") 
(point-at-eol) t)
+      (when (looking-at subed--regexp-timestamp)
         (point)))))
 
-(defun subed-ass--jump-to-subtitle-text (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-text (&context (major-mode 
subed-ass-mode) &optional sub-id)
   "Move point on the first character of subtitle's text.
-If SUB-ID is not given, use subtitle on point.
-Return point or nil if a the subtitle's text can't be found."
-  (interactive)
-  (when (subed-ass--jump-to-subtitle-id sub-id)
+If SUB-ID is not given, use subtitle on point.  Return point or
+nil if a the subtitle's text can't be found.  Use the
+format-specific function for MAJOR-MODE."
+  (when (subed-jump-to-subtitle-id sub-id)
     (beginning-of-line)
     (when (looking-at ".*?,.*?,.*?,.*?,.*?,.*?,.*?,.*?,.*?,")
       (goto-char (match-end 0)))
     (point)))
 
-(defun subed-ass--jump-to-subtitle-end (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-end (&context (major-mode 
subed-ass-mode) &optional sub-id)
   "Move point after the last character of the subtitle's text.
-If SUB-ID is not given, use subtitle on point.
-Return point or nil if point did not change or if no subtitle end
-can be found."
-  (interactive)
+If SUB-ID is not given, use subtitle on point.  Return point or
+nil if point did not change or if no subtitle end can be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (let ((orig-point (point)))
-      (when (subed-ass--jump-to-subtitle-text sub-id)
+      (when (subed-jump-to-subtitle-text sub-id)
         (end-of-line)
         (unless (= orig-point (point))
           (point))))))
 
-(defun subed-ass--forward-subtitle-id ()
+(cl-defmethod subed--forward-subtitle-id (&context (major-mode subed-ass-mode))
   "Move point to next subtitle's ID.
-Return point or nil if there is no next subtitle."
-  (interactive)
+Return point or nil if there is no next subtitle.  Use the
+format-specific function for MAJOR-MODE."
   (save-match-data
     (let ((pos (point)))
       (forward-line 1)
@@ -252,12 +196,12 @@ Return point or nil if there is no next subtitle."
         (goto-char pos)
         nil))))
 
-(defun subed-ass--backward-subtitle-id ()
+(cl-defmethod subed--backward-subtitle-id (&context (major-mode 
subed-ass-mode))
   "Move point to previous subtitle's ID.
-Return point or nil if there is no previous subtitle."
-  (interactive)
+Return point or nil if there is no previous subtitle.  Use the
+format-specific function for MAJOR-MODE."
   (let ((orig-point (point)))
-    (when (subed-ass--jump-to-subtitle-id)
+    (when (subed-jump-to-subtitle-id)
       (forward-line -1)
       (while (not (or (bobp) (looking-at subed-ass--regexp-start)))
         (forward-line -1))
@@ -266,87 +210,9 @@ Return point or nil if there is no previous subtitle."
         (goto-char orig-point)
         nil))))
 
-(defun subed-ass--forward-subtitle-text ()
-  "Move point to next subtitle's text.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-ass--forward-subtitle-id)
-    (subed-ass--jump-to-subtitle-text)))
-
-(defun subed-ass--backward-subtitle-text ()
-  "Move point to previous subtitle's text.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-ass--backward-subtitle-id)
-    (subed-ass--jump-to-subtitle-text)))
-
-(defun subed-ass--forward-subtitle-end ()
-  "Move point to end of next subtitle.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-ass--forward-subtitle-id)
-    (subed-ass--jump-to-subtitle-end)))
-
-(defun subed-ass--backward-subtitle-end ()
-  "Move point to end of previous subtitle.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-ass--backward-subtitle-id)
-    (subed-ass--jump-to-subtitle-end)))
-
-(defun subed-ass--forward-subtitle-time-start ()
-  "Move point to next subtitle's start time."
-  (interactive)
-  (when (subed-ass--forward-subtitle-id)
-    (subed-ass--jump-to-subtitle-time-start)))
-
-(defun subed-ass--backward-subtitle-time-start ()
-  "Move point to previous subtitle's start time."
-  (interactive)
-  (when (subed-ass--backward-subtitle-id)
-    (subed-ass--jump-to-subtitle-time-start)))
-
-(defun subed-ass--forward-subtitle-time-stop ()
-  "Move point to next subtitle's stop time."
-  (interactive)
-  (when (subed-ass--forward-subtitle-id)
-    (subed-ass--jump-to-subtitle-time-stop)))
-
-(defun subed-ass--backward-subtitle-time-stop ()
-  "Move point to previous subtitle's stop time."
-  (interactive)
-  (when (subed-ass--backward-subtitle-id)
-    (subed-ass--jump-to-subtitle-time-stop)))
-
 ;;; Manipulation
 
-(defun subed-ass--set-subtitle-time-start (msecs &optional sub-id)
-  "Set subtitle start time to MSECS milliseconds.
-
-If SUB-ID is not given, set the start of the current subtitle.
-
-Return the new subtitle start time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-ass--jump-to-subtitle-id sub-id)))
-      (subed-ass--jump-to-subtitle-time-start)
-      (when (looking-at subed-ass--regexp-timestamp)
-        (replace-match (subed-ass--msecs-to-timestamp msecs))))))
-
-(defun subed-ass--set-subtitle-time-stop (msecs &optional sub-id)
-  "Set subtitle stop time to MSECS milliseconds.
-
-If SUB-ID is not given, set the stop of the current subtitle.
-
-Return the new subtitle stop time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-ass--jump-to-subtitle-id sub-id)))
-      (subed-ass--jump-to-subtitle-time-stop)
-      (when (looking-at subed-ass--regexp-timestamp)
-        (replace-match (subed-ass--msecs-to-timestamp msecs))))))
-
-(defun subed-ass--make-subtitle (&optional id start stop text)
+(cl-defmethod subed--make-subtitle (&context (major-mode subed-ass-mode) 
&optional id start stop text)
   "Generate new subtitle string.
 
 ID, START default to 0.
@@ -354,108 +220,73 @@ STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
 A newline is appended to TEXT, meaning you'll get two trailing
-newlines if TEXT is nil or empty."
-  (interactive "P")
+newlines if TEXT is nil or empty.  Use the format-specific
+function for MAJOR-MODE."
   (format "Dialogue: 0,%s,%s,Default,,0,0,0,,%s\n"
-          (subed-ass--msecs-to-timestamp (or start 0))
-          (subed-ass--msecs-to-timestamp (or stop (+ (or start 0)
+          (subed-msecs-to-timestamp (or start 0))
+          (subed-msecs-to-timestamp (or stop (+ (or start 0)
                                                      
subed-default-subtitle-length)))
           (replace-regexp-in-string "\n" "\\n" (or text ""))))
 
-(defun subed-ass--prepend-subtitle (&optional id start stop text)
+(cl-defmethod subed--prepend-subtitle (&context (major-mode subed-ass-mode) 
&optional id start stop text)
   "Insert new subtitle before the subtitle at point.
 
 ID and START default to 0.
 STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
-Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (subed-ass--jump-to-subtitle-id)
-  (insert (subed-ass--make-subtitle id start stop text))
+Move point to the text of the inserted subtitle.  Return new
+point.  Use the format-specific function for MAJOR-MODE."
+  (subed-jump-to-subtitle-id)
+  (insert (subed-make-subtitle id start stop text))
   (forward-line -1)
-  (subed-ass--jump-to-subtitle-text))
+  (subed-jump-to-subtitle-text))
 
-(defun subed-ass--append-subtitle (&optional id start stop text)
+(cl-defmethod subed--append-subtitle (&context (major-mode subed-ass-mode) 
&optional id start stop text)
   "Insert new subtitle after the subtitle at point.
 
 ID, START default to 0.
 STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
-Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (unless (subed-ass--forward-subtitle-id)
+Move point to the text of the inserted subtitle.  Return new
+point.  Use the format-specific function for MAJOR-MODE."
+  (unless (subed-forward-subtitle-id)
     ;; Point is on last subtitle or buffer is empty
-    (subed-ass--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     (unless (bolp) (insert "\n")))
-  (insert (subed-ass--make-subtitle id start stop text))
+  (insert (subed-make-subtitle id start stop text))
   (forward-line -1)
-  (subed-ass--jump-to-subtitle-text))
-
-(defun subed-ass--kill-subtitle ()
-  "Remove subtitle at point."
-  (interactive)
-  (let ((beg (save-excursion (subed-ass--jump-to-subtitle-id)
-                             (point)))
-        (end (save-excursion (subed-ass--jump-to-subtitle-id)
-                             (when (subed-ass--forward-subtitle-id)
-                               (point)))))
-    (if (not end)
-        ;; Removing the last subtitle because forward-subtitle-id returned nil
-        (setq beg (save-excursion (goto-char beg)
-                                  (subed-ass--backward-subtitle-end)
-                                  (1+ (point)))
-              end (save-excursion (goto-char (point-max)))))
-    (delete-region beg end)))
-
-(defun subed-ass--merge-with-next ()
+  (subed-jump-to-subtitle-text))
+
+(cl-defmethod subed--merge-with-next (&context (major-mode subed-ass-mode))
   "Merge the current subtitle with the next subtitle.
-Update the end timestamp accordingly."
-  (interactive)
+Update the end timestamp accordingly.  Use the format-specific
+function for MAJOR-MODE."
   (save-excursion
-    (subed-ass--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     (let ((pos (point)) new-end)
-      (if (subed-ass--forward-subtitle-time-stop)
+      (if (subed-forward-subtitle-time-stop)
           (progn
-            (when (looking-at subed-ass--regexp-timestamp)
-              (setq new-end (subed-ass--timestamp-to-msecs (match-string 0))))
-            (subed-ass--jump-to-subtitle-text)
+            (when (looking-at subed--regexp-timestamp)
+              (setq new-end (subed-timestamp-to-msecs (match-string 0))))
+            (subed-jump-to-subtitle-text)
             (delete-region pos (point))
             (insert " ")
-            (subed-ass--set-subtitle-time-stop new-end))
+            (subed-set-subtitle-time-stop new-end))
         (error "No subtitle to merge into")))))
 
 
-;;; Maintenance
-
-(defun subed-ass--regenerate-ids ()
-  "Not applicable to ASS."
-  (interactive))
-
-(defvar-local subed-ass--regenerate-ids-soon-timer nil)
-(defun subed-ass--regenerate-ids-soon ()
-  "Not applicable to ASS."
-  (interactive))
-
-(defun subed-ass--sanitize ()
-  "Not yet implemented."
-  (interactive))
-
-(defun subed-ass--validate ()
-  "Not yet implemented."
-  (interactive))
-
-(defun subed-ass--sort ()
-  "Not yet implemented."
-  (interactive))
-
-(defun subed-ass--init ()
-  "This function is called when subed-mode is entered for a ASS file."
+;;;###autoload
+(define-derived-mode subed-ass-mode subed-mode "Subed-ASS"
+  "Major mode for editing Advanced SubStation Alpha subtitle files."
   (setq-local subed--subtitle-format "ass")
+  (setq-local subed--regexp-timestamp subed-ass--regexp-timestamp)
+  (setq-local subed--regexp-separator subed-ass--regexp-separator)
   (setq-local font-lock-defaults '(subed-ass-font-lock-keywords)))
 
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.ass\\'" . subed-ass-mode))
+
 (provide 'subed-ass)
 ;;; subed-ass.el ends here
diff --git a/subed/subed-autoloads.el b/subed/subed-autoloads.el
new file mode 100644
index 0000000000..de47cade7e
--- /dev/null
+++ b/subed/subed-autoloads.el
@@ -0,0 +1,107 @@
+;;; subed-autoloads.el --- automatically extracted autoloads  -*- 
lexical-binding: t -*-
+;;
+;;; Code:
+
+
+;;;### (autoloads nil "subed" "subed.el" (0 0 0 0))
+;;; Generated autoloads from subed.el
+
+(autoload 'subed-mode "subed" "\
+Major mode for editing subtitles.
+
+subed uses the following terminology when it comes to changes in
+subtitles' timestamps:
+
+Adjust - Increase or decrease start or stop time of a subtitle
+  Move - Increase or decrease start and stop time of a subtitle
+         by the same amount
+ Shift - Increase or decrease start and stop time of the current
+         and all following subtitles by the same amount
+
+Key bindings:
+\\{subed-mode-map}
+
+\(fn)" t nil)
+
+(register-definition-prefixes "subed" '("subed-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-ass" "subed-ass.el" (0 0 0 0))
+;;; Generated autoloads from subed-ass.el
+
+(autoload 'subed-ass-mode "subed-ass" "\
+Major mode for editing Advanced SubStation Alpha subtitle files.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.ass\\'" . subed-ass-mode))
+
+(register-definition-prefixes "subed-ass" '("subed-ass-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-common" "subed-common.el" (0 0 0 0))
+;;; Generated autoloads from subed-common.el
+
+(register-definition-prefixes "subed-common" '("subed-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-config" "subed-config.el" (0 0 0 0))
+;;; Generated autoloads from subed-config.el
+
+(register-definition-prefixes "subed-config" '("subed-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-debug" "subed-debug.el" (0 0 0 0))
+;;; Generated autoloads from subed-debug.el
+
+(register-definition-prefixes "subed-debug" '("subed-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-mpv" "subed-mpv.el" (0 0 0 0))
+;;; Generated autoloads from subed-mpv.el
+
+(register-definition-prefixes "subed-mpv" '("subed-mpv-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-srt" "subed-srt.el" (0 0 0 0))
+;;; Generated autoloads from subed-srt.el
+
+(autoload 'subed-srt-mode "subed-srt" "\
+Major mode for editing SubRip subtitle files.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.srt\\'" . subed-srt-mode))
+
+(register-definition-prefixes "subed-srt" '("subed-srt-"))
+
+;;;***
+
+;;;### (autoloads nil "subed-vtt" "subed-vtt.el" (0 0 0 0))
+;;; Generated autoloads from subed-vtt.el
+
+(autoload 'subed-vtt-mode "subed-vtt" "\
+Major mode for editing WebVTT subtitle files.
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.vtt\\'" . subed-vtt-mode))
+
+(register-definition-prefixes "subed-vtt" '("subed-vtt-"))
+
+;;;***
+
+(provide 'subed-autoloads)
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; subed-autoloads.el ends here
diff --git a/subed/subed-common.el b/subed/subed-common.el
index f6d1891342..8896900d19 100644
--- a/subed/subed-common.el
+++ b/subed/subed-common.el
@@ -33,14 +33,337 @@
 (require 'subed-mpv)
 
 
-;;; Utilities
+;;; Generic functions
+
+
+(defvar-local subed--regexp-separator nil "Regexp separating subtitles.")
+(defvar-local subed--regexp-timestamp nil "Regexp matching timestamps.")
+
+(defmacro subed-define-generic-function (name args &rest body)
+  "Declare an object method and provide the old way of calling it.
+NAME is the part of the function name that will go after the
+subed- prefix.  ARGS are the arguments for the function.  BODY is
+the body of the function, and may include a docstring or an
+interactive form."
+  (declare
+   (indent defun)
+   (debug defun))
+  (let (is-interactive
+        doc)
+    (when (stringp (car body))
+      (setq doc (pop body)))
+    (setq is-interactive (eq (caar body) 'interactive))
+    `(progn
+       (cl-defgeneric ,(intern (concat "subed--" (symbol-name name)))
+           ,args
+         ,doc
+         ,@(if is-interactive
+               (cdr body)
+             body))
+       ;; Define old internal functions as obsolete aliases
+       ,@(mapcar (lambda (sub-format)
+                   `(define-obsolete-function-alias
+                      (quote ,(intern (format "subed-%s--%s" sub-format 
(symbol-name name))))
+                      (function ,(intern (format "subed-%s" (symbol-name 
name))))
+                      "1.0.0"
+                      ,doc))
+                 '("srt" "vtt" "ass"))
+       ,(if is-interactive
+            `(defun ,(intern (concat "subed-" (symbol-name name))) ,args
+               ,(concat doc "\n\nThis function calls the generic function `"
+                        (concat "subed--" (symbol-name name)) "' for the 
actual implementation.")
+               ,(car body)
+               (,(intern (concat "subed--" (symbol-name name)))
+                ,@(delq nil (mapcar (lambda (a)
+                                      (unless (string-match "^&" (symbol-name 
a))
+                                        a))
+                                    args))))
+          `(defalias ',(intern (concat "subed-" (symbol-name name)))
+             #',(intern (concat "subed--" (symbol-name name)))
+             ,doc)))))
+
+(subed-define-generic-function timestamp-to-msecs (time-string)
+  "Find timestamp pattern in TIME-STRING and convert it to milliseconds.
+Return nil if TIME-STRING doesn't match the pattern.")
+
+(subed-define-generic-function msecs-to-timestamp (msecs)
+  "Convert MSECS to string in the subtitle's timestamp format.")
+
+(subed-define-generic-function subtitle-id ()
+  "Return the ID of the subtitle at point or nil if there is no ID.")
+
+(subed-define-generic-function subtitle-id-max ()
+  "Return the ID of the last subtitle or nil if there are no subtitles."
+  (save-excursion
+    (goto-char (point-max))
+    (subed-subtitle-id)))
+
+(subed-define-generic-function subtitle-id-at-msecs (msecs)
+  "Return the ID of the subtitle at MSECS milliseconds.
+Return nil if there is no subtitle at MSECS.")
+
+(subed-define-generic-function jump-to-subtitle-id (&optional sub-id)
+  "Move to the ID of a subtitle and return point.
+If SUB-ID is not given, focus the current subtitle's ID.
+Return point or nil if no subtitle ID could be found."
+  (interactive))
+
+(subed-define-generic-function jump-to-subtitle-time-start (&optional sub-id)
+  "Move point to subtitle's start time.
+If SUB-ID is not given, use subtitle on point.
+Return point or nil if no start time could be found."
+  (interactive))
+
+(subed-define-generic-function jump-to-subtitle-time-stop (&optional sub-id)
+  "Move point to subtitle's stop time.
+If SUB-ID is not given, use subtitle on point.
+Return point or nil if no stop time could be found."
+  (interactive))
+
+(subed-define-generic-function jump-to-subtitle-text (&optional sub-id)
+  "Move point on the first character of subtitle's text.
+If SUB-ID is not given, use subtitle on point.
+Return point or nil if a the subtitle's text can't be found."
+  (interactive))
+
+(subed-define-generic-function jump-to-subtitle-end (&optional sub-id)
+  "Move point after the last character of the subtitle's text.
+If SUB-ID is not given, use subtitle on point.
+Return point or nil if point did not change or if no subtitle end
+can be found."
+  (interactive))
+
+(subed-define-generic-function jump-to-subtitle-id-at-msecs (msecs)
+  "Move point to the ID of the subtitle that is playing at MSECS.
+Return point or nil if point is still on the same subtitle.
+See also `subed-subtitle-id-at-msecs'."
+  (let ((current-sub-id (subed-subtitle-id))
+        (target-sub-id (subed-subtitle-id-at-msecs msecs)))
+    (when (and target-sub-id current-sub-id (not (equal target-sub-id 
current-sub-id)))
+      (subed-jump-to-subtitle-id target-sub-id))))
+
+(subed-define-generic-function jump-to-subtitle-text-at-msecs (msecs)
+  "Move point to the text of the subtitle that is playing at MSECS.
+Return point or nil if point is still on the same subtitle.
+See also `subed-vtt--subtitle-id-at-msecs'."
+  (when (subed-jump-to-subtitle-id-at-msecs msecs)
+    (subed-jump-to-subtitle-text)))
+
+(subed-define-generic-function forward-subtitle-id ()
+  "Move point to next subtitle's ID.
+Return point or nil if there is no next subtitle."
+  (interactive))
+
+(subed-define-generic-function backward-subtitle-id ()
+  "Move point to previous subtitle's ID.
+Return point or nil if there is no previous subtitle."
+  (interactive))
+
+(subed-define-generic-function forward-subtitle-text ()
+  "Move point to next subtitle's text.
+Return point or nil if there is no next subtitle."
+  (interactive)
+  (when (subed-forward-subtitle-id)
+    (subed-jump-to-subtitle-text)))
+
+(subed-define-generic-function backward-subtitle-text ()
+  "Move point to previous subtitle's text.
+Return point or nil if there is no previous subtitle."
+  (interactive)
+  (when (subed-backward-subtitle-id)
+    (subed-jump-to-subtitle-text)))
+
+(subed-define-generic-function forward-subtitle-end ()
+  "Move point to end of next subtitle.
+Return point or nil if there is no next subtitle."
+  (interactive)
+  (when (subed-forward-subtitle-id)
+    (subed-jump-to-subtitle-end)))
+
+(subed-define-generic-function backward-subtitle-end ()
+  "Move point to end of previous subtitle.
+Return point or nil if there is no previous subtitle."
+  (interactive)
+  (when (subed-backward-subtitle-id)
+    (subed-jump-to-subtitle-end)))
+
+(subed-define-generic-function forward-subtitle-time-start ()
+  "Move point to next subtitle's start time."
+  (interactive)
+  (when (subed-forward-subtitle-id)
+    (subed-jump-to-subtitle-time-start)))
+
+(subed-define-generic-function backward-subtitle-time-start ()
+  "Move point to previous subtitle's start time."
+  (interactive)
+  (when (subed-backward-subtitle-id)
+    (subed-jump-to-subtitle-time-start)))
+
+(subed-define-generic-function forward-subtitle-time-stop ()
+  "Move point to next subtitle's stop time."
+  (interactive)
+  (when (subed-forward-subtitle-id)
+    (subed-jump-to-subtitle-time-stop)))
 
-(defun subed-msecs-to-timestamp (msecs)
-  "Convert MSECS to human-readable string."
-  ;; We need to wrap format-seconds in save-match-data because it does regexp
-  ;; stuff and we need to preserve our own match-data.
-  (concat (save-match-data (format-seconds "%02h:%02m:%02s" (/ msecs 1000)))
-          "," (format "%03d" (mod msecs 1000))))
+(subed-define-generic-function backward-subtitle-time-stop ()
+  "Move point to previous subtitle's stop time."
+  (interactive)
+  (when (subed-backward-subtitle-id)
+    (subed-jump-to-subtitle-time-stop)))
+
+(subed-define-generic-function subtitle-msecs-start (&optional sub-id)
+  "Subtitle start time in milliseconds or nil if it can't be found.
+If SUB-ID is not given, use subtitle on point."
+  (let ((timestamp (save-excursion
+                     (when (subed-jump-to-subtitle-time-start sub-id)
+                       (when (looking-at subed--regexp-timestamp)
+                         (match-string 0))))))
+    (when timestamp
+      (subed-timestamp-to-msecs timestamp))))
+
+(subed-define-generic-function subtitle-msecs-stop (&optional sub-id)
+  "Subtitle stop time in milliseconds or nil if it can't be found.
+If SUB-ID is not given, use subtitle on point."
+  (let ((timestamp (save-excursion
+                     (when (subed-jump-to-subtitle-time-stop sub-id)
+                       (when (looking-at subed--regexp-timestamp)
+                         (match-string 0))))))
+    (when timestamp
+      (subed-timestamp-to-msecs timestamp))))
+
+(subed-define-generic-function subtitle-text (&optional sub-id)
+  "Return subtitle's text or an empty string.
+If SUB-ID is not given, use subtitle on point."
+  (or (save-excursion
+        (let ((beg (subed-jump-to-subtitle-text sub-id))
+              (end (subed-jump-to-subtitle-end sub-id)))
+          (when (and beg end)
+            (buffer-substring beg end)))) ""))
+
+(subed-define-generic-function subtitle-relative-point ()
+  "Point relative to subtitle's ID or nil if ID can't be found."
+  (let ((start-point (save-excursion
+                       (when (subed-jump-to-subtitle-id)
+                         (point)))))
+    (when start-point
+      (- (point) start-point))))
+
+(subed-define-generic-function set-subtitle-time-start (msecs &optional sub-id)
+  "Set subtitle start time to MSECS milliseconds.
+
+If SUB-ID is not given, set the start of the current subtitle.
+
+Return the new subtitle start time in milliseconds."
+  (save-excursion
+    (when (or (not sub-id)
+              (and sub-id (subed-jump-to-subtitle-id sub-id)))
+      (when (and (subed-jump-to-subtitle-time-start sub-id)
+                 (looking-at subed--regexp-timestamp))
+        (replace-match (subed-msecs-to-timestamp msecs))))))
+
+(subed-define-generic-function set-subtitle-time-stop (msecs &optional sub-id)
+  "Set subtitle stop time to MSECS milliseconds.
+
+If SUB-ID is not given, set the stop of the current subtitle.
+
+Return the new subtitle stop time in milliseconds."
+  (save-excursion
+    (when (and (subed-jump-to-subtitle-time-stop sub-id)
+               (looking-at subed--regexp-timestamp))
+      (replace-match (subed-msecs-to-timestamp msecs)))))
+
+(subed-define-generic-function make-subtitle (&optional id start stop text)
+  "Generate new subtitle string.
+
+ID, START default to 0.
+STOP defaults to (+ START `subed-subtitle-spacing')
+TEXT defaults to an empty string."
+  (interactive "P"))
+
+(subed-define-generic-function prepend-subtitle (&optional id start stop text)
+  "Insert new subtitle before the subtitle at point.
+
+ID and START default to 0.
+STOP defaults to (+ START `subed-subtitle-spacing')
+TEXT defaults to an empty string.
+
+Move point to the text of the inserted subtitle.
+Return new point."
+  (interactive "P"))
+
+(subed-define-generic-function append-subtitle (&optional id start stop text)
+  "Insert new subtitle after the subtitle at point.
+
+ID, START default to 0.
+STOP defaults to (+ START `subed-subtitle-spacing')
+TEXT defaults to an empty string.
+
+Move point to the text of the inserted subtitle.
+Return new point."
+  (interactive "P"))
+
+(subed-define-generic-function kill-subtitle ()
+  "Remove subtitle at point."
+  (interactive)
+  (let ((beg (save-excursion (subed-jump-to-subtitle-id)
+                             (point)))
+        (end (save-excursion (subed-jump-to-subtitle-id)
+                             (when (subed-forward-subtitle-id)
+                               (point)))))
+    (if (not end)
+        ;; Removing the last subtitle because forward-subtitle-id returned nil
+        (setq beg (save-excursion (goto-char beg)
+                                  (subed-backward-subtitle-end)
+                                  (1+ (point)))
+              end (save-excursion (goto-char (point-max)))))
+    (delete-region beg end)))
+
+(subed-define-generic-function subtitle-list (&optional beg end)
+  "Return the subtitles from BEG to END as a list.
+The list will contain entries of the form (id start stop text).
+If BEG and END are not specified, use the whole buffer."
+  (let (result)
+    (subed-for-each-subtitle
+      (or beg (point-min))
+      (or end (point-max))
+      nil
+      (when (subed-subtitle-msecs-start)
+        (setq result
+              (cons
+               (list
+                (subed-subtitle-id)
+                (subed-subtitle-msecs-start)
+                (subed-subtitle-msecs-stop)
+                (subed-subtitle-text))
+               result))))
+    (nreverse result)))
+
+(subed-define-generic-function sanitize ()
+  "Remove surplus newlines and whitespace.")
+
+(subed-define-generic-function validate ()
+  "Move point to the first invalid subtitle and report an error.")
+
+(subed-define-generic-function regenerate-ids ()
+  "Ensure consecutive, unduplicated subtitle IDs in formats that use them.")
+
+(defvar-local subed--regenerate-ids-soon-timer nil)
+(subed-define-generic-function regenerate-ids-soon ()
+  "Delay regenerating subtitle IDs for a short amount of time.
+
+  Run `subed-regenerate-ids' in 100ms unless this function is
+called again within the next 100ms, in which case the previously
+scheduled call is canceled and another call is scheduled in
+100ms."
+  (interactive)
+  (when subed--regenerate-ids-soon-timer
+    (cancel-timer subed-srt--regenerate-ids-soon-timer))
+  (setq subed--regenerate-ids-soon-timer
+        (run-at-time 0.1 nil (lambda ()
+                               (setq subed--regenerate-ids-soon-timer nil)
+                               (subed-regenerate-ids)))))
+
+;;; Utilities
 
 (defmacro subed-save-excursion (&rest body)
   "Restore relative point within current subtitle after executing BODY.
@@ -663,7 +986,7 @@ Return a list of values in the following order:
           msecs-min msecs-max msecs-avail msecs-per-sub msecs-between
           insert-subtitle-func)))
 
-(defun subed-insert-subtitle (&optional arg)
+(subed-define-generic-function insert-subtitle (&optional arg)
   "Insert subtitle(s) evenly spaced.
 
 The inserted subtitles are `subed-default-subtitle-length'
@@ -717,11 +1040,10 @@ following manner:
           (funcall insert-subtitle-func nil msecs-start msecs-stop nil)))
       (unless insert-before-current
         (dotimes (_ (1- number-of-subs))
-          (subed-backward-subtitle-text))))
-    (subed-regenerate-ids-soon))
+          (subed-backward-subtitle-text)))))
   (point))
 
-(defun subed-insert-subtitle-adjacent (&optional arg)
+(subed-define-generic-function insert-subtitle-adjacent (&optional arg)
   "Insert subtitle(s) close to each other.
 
 The inserted subtitles are `subed-default-subtitle-length'
@@ -768,11 +1090,10 @@ following manner:
           (funcall insert-subtitle-func nil msecs-start msecs-stop nil)))
       (unless insert-before-current
         (dotimes (_ (1- number-of-subs))
-          (subed-backward-subtitle-text))))
-    (subed-regenerate-ids-soon))
+          (subed-backward-subtitle-text)))))
   (point))
 
-(defun subed-split-subtitle (&optional offset)
+(subed-define-generic-function split-subtitle (&optional offset)
   "Split current subtitle at point.
 
 The subtitle text after point is moved to a new subtitle that is
@@ -830,12 +1151,16 @@ position of the point."
       (delete-region (point) (progn (subed-jump-to-subtitle-end) 
(skip-chars-forward " \t") (point)))
       (when (looking-at "[ \t]+") (replace-match ""))
       (subed-append-subtitle nil new-start-timestamp orig-end (string-trim 
new-text)))
-    (subed-regenerate-ids-soon)
     (point)))
 
 ;;; Merging
 
-(defun subed-merge-with-previous ()
+(subed-define-generic-function merge-with-next ()
+  "Merge the current subtitle with the next subtitle.
+Update the end timestamp accordingly."
+  (interactive))
+
+(subed-define-generic-function merge-with-previous ()
   "Merge the current subtitle with the previous subtitle.
 Update the end timestamp accordingly."
   (interactive)
@@ -1027,7 +1352,7 @@ If QUIET is non-nil, do not display a message in the 
minibuffer."
     (add-hook 'subed-subtitle-motion-hook #'subed--set-subtitle-loop :append 
:local)
     (subed-debug "Enabling loop: %s - %s" subed--subtitle-loop-start 
subed--subtitle-loop-stop)
     (when (subed-sync-point-to-player-p)
-      (subed-disable-sync-point-to-player)
+      (subed-disable-sync-point-to-player quiet)
       (setq subed--enable-point-to-player-sync-after-disabling-loop t))
     (unless quiet
       (message "Enabled looping over current subtitle"))))
@@ -1421,12 +1746,12 @@ the stop time isn't smaller than the start time."
 ;;; Sorting and sanitizing
 
 (defvar-local subed-sanitize-functions
-  '(subed-trim-overlap-maybe-sanitize)
+  '(subed-sort subed-trim-overlap-maybe-sanitize)
   "Functions to sanitize this buffer.
 Functions can clean up whitespace, rearrange subtitles, etc.")
 
 (defvar-local subed-validate-functions
-  '(subed-trim-overlap-maybe-check)
+  '(subed-validate subed-trim-overlap-maybe-check)
   "Functions to validate this buffer.
 Validation functions should throw an error or prompt the user for
 action.")
@@ -1438,19 +1763,27 @@ action.")
     (run-hooks 'subed-sanitize-functions)
     (run-hooks 'subed-validate-functions)))
 
-(defun subed-sort ()
+(subed-define-generic-function sort ()
   "Sort subtitles."
-  (subed-save-excursion
-   (goto-char (point-min))
-   (sort-subr nil
-              ;; nextrecfun (move to next record/subtitle or to end-of-buffer
-              ;; if there are no more records)
-              (lambda () (unless (subed-forward-subtitle-id)
-                           (goto-char (point-max))))
-              ;; endrecfun (move to end of current record/subtitle)
-              #'subed-jump-to-subtitle-end
-              ;; startkeyfun (return sort value of current record/subtitle)
-              #'subed-subtitle-msecs-start)))
+  (atomic-change-group
+    (subed-sanitize)
+    (subed-validate)
+    (subed-save-excursion
+     (goto-char (point-min))
+     (unless (subed-subtitle-id)
+       (subed-forward-subtitle-id))
+     (sort-subr nil
+                ;; nextrecfun (move to next record/subtitle or to end-of-buffer
+                ;; if there are no more records)
+                (lambda () (unless (subed-forward-subtitle-id)
+                             (goto-char (point-max))))
+                ;; endrecfun (move to end of current record/subtitle)
+                #'subed-jump-to-subtitle-end
+                ;; startkeyfun (return sort value of current record/subtitle)
+                #'subed-subtitle-msecs-start))))
+
+;;; Initialization
+
 
 (provide 'subed-common)
 ;;; subed-common.el ends here
diff --git a/subed/subed-mpv.el b/subed/subed-mpv.el
index 4701e07564..3575d7c0ca 100644
--- a/subed/subed-mpv.el
+++ b/subed/subed-mpv.el
@@ -214,28 +214,29 @@ string."
   ;; Therefore we maintain a buffer and process only complete lines.
   (when (buffer-live-p (process-buffer proc))
     (let ((orig-buffer (current-buffer)))
-         (with-current-buffer (process-buffer proc)
-        ;; Insert new response where previous response ended
-           (let* ((proc-mark (process-mark proc))
-               (moving (= (point) proc-mark)))
-                 (save-excursion
-                   (goto-char proc-mark)
-                   (insert response)
-                   (set-marker proc-mark (point)))
-                 (if moving (goto-char proc-mark)))
-           ;; Process and remove all complete lines of JSON (lines are 
complete if
-           ;; they end with \n)
-           (let ((p0 (point-min)))
-                 (while (progn (goto-char p0)
-                        (end-of-line)
-                                   (equal (following-char) ?\n))
-                   (let* ((p1 (point))
-                              (line (buffer-substring p0 p1)))
-                         (delete-region p0 (+ p1 1))
-              ;; Return context to the subtitle file buffer because we're using
-              ;; buffer-local variables to store player state.
-              (with-current-buffer orig-buffer
-                           (subed-mpv--client-handle-json line)))))))))
+      (when (derived-mode-p 'subed-mode)
+             (with-current-buffer (process-buffer proc)
+          ;; Insert new response where previous response ended
+               (let* ((proc-mark (process-mark proc))
+                 (moving (= (point) proc-mark)))
+                       (save-excursion
+                         (goto-char proc-mark)
+                         (insert response)
+                         (set-marker proc-mark (point)))
+                       (if moving (goto-char proc-mark)))
+               ;; Process and remove all complete lines of JSON (lines are 
complete if
+               ;; they end with \n)
+               (let ((p0 (point-min)))
+                       (while (progn (goto-char p0)
+                          (end-of-line)
+                                           (equal (following-char) ?\n))
+                         (let* ((p1 (point))
+                                      (line (buffer-substring p0 p1)))
+                                 (delete-region p0 (+ p1 1))
+                ;; Return context to the subtitle file buffer because we're 
using
+                ;; buffer-local variables to store player state.
+                (with-current-buffer orig-buffer
+                                   (subed-mpv--client-handle-json 
line))))))))))
 
 (defun subed-mpv--client-handle-json (json-string)
   "Process server response JSON-STRING."
diff --git a/subed/subed-srt.el b/subed/subed-srt.el
index 3a7989c735..77c260cf41 100644
--- a/subed/subed-srt.el
+++ b/subed/subed-srt.el
@@ -27,6 +27,7 @@
 
 ;;; Code:
 
+(require 'subed)
 (require 'subed-config)
 (require 'subed-debug)
 (require 'subed-common)
@@ -47,11 +48,12 @@
 (defconst subed-srt--regexp-timestamp 
"\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\),\\([0-9]+\\)")
 (defconst subed-srt--regexp-separator "\\(?:[[:blank:]]*\n\\)+[[:blank:]]*\n")
 
-(defun subed-srt--timestamp-to-msecs (time-string)
+(cl-defmethod subed--timestamp-to-msecs (time-string &context (major-mode 
subed-srt-mode))
   "Find HH:MM:SS,MS pattern in TIME-STRING and convert it to milliseconds.
-Return nil if TIME-STRING doesn't match the pattern."
+Return nil if TIME-STRING doesn't match the pattern.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (string-match subed-srt--regexp-timestamp time-string)
+    (when (string-match subed--regexp-timestamp time-string)
       (let ((hours (string-to-number (match-string 1 time-string)))
             (mins  (string-to-number (match-string 2 time-string)))
             (secs  (string-to-number (match-string 3 time-string)))
@@ -61,28 +63,25 @@ Return nil if TIME-STRING doesn't match the pattern."
            (* (truncate secs) 1000)
            (truncate msecs))))))
 
-(defun subed-srt--msecs-to-timestamp (msecs)
-  "Convert MSECS to string in the format HH:MM:SS,MS."
+(cl-defmethod subed--msecs-to-timestamp (msecs &context (major-mode 
subed-srt-mode))
+  "Convert MSECS to string in the format HH:MM:SS,MS.
+Use the format-specific function for MAJOR-MODE."
   ;; We need to wrap format-seconds in save-match-data because it does regexp
   ;; stuff and we need to preserve our own match-data.
   (concat (save-match-data (format-seconds "%02h:%02m:%02s" (/ msecs 1000)))
           "," (format "%03d" (mod msecs 1000))))
 
-(defun subed-srt--subtitle-id ()
-  "Return the ID of the subtitle at point or nil if there is no ID."
+(cl-defmethod subed--subtitle-id (&context (major-mode subed-srt-mode))
+  "Return the ID of the subtitle at point or nil if there is no ID.
+Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (when (subed-srt--jump-to-subtitle-id)
+    (when (subed-jump-to-subtitle-id)
       (string-to-number (current-word)))))
 
-(defun subed-srt--subtitle-id-max ()
-  "Return the ID of the last subtitle or nil if there are no subtitles."
-  (save-excursion
-    (goto-char (point-max))
-    (subed-srt--subtitle-id)))
-
-(defun subed-srt--subtitle-id-at-msecs (msecs)
+(cl-defmethod subed--subtitle-id-at-msecs (msecs &context (major-mode 
subed-srt-mode))
   "Return the ID of the subtitle at MSECS milliseconds.
-Return nil if there is no subtitle at MSECS."
+Return nil if there is no subtitle at MSECS.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (save-excursion
       (goto-char (point-min))
@@ -90,71 +89,33 @@ Return nil if there is no subtitle at MSECS."
              (only-hours (truncate (/ secs 3600)))
              (only-mins  (truncate (/ (- secs (* only-hours 3600)) 60))))
         ;; Move to first subtitle in the relevant hour
-        (when (re-search-forward (format "\\(%s\\|\\`\\)[0-9]+\n%02d:" 
subed-srt--regexp-separator only-hours) nil t)
+        (when (re-search-forward (format "\\(%s\\|\\`\\)[0-9]+\n%02d:" 
subed--regexp-separator only-hours) nil t)
           (beginning-of-line)
           ;; Move to first subtitle in the relevant hour and minute
           (re-search-forward (format "\\(\n\n\\|\\`\\)[0-9]+\n%02d:%02d" 
only-hours only-mins) nil t)))
       ;; Move to first subtitle that starts at or after MSECS
       (catch 'subtitle-id
-        (while (<= (or (subed-srt--subtitle-msecs-start) -1) msecs)
+        (while (<= (or (subed-subtitle-msecs-start) -1) msecs)
           ;; If stop time is >= MSECS, we found a match
-          (let ((cur-sub-end (subed-srt--subtitle-msecs-stop)))
+          (let ((cur-sub-end (subed-subtitle-msecs-stop)))
             (when (and cur-sub-end (>= cur-sub-end msecs))
-              (throw 'subtitle-id (subed-srt--subtitle-id))))
-          (unless (subed-srt--forward-subtitle-id)
+              (throw 'subtitle-id (subed-subtitle-id))))
+          (unless (subed-forward-subtitle-id)
             (throw 'subtitle-id nil)))))))
 
-(defun subed-srt--subtitle-msecs-start (&optional sub-id)
-  "Subtitle start time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-srt--jump-to-subtitle-time-start sub-id)
-                       (when (looking-at subed-srt--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-srt--timestamp-to-msecs timestamp))))
-
-(defun subed-srt--subtitle-msecs-stop (&optional sub-id)
-  "Subtitle stop time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-srt--jump-to-subtitle-time-stop sub-id)
-                       (when (looking-at subed-srt--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-srt--timestamp-to-msecs timestamp))))
-
-(defun subed-srt--subtitle-text (&optional sub-id)
-  "Return subtitle's text or an empty string.
-If SUB-ID is not given, use subtitle on point."
-  (or (save-excursion
-        (let ((beg (subed-srt--jump-to-subtitle-text sub-id))
-              (end (subed-srt--jump-to-subtitle-end sub-id)))
-          (when (and beg end)
-            (buffer-substring beg end)))) ""))
-
-(defun subed-srt--subtitle-relative-point ()
-  "Point relative to subtitle's ID or nil if ID can't be found."
-  (let ((start-point (save-excursion
-                       (when (subed-srt--jump-to-subtitle-id)
-                         (point)))))
-    (when start-point
-      (- (point) start-point))))
-
-
 ;;; Traversing
 
-(defun subed-srt--jump-to-subtitle-id (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-id (&context (major-mode subed-srt-mode) 
&optional sub-id)
   "Move to the ID of a subtitle and return point.
 If SUB-ID is not given, focus the current subtitle's ID.
-Return point or nil if no subtitle ID could be found."
-  (interactive)
+Return point or nil if no subtitle ID could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (if sub-id
         ;; Look for a line that contains only the ID, preceded by one or more
         ;; blank lines or the beginning of the buffer.
         (let* ((orig-point (point))
-               (regex (format "\\(%s\\|\\`\\)\\(%d\\)$" 
subed-srt--regexp-separator sub-id))
+               (regex (format "\\(%s\\|\\`\\)\\(%d\\)$" 
subed--regexp-separator sub-id))
                (match-found (progn (goto-char (point-min))
                                    (re-search-forward regex nil t))))
           (if match-found
@@ -164,7 +125,7 @@ Return point or nil if no subtitle ID could be found."
       (re-search-forward "\\([[:blank:]]*\n\\)+" nil t)
       ;; Find two or more blank lines or the beginning of the buffer, followed
       ;; by line composed of only digits.
-      (let* ((regex (concat "\\(" subed-srt--regexp-separator 
"\\|\\`\\)\\([0-9]+\\)$"))
+      (let* ((regex (concat "\\(" subed--regexp-separator 
"\\|\\`\\)\\([0-9]+\\)$"))
              (match-found (re-search-backward regex nil t)))
         (when match-found
           (goto-char (match-beginning 2)))))
@@ -172,63 +133,46 @@ Return point or nil if no subtitle ID could be found."
     (when (looking-at "^\\([0-9]+\\)$")
       (point))))
 
-(defun subed-srt--jump-to-subtitle-id-at-msecs (msecs)
-  "Move point to the ID of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-srt--subtitle-id-at-msecs'."
-  (let ((current-sub-id (subed-srt--subtitle-id))
-        (target-sub-id (subed-srt--subtitle-id-at-msecs msecs)))
-    (when (and target-sub-id current-sub-id (not (= target-sub-id 
current-sub-id)))
-      (subed-srt--jump-to-subtitle-id target-sub-id))))
-
-(defun subed-srt--jump-to-subtitle-text-at-msecs (msecs)
-  "Move point to the text of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-srt--subtitle-id-at-msecs'."
-  (when (subed-srt--jump-to-subtitle-id-at-msecs msecs)
-    (subed-srt--jump-to-subtitle-text)))
-
-(defun subed-srt--jump-to-subtitle-time-start (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-start (&context (major-mode 
subed-srt-mode) &optional sub-id)
   "Move point to subtitle's start time.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if no start time could be found."
-  (interactive)
+Return point or nil if no start time could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (subed-srt--jump-to-subtitle-id sub-id)
+    (when (subed-jump-to-subtitle-id sub-id)
       (forward-line)
-      (when (looking-at subed-srt--regexp-timestamp)
+      (when (looking-at subed--regexp-timestamp)
         (point)))))
 
-(defun subed-srt--jump-to-subtitle-time-stop (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-stop (&context (major-mode 
subed-srt-mode) &optional sub-id)
   "Move point to subtitle's stop time.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if no stop time could be found."
-  (interactive)
+Return point or nil if no stop time could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (subed-srt--jump-to-subtitle-id sub-id)
+    (when (subed-jump-to-subtitle-id sub-id)
       (forward-line 1)
       (re-search-forward " *--> *" (point-at-eol) t)
-      (when (looking-at subed-srt--regexp-timestamp)
+      (when (looking-at subed--regexp-timestamp)
         (point)))))
 
-(defun subed-srt--jump-to-subtitle-text (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-text (&context (major-mode 
subed-srt-mode) &optional sub-id)
   "Move point on the first character of subtitle's text.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if a the subtitle's text can't be found."
-  (interactive)
-  (when (subed-srt--jump-to-subtitle-id sub-id)
+Return point or nil if a the subtitle's text can't be found.
+Use the format-specific function for MAJOR-MODE."
+  (when (subed-jump-to-subtitle-id sub-id)
     (forward-line 2)
     (point)))
 
-(defun subed-srt--jump-to-subtitle-end (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-end (&context (major-mode 
subed-srt-mode) &optional sub-id)
   "Move point after the last character of the subtitle's text.
 If SUB-ID is not given, use subtitle on point.
 Return point or nil if point did not change or if no subtitle end
-can be found."
-  (interactive)
+can be found.  Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (let ((orig-point (point)))
-      (subed-srt--jump-to-subtitle-text sub-id)
+      (subed-jump-to-subtitle-text sub-id)
       ;; Look for next separator or end of buffer.  We can't use
       ;; `subed-srt--regexp-separator' here because if subtitle text is empty,
       ;; it may be the only empty line in the separator, i.e. there's only one
@@ -239,109 +183,30 @@ can be found."
       (unless (= (point) orig-point)
         (point)))))
 
-(defun subed-srt--forward-subtitle-id ()
+(cl-defmethod subed--forward-subtitle-id (&context (major-mode subed-srt-mode))
   "Move point to next subtitle's ID.
-Return point or nil if there is no next subtitle."
-  (interactive)
+Return point or nil if there is no next subtitle.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (re-search-forward (concat subed-srt--regexp-separator "[0-9]+\n") 
nil t)
-      (subed-srt--jump-to-subtitle-id))))
+    (when (re-search-forward (concat subed--regexp-separator "[0-9]+\n") nil t)
+      (subed-jump-to-subtitle-id))))
 
-(defun subed-srt--backward-subtitle-id ()
+(cl-defmethod subed--backward-subtitle-id (&context (major-mode 
subed-srt-mode))
   "Move point to previous subtitle's ID.
-Return point or nil if there is no previous subtitle."
-  (interactive)
+Return point or nil if there is no previous subtitle.
+Use the format-specific function for MAJOR-MODE."
   (let ((orig-point (point)))
-    (when (subed-srt--jump-to-subtitle-id)
-      (if (re-search-backward (concat "\\(" subed-srt--regexp-separator 
"\\|\\`[[:space:]]*\\)" "\\([0-9]+\\)\n") nil t)
+    (when (subed-jump-to-subtitle-id)
+      (if (re-search-backward (concat "\\(" subed--regexp-separator 
"\\|\\`[[:space:]]*\\)" "\\([0-9]+\\)\n") nil t)
           (progn
             (goto-char (match-beginning 2))
             (point))
         (goto-char orig-point)
         nil))))
 
-(defun subed-srt--forward-subtitle-text ()
-  "Move point to next subtitle's text.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-srt--forward-subtitle-id)
-    (subed-srt--jump-to-subtitle-text)))
-
-(defun subed-srt--backward-subtitle-text ()
-  "Move point to previous subtitle's text.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-srt--backward-subtitle-id)
-    (subed-srt--jump-to-subtitle-text)))
-
-(defun subed-srt--forward-subtitle-end ()
-  "Move point to end of next subtitle.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-srt--forward-subtitle-id)
-    (subed-srt--jump-to-subtitle-end)))
-
-(defun subed-srt--backward-subtitle-end ()
-  "Move point to end of previous subtitle.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-srt--backward-subtitle-id)
-    (subed-srt--jump-to-subtitle-end)))
-
-(defun subed-srt--forward-subtitle-time-start ()
-  "Move point to next subtitle's start time."
-  (interactive)
-  (when (subed-srt--forward-subtitle-id)
-    (subed-srt--jump-to-subtitle-time-start)))
-
-(defun subed-srt--backward-subtitle-time-start ()
-  "Move point to previous subtitle's start time."
-  (interactive)
-  (when (subed-srt--backward-subtitle-id)
-    (subed-srt--jump-to-subtitle-time-start)))
-
-(defun subed-srt--forward-subtitle-time-stop ()
-  "Move point to next subtitle's stop time."
-  (interactive)
-  (when (subed-srt--forward-subtitle-id)
-    (subed-srt--jump-to-subtitle-time-stop)))
-
-(defun subed-srt--backward-subtitle-time-stop ()
-  "Move point to previous subtitle's stop time."
-  (interactive)
-  (when (subed-srt--backward-subtitle-id)
-    (subed-srt--jump-to-subtitle-time-stop)))
-
-
 ;;; Manipulation
 
-(defun subed-srt--set-subtitle-time-start (msecs &optional sub-id)
-  "Set subtitle start time to MSECS milliseconds.
-
-If SUB-ID is not given, set the start of the current subtitle.
-
-Return the new subtitle start time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-srt--jump-to-subtitle-id sub-id)))
-      (subed-srt--jump-to-subtitle-time-start)
-      (when (looking-at subed-srt--regexp-timestamp)
-        (replace-match (subed-srt--msecs-to-timestamp msecs))))))
-
-(defun subed-srt--set-subtitle-time-stop (msecs &optional sub-id)
-  "Set subtitle stop time to MSECS milliseconds.
-
-If SUB-ID is not given, set the stop of the current subtitle.
-
-Return the new subtitle stop time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-srt--jump-to-subtitle-id sub-id)))
-      (subed-srt--jump-to-subtitle-time-stop)
-      (when (looking-at subed-srt--regexp-timestamp)
-        (replace-match (subed-srt--msecs-to-timestamp msecs))))))
-
-(defun subed-srt--make-subtitle (&optional id start stop text)
+(cl-defmethod subed--make-subtitle (&context (major-mode subed-srt-mode) 
&optional id start stop text)
   "Generate new subtitle string.
 
 ID, START default to 0.
@@ -349,16 +214,16 @@ STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
 A newline is appended to TEXT, meaning you'll get two trailing
-newlines if TEXT is nil or empty."
-  (interactive "P")
+newlines if TEXT is nil or empty.  Use the format-specific
+function for MAJOR-MODE."
   (format "%s\n%s --> %s\n%s\n"
           (or id 0)
-          (subed-srt--msecs-to-timestamp (or start 0))
-          (subed-srt--msecs-to-timestamp (or stop (+ (or start 0)
-                                                     
subed-default-subtitle-length)))
+          (subed-msecs-to-timestamp (or start 0))
+          (subed-msecs-to-timestamp (or stop (+ (or start 0)
+                                                
subed-default-subtitle-length)))
           (or text "")))
 
-(defun subed-srt--prepend-subtitle (&optional id start stop text)
+(cl-defmethod subed--prepend-subtitle (&context (major-mode subed-srt-mode) 
&optional id start stop text)
   "Insert new subtitle before the subtitle at point.
 
 ID and START default to 0.
@@ -366,17 +231,16 @@ STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
 Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (subed-srt--jump-to-subtitle-id)
-  (insert (subed-srt--make-subtitle id start stop text))
+Return new point.  Use the format-specific function for MAJOR-MODE."
+  (subed-jump-to-subtitle-id)
+  (insert (subed-make-subtitle id start stop text))
   (save-match-data
     (when (looking-at "\\([[:space:]]*\\|^\\)[0-9]+$")
       (insert "\n")))
   (forward-line -2)
-  (subed-srt--jump-to-subtitle-text))
+  (subed-jump-to-subtitle-text))
 
-(defun subed-srt--append-subtitle (&optional id start stop text)
+(cl-defmethod subed--append-subtitle (&context (major-mode subed-srt-mode) 
&optional id start stop text)
   "Insert new subtitle after the subtitle at point.
 
 ID, START default to 0.
@@ -384,100 +248,76 @@ STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
 Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (unless (subed-srt--forward-subtitle-id)
+Return new point.  Use the format-specific function for MAJOR-MODE."
+  (unless (subed-forward-subtitle-id)
     ;; Point is on last subtitle or buffer is empty
-    (subed-srt--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     ;; Moved point to end of last subtitle; ensure separator exists
     (while (not (looking-at "\\(\\`\\|[[:blank:]]*\n[[:blank:]]*\n\\)"))
       (save-excursion (insert ?\n)))
     ;; Move to end of separator
     (goto-char (match-end 0)))
-  (insert (subed-srt--make-subtitle id start stop text))
+  (insert (subed-make-subtitle id start stop text))
   ;; Complete separator with another newline unless we inserted at the end
   (save-match-data
     (when (looking-at "\\([[:space:]]*\\|^\\)[0-9]+$")
       (insert ?\n)))
   (forward-line -2)
-  (subed-srt--jump-to-subtitle-text))
+  (subed-jump-to-subtitle-text))
 
-(defun subed-srt--kill-subtitle ()
-  "Remove subtitle at point."
-  (interactive)
-  (let ((beg (save-excursion (subed-srt--jump-to-subtitle-id)
-                             (point)))
-        (end (save-excursion (subed-srt--jump-to-subtitle-id)
-                             (when (subed-srt--forward-subtitle-id)
-                               (point)))))
-    (if (not end)
-        ;; Removing the last subtitle because forward-subtitle-id returned nil
-        (setq beg (save-excursion (goto-char beg)
-                                  (subed-srt--backward-subtitle-end)
-                                  (1+ (point)))
-              end (save-excursion (goto-char (point-max)))))
-    (delete-region beg end))
-  (subed-srt--regenerate-ids-soon))
-
-(defun subed-srt--merge-with-next ()
+(cl-defmethod subed--kill-subtitle :after (&context (major-mode 
subed-srt-mode))
+  "Remove subtitle at point.
+Use the format-specific function for MAJOR-MODE."
+  (subed-regenerate-ids-soon))
+
+(cl-defmethod subed--split-subtitle :after (&context (major-mode 
subed-srt-mode) &optional offset)
+  "Split current subtitle at point.
+Use the format-specific function for MAJOR-MODE."
+  (subed-regenerate-ids-soon))
+
+(cl-defmethod subed--merge-with-next (&context (major-mode subed-srt-mode))
   "Merge the current subtitle with the next subtitle.
-Update the end timestamp accordingly."
-  (interactive)
+Update the end timestamp accordingly.
+Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (subed-srt--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     (let ((pos (point)) new-end)
-      (if (subed-srt--forward-subtitle-time-stop)
+      (if (subed-forward-subtitle-time-stop)
           (progn
-            (when (looking-at subed-srt--regexp-timestamp)
-              (setq new-end (subed-srt--timestamp-to-msecs (match-string 0))))
-            (subed-srt--jump-to-subtitle-text)
+            (when (looking-at subed--regexp-timestamp)
+              (setq new-end (subed-timestamp-to-msecs (match-string 0))))
+            (subed-jump-to-subtitle-text)
             (delete-region pos (point))
             (insert "\n")
-            (subed-srt--set-subtitle-time-stop new-end)
-            (subed-srt--regenerate-ids-soon))
+            (subed-set-subtitle-time-stop new-end)
+            (subed-regenerate-ids-soon))
         (error "No subtitle to merge into")))))
 
 ;;; Maintenance
 
-(defun subed-srt--regenerate-ids ()
+(cl-defmethod subed-regenerate-ids (&context (major-mode subed-srt-mode))
   "Ensure consecutive, unduplicated subtitle IDs."
   (interactive)
   (atomic-change-group
     (save-match-data
       (save-excursion
         (goto-char (point-min))
-        (subed-srt--jump-to-subtitle-id)
+        (subed-jump-to-subtitle-id)
         (when (looking-at "^[[:digit:]]+$")
           (unless (string= (current-word) "1")
             (delete-region (point) (progn (forward-word 1) (point)))
             (insert "1")))
         (let ((id 2))
-          (while (subed-srt--forward-subtitle-id)
+          (while (subed-forward-subtitle-id)
             (let ((id-str (number-to-string id)))
               (unless (string= (current-word) id-str)
                 (delete-region (point) (progn (forward-word 1) (point)))
                 (insert id-str)))
             (setq id (1+ id))))))))
 
-(defvar-local subed-srt--regenerate-ids-soon-timer nil)
-(defun subed-srt--regenerate-ids-soon ()
-  "Delay regenerating subtitle IDs for a short amount of time.
-
-Run `subed-srt--regenerate-ids' in 100ms unless this function is
-called again within the next 100ms, in which case the previously
-scheduled call is canceled and another call is scheduled in
-100ms."
-  (interactive)
-  (when subed-srt--regenerate-ids-soon-timer
-    (cancel-timer subed-srt--regenerate-ids-soon-timer))
-  (setq subed-srt--regenerate-ids-soon-timer
-        (run-at-time 0.1 nil (lambda ()
-                               (setq subed-srt--regenerate-ids-soon-timer nil)
-                               (subed-srt--regenerate-ids)))))
-
-(defun subed-srt--sanitize ()
-  "Remove surplus newlines and whitespace."
-  (interactive)
+(cl-defmethod subed--sanitize (&context (major-mode subed-srt-mode))
+  "Remove surplus newlines and whitespace.
+Use the format-specific function for MAJOR-MODE."
   (atomic-change-group
     (save-match-data
       (subed-save-excursion
@@ -496,8 +336,8 @@ scheduled call is canceled and another call is scheduled in
 
        ;; Replace separators between subtitles with double newlines
        (goto-char (point-min))
-       (while (subed-srt--forward-subtitle-id)
-         (let ((prev-sub-end (save-excursion (when 
(subed-srt--backward-subtitle-end)
+       (while (subed-forward-subtitle-id)
+         (let ((prev-sub-end (save-excursion (when 
(subed-backward-subtitle-end)
                                                (point)))))
            (when (and prev-sub-end
                       (not (string= (buffer-substring prev-sub-end (point)) 
"\n\n")))
@@ -510,27 +350,28 @@ scheduled call is canceled and another call is scheduled 
in
        (goto-char (point-min))
        (when (re-search-forward "[[:graph:]]" nil t)
          (goto-char (point-max))
-         (subed-srt--jump-to-subtitle-end)
+         (subed-jump-to-subtitle-end)
          (unless (looking-at "\n\\'")
            (delete-region (point) (point-max))
            (insert "\n")))
 
        ;; One space before and after " --> "
        (goto-char (point-min))
-       (while (re-search-forward (format "^%s" subed-srt--regexp-timestamp) 
nil t)
+       (while (re-search-forward (format "^%s" subed--regexp-timestamp) nil t)
          (when (looking-at "[[:blank:]]*-->[[:blank:]]*")
            (unless (= (length (match-string 0)) 5)
              (replace-match " --> "))))))))
 
-(defun subed-srt--validate ()
-  "Move point to the first invalid subtitle and report an error."
-  (interactive)
+(cl-defmethod subed--validate (&context (major-mode subed-srt-mode))
+  "Move point to the first invalid subtitle and report an error.
+Use the format-specific function for MAJOR-MODE."
   (when (> (buffer-size) 0)
     (atomic-change-group
       (save-match-data
         (let ((orig-point (point)))
           (goto-char (point-min))
-          (while (and (re-search-forward (format "\\(%s\\|\\`\\)" 
subed-srt--regexp-separator) nil t)
+          (while (and (re-search-forward (format "\\(%s\\|\\`\\)" 
subed--regexp-separator)
+                                         nil t)
                       (looking-at "[[:alnum:]]"))
             (unless (looking-at "^[0-9]+$")
               (error "Found invalid subtitle ID: %S" (substring (or 
(thing-at-point 'line :no-properties) "\n") 0 -1)))
@@ -550,33 +391,31 @@ scheduled call is canceled and another call is scheduled 
in
               (error "Found invalid stop time: %S" (substring (or 
(thing-at-point 'line :no-properties) "\n") 0 -1))))
           (goto-char orig-point))))))
 
-(defun subed-srt--sort ()
-  "Sanitize, then sort subtitles by start time and re-number them."
-  (interactive)
-  (atomic-change-group
-    (subed-srt--sanitize)
-    (subed-srt--validate)
-    (subed-save-excursion
-     (goto-char (point-min))
-     (sort-subr nil
-                ;; nextrecfun (move to next record/subtitle or to end-of-buffer
-                ;; if there are no more records)
-                (lambda () (unless (subed-srt--forward-subtitle-id)
-                             (goto-char (point-max))))
-                ;; endrecfun (move to end of current record/subtitle)
-                #'subed-srt--jump-to-subtitle-end
-                ;; startkeyfun (return sort value of current record/subtitle)
-                #'subed-srt--subtitle-msecs-start))
-    (subed-srt--regenerate-ids)))
-
-(defun subed-srt--init ()
-  "This function is called when subed-mode is entered for a SRT file."
+(cl-defmethod subed--sort :after (&context (major-mode subed-srt-mode))
+  "Renumber after sorting. Format-specific for MAJOR-MODE."
+  (subed-regenerate-ids))
+
+(cl-defmethod subed--insert-subtitle :after (&context (major-mode 
subed-srt-mode) &optional arg)
+  "Renumber afterwards. Format-specific for MAJOR-MODE."
+  (subed-regenerate-ids-soon)
+  (point))
+
+(cl-defmethod subed--insert-subtitle-adjacent :after (&context (major-mode 
subed-srt-mode) &optional arg)
+  "Renumber afterwards. Format-specific for MAJOR-MODE."
+  (subed-regenerate-ids-soon)
+  (point))
+
+;;;###autoload
+(define-derived-mode subed-srt-mode subed-mode "Subed-SRT"
+  "Major mode for editing SubRip subtitle files."
   (setq-local subed--subtitle-format "srt")
+  (setq-local subed--regexp-timestamp subed-srt--regexp-timestamp)
+  (setq-local subed--regexp-separator subed-srt--regexp-separator)
   (setq-local font-lock-defaults '(subed-srt-font-lock-keywords))
   ;; Support for fill-paragraph (M-q)
-  (let ((timestamps-regexp (concat subed-srt--regexp-timestamp
+  (let ((timestamps-regexp (concat subed--regexp-timestamp
                                    " *--> *"
-                                   subed-srt--regexp-timestamp)))
+                                   subed--regexp-timestamp)))
     (setq-local paragraph-separate (concat "^\\("
                                            (mapconcat 'identity 
`("[[:blank:]]*"
                                                                   
"[[:digit:]]+"
@@ -589,9 +428,10 @@ scheduled call is canceled and another call is scheduled in
                                         (mapconcat 'identity '("^-"
                                                                
"[[:graph:]]*$") "\\|")
                                         "\\)")))
-  (add-hook 'subed-sanitize-functions #'subed-srt--sort nil t)
-  (add-hook 'subed-sanitize-functions #'subed-srt--regenerate-ids t t)
-  (add-hook 'subed-validate-functions #'subed-srt--validate t t))
+  (add-hook 'subed-sanitize-functions #'subed-regenerate-ids t t))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.srt\\'" . subed-srt-mode))
 
 (provide 'subed-srt)
 ;;; subed-srt.el ends here
diff --git a/subed/subed-vtt.el b/subed/subed-vtt.el
index d87fcd09aa..45f7ce8400 100644
--- a/subed/subed-vtt.el
+++ b/subed/subed-vtt.el
@@ -27,6 +27,7 @@
 
 ;;; Code:
 
+(require 'subed)
 (require 'subed-config)
 (require 'subed-debug)
 (require 'subed-common)
@@ -46,11 +47,12 @@
 (defconst subed-vtt--regexp-timestamp 
"\\(\\([0-9]+\\):\\)?\\([0-9]+\\):\\([0-9]+\\)\\.\\([0-9]+\\)")
 (defconst subed-vtt--regexp-separator "\\(?:[[:blank:]]*\n\\)+\\(?:NOTE[ 
\n]\\(?:.+?\n\\)+\n\\)*\n")
 
-(defun subed-vtt--timestamp-to-msecs (time-string)
+(cl-defmethod subed--timestamp-to-msecs (time-string &context (major-mode 
subed-vtt-mode))
   "Find HH:MM:SS.MS pattern in TIME-STRING and convert it to milliseconds.
-Return nil if TIME-STRING doesn't match the pattern."
+Return nil if TIME-STRING doesn't match the pattern.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (string-match subed-vtt--regexp-timestamp time-string)
+    (when (string-match subed--regexp-timestamp time-string)
       (let ((hours (string-to-number (or (match-string 2 time-string) "0")))
             (mins  (string-to-number (match-string 3 time-string)))
             (secs  (string-to-number (match-string 4 time-string)))
@@ -60,29 +62,26 @@ Return nil if TIME-STRING doesn't match the pattern."
            (* (truncate secs) 1000)
            (truncate msecs))))))
 
-(defun subed-vtt--msecs-to-timestamp (msecs)
-  "Convert MSECS to string in the format HH:MM:SS,MS."
+(cl-defmethod subed--msecs-to-timestamp (msecs &context (major-mode 
subed-vtt-mode))
+  "Convert MSECS to string in the format HH:MM:SS.MS.
+Use the format-specific function for MAJOR-MODE."
   ;; We need to wrap format-seconds in save-match-data because it does regexp
   ;; stuff and we need to preserve our own match-data.
   (concat (save-match-data (format-seconds "%02h:%02m:%02s" (/ msecs 1000)))
           "." (format "%03d" (mod msecs 1000))))
 
-(defun subed-vtt--subtitle-id ()
-  "Return the ID of the subtitle at point or nil if there is no ID."
+(cl-defmethod subed--subtitle-id (&context (major-mode subed-vtt-mode))
+  "Return the ID of the subtitle at point or nil if there is no ID.
+Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (when (subed-vtt--jump-to-subtitle-id)
-      (when (looking-at subed-vtt--regexp-timestamp)
-        (match-string 0)))))
+    (when (and (subed-jump-to-subtitle-time-start)
+               (looking-at subed--regexp-timestamp))
+      (match-string 0))))
 
-(defun subed-vtt--subtitle-id-max ()
-  "Return the ID of the last subtitle or nil if there are no subtitles."
-  (save-excursion
-    (goto-char (point-max))
-    (subed-vtt--subtitle-id)))
-
-(defun subed-vtt--subtitle-id-at-msecs (msecs)
+(cl-defmethod subed--subtitle-id-at-msecs (msecs &context (major-mode 
subed-vtt-mode))
   "Return the ID of the subtitle at MSECS milliseconds.
-Return nil if there is no subtitle at MSECS."
+Return nil if there is no subtitle at MSECS.  Use the
+format-specific function for MAJOR-MODE."
   (save-match-data
     (save-excursion
       (goto-char (point-min))
@@ -90,72 +89,34 @@ Return nil if there is no subtitle at MSECS."
              (only-hours (truncate (/ secs 3600)))
              (only-mins  (truncate (/ (- secs (* only-hours 3600)) 60))))
         ;; Move to first subtitle in the relevant hour
-        (when (re-search-forward (format "\\(%s\\|\\`\\)%02d:" 
subed-vtt--regexp-separator only-hours) nil t)
+        (when (re-search-forward (format "\\(%s\\|\\`\\)%02d:" 
subed--regexp-separator only-hours) nil t)
           (beginning-of-line)
           ;; Move to first subtitle in the relevant hour and minute
           (re-search-forward (format "\\(\n\n\\|\\`\\)%02d:%02d" only-hours 
only-mins) nil t)))
       ;; Move to first subtitle that starts at or after MSECS
       (catch 'subtitle-id
-        (while (<= (or (subed-vtt--subtitle-msecs-start) -1) msecs)
+        (while (<= (or (subed-subtitle-msecs-start) -1) msecs)
           ;; If stop time is >= MSECS, we found a match
-          (let ((cur-sub-end (subed-vtt--subtitle-msecs-stop)))
+          (let ((cur-sub-end (subed-subtitle-msecs-stop)))
             (when (and cur-sub-end (>= cur-sub-end msecs))
-              (throw 'subtitle-id (subed-vtt--subtitle-id))))
-          (unless (subed-vtt--forward-subtitle-id)
+              (throw 'subtitle-id (subed-subtitle-id))))
+          (unless (subed-forward-subtitle-id)
             (throw 'subtitle-id nil)))))))
 
-(defun subed-vtt--subtitle-msecs-start (&optional sub-id)
-  "Subtitle start time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-vtt--jump-to-subtitle-time-start sub-id)
-                       (when (looking-at subed-vtt--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-vtt--timestamp-to-msecs timestamp))))
-
-(defun subed-vtt--subtitle-msecs-stop (&optional sub-id)
-  "Subtitle stop time in milliseconds or nil if it can't be found.
-If SUB-ID is not given, use subtitle on point."
-  (let ((timestamp (save-excursion
-                     (when (subed-vtt--jump-to-subtitle-time-stop sub-id)
-                       (when (looking-at subed-vtt--regexp-timestamp)
-                         (match-string 0))))))
-    (when timestamp
-      (subed-vtt--timestamp-to-msecs timestamp))))
-
-(defun subed-vtt--subtitle-text (&optional sub-id)
-  "Return subtitle's text or an empty string.
-If SUB-ID is not given, use subtitle on point."
-  (or (save-excursion
-        (let ((beg (subed-vtt--jump-to-subtitle-text sub-id))
-              (end (subed-vtt--jump-to-subtitle-end sub-id)))
-          (when (and beg end)
-            (buffer-substring beg end))))
-      ""))
-
-(defun subed-vtt--subtitle-relative-point ()
-  "Point relative to subtitle's ID or nil if ID can't be found."
-  (let ((start-point (save-excursion
-                       (when (subed-vtt--jump-to-subtitle-id)
-                         (point)))))
-    (when start-point
-      (- (point) start-point))))
-
 ;;; Traversing
 
-(defun subed-vtt--jump-to-subtitle-id (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-id (&context (major-mode subed-vtt-mode) 
&optional sub-id)
   "Move to the ID of a subtitle and return point.
 If SUB-ID is not given, focus the current subtitle's ID.
 Return point or nil if no subtitle ID could be found.
-WebVTT doesn't use IDs, so we use the starting timestamp instead."
-  (interactive)
+WebVTT doesn't use IDs, so we use the starting timestamp instead.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (if (stringp sub-id)
-        ;; Look for a line that contains only the ID, preceded by one or more
+        ;; Look for a line that contains the timestamp, preceded by one or more
         ;; blank lines or the beginning of the buffer.
         (let* ((orig-point (point))
-               (regex (concat "\\(" subed-srt--regexp-separator "\\|\\`\\)\\(" 
(regexp-quote sub-id) "\\)"))
+               (regex (concat "\\(" subed--regexp-separator "\\|\\`\\)\\(" 
(regexp-quote sub-id) "\\)"))
                (match-found (progn (goto-char (point-min))
                                    (re-search-forward regex nil t))))
           (if match-found
@@ -165,7 +126,7 @@ WebVTT doesn't use IDs, so we use the starting timestamp 
instead."
       (re-search-forward "\\([[:blank:]]*\n\\)+" nil t)
       ;; Find two or more blank lines or the beginning of the buffer, followed
       ;; by line starting with a timestamp.
-      (let* ((regex (concat  "\\(" subed-srt--regexp-separator "\\|\\`\\)\\(" 
subed-vtt--regexp-timestamp "\\)"))
+      (let* ((regex (concat  "\\(" subed--regexp-separator "\\|\\`\\)\\(" 
subed--regexp-timestamp "\\)"))
              (match-found (re-search-backward regex nil t)))
         (when match-found
           (goto-char (match-beginning 2)))))
@@ -173,176 +134,80 @@ WebVTT doesn't use IDs, so we use the starting timestamp 
instead."
     (when (looking-at "^\\(\\([0-9]+:\\)?[0-9]+:[0-9]+\\.[0-9]+\\)")
       (point))))
 
-(defun subed-vtt--jump-to-subtitle-id-at-msecs (msecs)
-  "Move point to the ID of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-vtt--subtitle-id-at-msecs'."
-  (let ((current-sub-id (subed-vtt--subtitle-id))
-        (target-sub-id (subed-vtt--subtitle-id-at-msecs msecs)))
-    (when (and target-sub-id current-sub-id (not (equal target-sub-id 
current-sub-id)))
-      (subed-vtt--jump-to-subtitle-id target-sub-id))))
-
-(defun subed-vtt--jump-to-subtitle-text-at-msecs (msecs)
-  "Move point to the text of the subtitle that is playing at MSECS.
-Return point or nil if point is still on the same subtitle.
-See also `subed-vtt--subtitle-id-at-msecs'."
-  (when (subed-vtt--jump-to-subtitle-id-at-msecs msecs)
-    (subed-vtt--jump-to-subtitle-text)))
-
-(defun subed-vtt--jump-to-subtitle-time-start (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-start (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point to subtitle's start time.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if no start time could be found."
-  (interactive)
+Return point or nil if no start time could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (subed-vtt--jump-to-subtitle-id sub-id)
-      (when (looking-at subed-vtt--regexp-timestamp)
+    (when (subed-jump-to-subtitle-id sub-id)
+      (when (looking-at subed--regexp-timestamp)
         (point)))))
 
-(defun subed-vtt--jump-to-subtitle-time-stop (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-time-stop (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point to subtitle's stop time.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if no stop time could be found."
-  (interactive)
+Return point or nil if no stop time could be found.
+Use the format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (subed-vtt--jump-to-subtitle-id sub-id)
+    (when (subed-jump-to-subtitle-id sub-id)
       (re-search-forward " *--> *" (point-at-eol) t)
-      (when (looking-at subed-vtt--regexp-timestamp)
+      (when (looking-at subed--regexp-timestamp)
         (point)))))
 
-(defun subed-vtt--jump-to-subtitle-text (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-text (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point on the first character of subtitle's text.
 If SUB-ID is not given, use subtitle on point.
-Return point or nil if a the subtitle's text can't be found."
-  (interactive)
-  (when (subed-vtt--jump-to-subtitle-id sub-id)
+Return point or nil if a the subtitle's text can't be found.
+Use the format-specific function for MAJOR-MODE."
+  (when (subed-jump-to-subtitle-id sub-id)
     (forward-line 1)
     (point)))
 
-(defun subed-vtt--jump-to-subtitle-end (&optional sub-id)
+(cl-defmethod subed--jump-to-subtitle-end (&context (major-mode 
subed-vtt-mode) &optional sub-id)
   "Move point after the last character of the subtitle's text.
 If SUB-ID is not given, use subtitle on point.
 Return point or nil if point did not change or if no subtitle end
-can be found."
-  (interactive)
+can be found.  Use the format-specific function for MAJOR-MODE."
   (save-match-data
     (let ((orig-point (point)))
-      (subed-vtt--jump-to-subtitle-text sub-id)
+      (subed-jump-to-subtitle-text sub-id)
       ;; Look for next separator or end of buffer.  We can't use
       ;; `subed-vtt--regexp-separator' here because if subtitle text is empty,
       ;; it may be the only empty line in the separator, i.e. there's only one
       ;; "\n".
       (let ((regex (concat "\\([[:blank:]]*\n\\)+"
                            "\\(?:NOTE[ \n]\\(?:.+?\n\\)+\n\\)*"
-                           "\\(" subed-vtt--regexp-timestamp 
"\\)\\|\\([[:blank:]]*\n*\\)\\'")))
+                           "\\(" subed--regexp-timestamp 
"\\)\\|\\([[:blank:]]*\n*\\)\\'")))
         (when (re-search-forward regex nil t)
           (goto-char (match-beginning 0))))
       (unless (= (point) orig-point)
         (point)))))
 
-(defun subed-vtt--forward-subtitle-id ()
+(cl-defmethod subed--forward-subtitle-id (&context (major-mode subed-vtt-mode))
   "Move point to next subtitle's ID.
-Return point or nil if there is no next subtitle."
-  (interactive)
+Return point or nil if there is no next subtitle.  Use the
+format-specific function for MAJOR-MODE."
   (save-match-data
-    (when (re-search-forward (concat subed-vtt--regexp-separator 
subed-vtt--regexp-timestamp) nil t)
-      (subed-vtt--jump-to-subtitle-id))))
+    (when (re-search-forward (concat subed--regexp-separator 
subed--regexp-timestamp) nil t)
+      (subed-jump-to-subtitle-id))))
 
-(defun subed-vtt--backward-subtitle-id ()
+(cl-defmethod subed--backward-subtitle-id (&context (major-mode 
subed-vtt-mode))
   "Move point to previous subtitle's ID.
-Return point or nil if there is no previous subtitle."
-  (interactive)
+Return point or nil if there is no previous subtitle.  Use the
+format-specific function for MAJOR-MODE."
   (let ((orig-point (point)))
-    (when (subed-vtt--jump-to-subtitle-id)
-      (if (re-search-backward (concat "\\(" subed-vtt--regexp-separator 
"\\|\\`[[:space:]]*\\)\\(" subed-vtt--regexp-timestamp "\\)") nil t)
+    (when (subed-jump-to-subtitle-id)
+      (if (re-search-backward (concat "\\(" subed--regexp-separator 
"\\|\\`[[:space:]]*\\)\\(" subed--regexp-timestamp "\\)") nil t)
           (progn
             (goto-char (match-beginning 2))
             (point))
         (goto-char orig-point)
         nil))))
 
-(defun subed-vtt--forward-subtitle-text ()
-  "Move point to next subtitle's text.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-vtt--forward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-text)))
-
-(defun subed-vtt--backward-subtitle-text ()
-  "Move point to previous subtitle's text.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-vtt--backward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-text)))
-
-(defun subed-vtt--forward-subtitle-end ()
-  "Move point to end of next subtitle.
-Return point or nil if there is no next subtitle."
-  (interactive)
-  (when (subed-vtt--forward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-end)))
-
-(defun subed-vtt--backward-subtitle-end ()
-  "Move point to end of previous subtitle.
-Return point or nil if there is no previous subtitle."
-  (interactive)
-  (when (subed-vtt--backward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-end)))
-
-(defun subed-vtt--forward-subtitle-time-start ()
-  "Move point to next subtitle's start time."
-  (interactive)
-  (when (subed-vtt--forward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-time-start)))
-
-(defun subed-vtt--backward-subtitle-time-start ()
-  "Move point to previous subtitle's start time."
-  (interactive)
-  (when (subed-vtt--backward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-time-start)))
-
-(defun subed-vtt--forward-subtitle-time-stop ()
-  "Move point to next subtitle's stop time."
-  (interactive)
-  (when (subed-vtt--forward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-time-stop)))
-
-(defun subed-vtt--backward-subtitle-time-stop ()
-  "Move point to previous subtitle's stop time."
-  (interactive)
-  (when (subed-vtt--backward-subtitle-id)
-    (subed-vtt--jump-to-subtitle-time-stop)))
-
-
 ;;; Manipulation
 
-(defun subed-vtt--set-subtitle-time-start (msecs &optional sub-id)
-  "Set subtitle start time to MSECS milliseconds.
-
-If SUB-ID is not given, set the start of the current subtitle.
-
-Return the new subtitle start time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-vtt--jump-to-subtitle-id sub-id)))
-      (subed-vtt--jump-to-subtitle-time-start)
-      (when (looking-at subed-vtt--regexp-timestamp)
-        (replace-match (subed-vtt--msecs-to-timestamp msecs))))))
-
-(defun subed-vtt--set-subtitle-time-stop (msecs &optional sub-id)
-  "Set subtitle stop time to MSECS milliseconds.
-
-If SUB-ID is not given, set the stop of the current subtitle.
-
-Return the new subtitle stop time in milliseconds."
-  (save-excursion
-    (when (or (not sub-id)
-              (and sub-id (subed-vtt--jump-to-subtitle-id sub-id)))
-      (subed-vtt--jump-to-subtitle-time-stop)
-      (when (looking-at subed-vtt--regexp-timestamp)
-        (replace-match (subed-vtt--msecs-to-timestamp msecs))))))
-
-(defun subed-vtt--make-subtitle (&optional id start stop text)
+(cl-defmethod subed--make-subtitle (&context (major-mode subed-vtt-mode) 
&optional id start stop text)
   "Generate new subtitle string.
 
 ID, START default to 0.
@@ -350,106 +215,79 @@ STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
 A newline is appended to TEXT, meaning you'll get two trailing
-newlines if TEXT is nil or empty."
-  (interactive "P")
+newlines if TEXT is nil or empty.  Use the format-specific
+function for MAJOR-MODE."
   (format "%s --> %s\n%s\n"
-          (subed-vtt--msecs-to-timestamp (or start 0))
-          (subed-vtt--msecs-to-timestamp (or stop (+ (or start 0)
-                                                     
subed-default-subtitle-length)))
+          (subed-msecs-to-timestamp (or start 0))
+          (subed-msecs-to-timestamp (or stop (+ (or start 0)
+                                                
subed-default-subtitle-length)))
           (or text "")))
 
-(defun subed-vtt--prepend-subtitle (&optional id start stop text)
+(cl-defmethod subed--prepend-subtitle (&context (major-mode subed-vtt-mode) 
&optional id start stop text)
   "Insert new subtitle before the subtitle at point.
 
 ID and START default to 0.
 STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
-Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (subed-vtt--jump-to-subtitle-id)
-  (insert (subed-vtt--make-subtitle id start stop text))
+Move point to the text of the inserted subtitle.  Return new
+point.  Use the format-specific function for MAJOR-MODE."
+  (subed-jump-to-subtitle-id)
+  (insert (subed-make-subtitle id start stop text))
   (save-match-data
-    (when (looking-at (concat "\\([[:space:]]*\\|^\\)" 
subed-vtt--regexp-timestamp))
+    (when (looking-at (concat "\\([[:space:]]*\\|^\\)" 
subed--regexp-timestamp))
       (insert "\n")))
   (forward-line -2)
-  (subed-vtt--jump-to-subtitle-text))
+  (subed-jump-to-subtitle-text))
 
-(defun subed-vtt--append-subtitle (&optional id start stop text)
+(cl-defmethod subed--append-subtitle (&context (major-mode subed-vtt-mode) 
&optional id start stop text)
   "Insert new subtitle after the subtitle at point.
 
 ID, START default to 0.
 STOP defaults to (+ START `subed-subtitle-spacing')
 TEXT defaults to an empty string.
 
-Move point to the text of the inserted subtitle.
-Return new point."
-  (interactive "P")
-  (unless (subed-vtt--forward-subtitle-id)
+Move point to the text of the inserted subtitle.  Return new
+point.  Use the format-specific function for MAJOR-MODE."
+  (unless (subed-forward-subtitle-id)
     ;; Point is on last subtitle or buffer is empty
-    (subed-vtt--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     ;; Moved point to end of last subtitle; ensure separator exists
     (while (not (looking-at "\\(\\`\\|[[:blank:]]*\n[[:blank:]]*\n\\)"))
       (save-excursion (insert ?\n)))
     ;; Move to end of separator
     (goto-char (match-end 0)))
-  (insert (subed-vtt--make-subtitle id start stop text))
+  (insert (subed-make-subtitle id start stop text))
   ;; Complete separator with another newline unless we inserted at the end
   (save-match-data
-    (when (looking-at (concat "\\([[:space:]]*\\|^\\)" 
subed-vtt--regexp-timestamp))
+    (when (looking-at (concat "\\([[:space:]]*\\|^\\)" 
subed--regexp-timestamp))
       (insert ?\n)))
   (forward-line -2)
-  (subed-vtt--jump-to-subtitle-text))
-
-(defun subed-vtt--kill-subtitle ()
-  "Remove subtitle at point."
-  (interactive)
-  (let ((beg (save-excursion (subed-vtt--jump-to-subtitle-id)
-                             (point)))
-        (end (save-excursion (subed-vtt--jump-to-subtitle-id)
-                             (when (subed-vtt--forward-subtitle-id)
-                               (point)))))
-    (if (not end)
-        ;; Removing the last subtitle because forward-subtitle-id returned nil
-        (setq beg (save-excursion (goto-char beg)
-                                  (subed-vtt--backward-subtitle-end)
-                                  (1+ (point)))
-              end (save-excursion (goto-char (point-max)))))
-    (delete-region beg end)))
-
-(defun subed-vtt--merge-with-next ()
+  (subed-jump-to-subtitle-text))
+
+(cl-defmethod subed--merge-with-next (&context (major-mode subed-vtt-mode))
   "Merge the current subtitle with the next subtitle.
-Update the end timestamp accordingly."
-  (interactive)
+Update the end timestamp accordingly.
+Use the format-specific function for MAJOR-MODE."
   (save-excursion
-    (subed-vtt--jump-to-subtitle-end)
+    (subed-jump-to-subtitle-end)
     (let ((pos (point)) new-end)
-      (if (subed-vtt--forward-subtitle-time-stop)
+      (if (subed-forward-subtitle-time-stop)
           (progn
-            (when (looking-at subed-vtt--regexp-timestamp)
-              (setq new-end (subed-vtt--timestamp-to-msecs (match-string 0))))
-            (subed-vtt--jump-to-subtitle-text)
+            (when (looking-at subed--regexp-timestamp)
+              (setq new-end (subed-timestamp-to-msecs (match-string 0))))
+            (subed-jump-to-subtitle-text)
             (delete-region pos (point))
             (insert "\n")
-            (subed-vtt--set-subtitle-time-stop new-end))
+            (subed-set-subtitle-time-stop new-end))
         (error "No subtitle to merge into")))))
 
-
 ;;; Maintenance
 
-(defun subed-vtt--regenerate-ids ()
-  "Not applicable to WebVTT."
-  (interactive))
 
-(defvar-local subed-vtt--regenerate-ids-soon-timer nil)
-(defun subed-vtt--regenerate-ids-soon ()
-  "Not applicable to WebVTT."
-  (interactive))
-
-(defun subed-vtt--sanitize ()
-  "Remove surplus newlines and whitespace."
-  (interactive)
+(cl-defmethod subed--sanitize (&context (major-mode subed-vtt-mode))
+  "Remove surplus newlines and whitespace.
+Use the format-specific function for MAJOR-MODE."
   (atomic-change-group
     (save-match-data
       (subed-save-excursion
@@ -468,8 +306,8 @@ Update the end timestamp accordingly."
 
        ;; Replace separators between subtitles with double newlines
        (goto-char (point-min))
-       (while (subed-vtt--forward-subtitle-id)
-         (let ((prev-sub-end (save-excursion (when 
(subed-vtt--backward-subtitle-end)
+       (while (subed-forward-subtitle-id)
+         (let ((prev-sub-end (save-excursion (when 
(subed-backward-subtitle-end)
                                                (point)))))
            (when (and prev-sub-end
                       (not (string= (buffer-substring prev-sub-end (point)) 
"\n\n")))
@@ -482,29 +320,29 @@ Update the end timestamp accordingly."
        (goto-char (point-min))
        (when (re-search-forward "[[:graph:]]" nil t)
          (goto-char (point-max))
-         (subed-vtt--jump-to-subtitle-end)
+         (subed-jump-to-subtitle-end)
          (unless (looking-at "\n\\'")
            (delete-region (point) (point-max))
            (insert "\n")))
 
        ;; One space before and after " --> "
        (goto-char (point-min))
-       (while (re-search-forward (format "^%s" subed-vtt--regexp-timestamp) 
nil t)
+       (while (re-search-forward (format "^%s" subed--regexp-timestamp) nil t)
          (when (looking-at "[[:blank:]]*-->[[:blank:]]*")
            (unless (= (length (match-string 0)) 5)
              (replace-match " --> "))))))))
 
-(defun subed-vtt--validate ()
-  "Move point to the first invalid subtitle and report an error."
-  (interactive)
+(cl-defmethod subed--validate (&context (major-mode subed-vtt-mode))
+  "Move point to the first invalid subtitle and report an error.
+Use the format-specific function for MAJOR-MODE."
   (when (> (buffer-size) 0)
     (atomic-change-group
       (save-match-data
         (let ((orig-point (point)))
           (goto-char (point-min))
-          (while (and (re-search-forward (format "^\\(%s\\)" 
subed-vtt--regexp-timestamp) nil t)
+          (while (and (re-search-forward (format "^\\(%s\\)" 
subed--regexp-timestamp) nil t)
                       (goto-char (match-beginning 1)))
-            ;; This regex is stricter than `subed-vtt--regexp-timestamp'
+            ;; This regex is stricter than `subed--regexp-timestamp'
             (unless (looking-at 
"^[0-9]\\{2\\}:[0-9]\\{2\\}:[0-9]\\{2\\}\\(\\.[0-9]\\{0,3\\}\\)")
               (error "Found invalid start time: %S"  (substring (or 
(thing-at-point 'line :no-properties) "\n") 0 -1)))
             (when (re-search-forward "[[:blank:]]" (point-at-eol) t)
@@ -519,33 +357,36 @@ Update the end timestamp accordingly."
               (error "Found invalid stop time: %S" (substring (or 
(thing-at-point 'line :no-properties) "\n") 0 -1))))
           (goto-char orig-point))))))
 
-(defun subed-vtt--sort ()
-  "Sanitize, then sort subtitles by start time and re-number them."
-  (interactive)
+(cl-defmethod subed--sort (&context (major-mode subed-vtt-mode))
+  "Sanitize, then sort subtitles by start time.
+Use the format-specific function for MAJOR-MODE."
   (atomic-change-group
-    (subed-vtt--sanitize)
-    (subed-vtt--validate)
+    (subed-sanitize)
+    (subed-validate)
     (subed-save-excursion
      (goto-char (point-min))
-     (subed-vtt--forward-subtitle-id)
+     (subed-forward-subtitle-id)
      (sort-subr nil
                 ;; nextrecfun (move to next record/subtitle or to end-of-buffer
                 ;; if there are no more records)
-                (lambda () (unless (subed-vtt--forward-subtitle-id)
+                (lambda () (unless (subed-forward-subtitle-id)
                              (goto-char (point-max))))
                 ;; endrecfun (move to end of current record/subtitle)
-                #'subed-vtt--jump-to-subtitle-end
+                #'subed-jump-to-subtitle-end
                 ;; startkeyfun (return sort value of current record/subtitle)
-                #'subed-vtt--subtitle-msecs-start))))
+                #'subed-subtitle-msecs-start))))
 
-(defun subed-vtt--init ()
-  "This function is called when subed-mode is entered for a SRT file."
+;;;###autoload
+(define-derived-mode subed-vtt-mode subed-mode "Subed-VTT"
+  "Major mode for editing WebVTT subtitle files."
   (setq-local subed--subtitle-format "vtt")
+  (setq-local subed--regexp-timestamp subed-vtt--regexp-timestamp)
+  (setq-local subed--regexp-separator subed-vtt--regexp-separator)
   (setq-local font-lock-defaults '(subed-vtt-font-lock-keywords))
   ;; Support for fill-paragraph (M-q)
-  (let ((timestamps-regexp (concat subed-vtt--regexp-timestamp
+  (let ((timestamps-regexp (concat subed--regexp-timestamp
                                    " *--> *"
-                                   subed-vtt--regexp-timestamp)))
+                                   subed--regexp-timestamp)))
     (setq-local paragraph-separate (concat "^\\("
                                            (mapconcat 'identity 
`("[[:blank:]]*"
                                                                   
"[[:digit:]]+"
@@ -557,9 +398,10 @@ Update the end timestamp accordingly."
                                         ;; a "-" at the start of the line.
                                         (mapconcat 'identity '("^-"
                                                                
"[[:graph:]]*$") "\\|")
-                                        "\\)"))
-    (add-hook 'subed-sanitize-functions #'subed-vtt--sort nil t)
-    (add-hook 'subed-validate-functions #'subed-vtt--validate t t)))
+                                        "\\)"))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.vtt\\'" . subed-vtt-mode))
 
 (provide 'subed-vtt)
 ;;; subed-vtt.el ends here
diff --git a/subed/subed.el b/subed/subed.el
index de74ddc5ea..130e0cff6b 100644
--- a/subed/subed.el
+++ b/subed/subed.el
@@ -1,6 +1,6 @@
 ;;; subed.el --- A major mode for editing subtitles  -*- lexical-binding: t; 
-*-
 
-;; Version: 0.0.4
+;; Version: 1.0.1
 ;; Keywords: convenience, files, hypermedia, multimedia
 ;; URL: https://github.com/rndusr/subed
 ;; Package-Requires: ((emacs "25.1"))
@@ -32,12 +32,10 @@
 
 ;;; Code:
 
+(require 'subed-autoloads)
 (require 'subed-config)
 (require 'subed-debug)
 (require 'subed-common)
-(require 'subed-srt)
-(require 'subed-vtt)
-(require 'subed-ass)
 (require 'subed-mpv)
 
 (defconst subed-mpv-frame-step-map
@@ -90,90 +88,25 @@
                                                 html-tag-keymap))
     subed-mode-map))
 
-;;;###autoload
-(defvar subed--init-alist '(("srt" . subed-srt--init)
-                            ("vtt" . subed-vtt--init)
-                            ("ass" . subed-ass--init))
-  "Alist that maps file extensions to format-specific init functions.")
-
-;;; Abstraction hack to support different subtitle formats
-;;
-;; We need subtitle format-specific functions for each individual buffer so it
-;; is possible to open a .srt and a .sub file in the same Emacs session.
-;; Buffer-local functions don't exist in Elisp, but we can store the format in 
a
-;; buffer-local variable.
-;;
-;; `subed-mode-enable' runs a format-specific init function based on the file
-;; extension.  The init function sets the buffer-local variable
-;; `subed--subtitle-format' which is then used by generic functions to assemble
-;; the names of format-specific functions on the fly (e.g. (concat "subed-"
-;; subed-subtitle-format "--subtitle-id")).
-
-(defvar subed--generic-function-suffixes
-  (list "subtitle-id" "subtitle-id-max" "subtitle-id-at-msecs"
-        "subtitle-msecs-start" "subtitle-msecs-stop"
-        "subtitle-text" "subtitle-relative-point"
-        "msecs-to-timestamp" "timestamp-to-msecs"
-        "jump-to-subtitle-id" "jump-to-subtitle-id-at-msecs"
-        "jump-to-subtitle-time-start" "jump-to-subtitle-time-stop"
-        "jump-to-subtitle-text" "jump-to-subtitle-text-at-msecs"
-        "jump-to-subtitle-end"
-        "forward-subtitle-id" "backward-subtitle-id"
-        "forward-subtitle-text" "backward-subtitle-text"
-        "forward-subtitle-end" "backward-subtitle-end"
-        "forward-subtitle-time-start" "backward-subtitle-time-start"
-        "forward-subtitle-time-stop" "backward-subtitle-time-stop"
-        "set-subtitle-time-start" "set-subtitle-time-stop"
-        "prepend-subtitle" "append-subtitle" "kill-subtitle" "merge-with-next"
-        "regenerate-ids" "regenerate-ids-soon"
-        "sanitize" "validate" "sort" "make-subtitle"))
-
-(defun subed--get-generic-func (func-suffix)
-  "Return the generic/public function for FUNC-SUFFIX."
-  (intern (concat "subed-" func-suffix)))
-
-(defun subed--get-specific-func (func-suffix)
-  "Return the format-specific function for the current buffer for FUNC-SUFFIX."
-  (intern (concat "subed-" subed--subtitle-format "--" func-suffix)))
-
-(defun subed--init ()
-  "Call subtitle format-specific init function and (re-)alias generic 
functions."
-  ;; Call format-specific init function based on file extension and
-  ;; `subed--init-alist'.
-  (let* ((file-ext (when (buffer-file-name)
-                     (file-name-extension (buffer-file-name))))
-         (init-func (alist-get file-ext subed--init-alist nil nil 'equal)))
-    (if (functionp init-func)
-        (funcall init-func)
-      (error "Missing init function: %S" init-func))
-    (unless subed--subtitle-format
-      (error "%S failed to set buffer-local variable: subed--subtitle-format"
-             init-func)))
-  ;; Define generic functions like `subed-subtitle-text'.
-  (cl-loop for func-suffix in subed--generic-function-suffixes do
-           (let ((generic-func (subed--get-generic-func func-suffix))
-                 (specific-func (subed--get-specific-func func-suffix)))
-             (unless (functionp specific-func)
-               (error "Missing subtitle format-specific function: %s" 
specific-func))
-             (if (functionp specific-func)
-               (let* ((argspec (help-function-arglist specific-func))
-                      (argvars (seq-filter (lambda (argvar)
-                                             (let ((first-char (substring 
(symbol-name argvar) 0 1)))
-                                               (not (equal first-char "&"))))
-                                           argspec)))
-                 (defalias generic-func
-                   `(lambda ,argspec
-                      ,(interactive-form specific-func) ;; (interactive ...) 
or nil
-                      (let (;; Get the format-specific function for the current
-                            ;; buffer.  We must do this every time the generic
-                            ;; function is called because the result depends on
-                            ;; the buffer-local variable 
`subed--subtitle-format'.
-                            (specific-func (subed--get-specific-func 
,func-suffix))
-                            ;; Turn the list of variable names into a list of
-                            ;; corresponding values.
-                            (argvals (mapcar 'eval ',argvars)))
-                        (apply specific-func argvals)))
-                   (documentation specific-func t)))))))
+(defun subed-auto-find-video-maybe ()
+  "Load video associated with this subtitle file."
+  (let ((video-file (subed-guess-video-file)))
+    (when video-file
+      (subed-debug "Auto-discovered video file: %s" video-file)
+      (condition-case err
+          (subed-mpv-find-video video-file)
+        (error (message "%s -- Set subed-auto-find-video to nil to avoid this 
error."
+                        (car (cdr err))))))))
+
+;; TODO: Make these more configurable.
+(defun subed-set-up-defaults ()
+  "Quietly enable some recommended defaults."
+  (subed-enable-pause-while-typing :quiet)
+  (subed-enable-sync-point-to-player :quiet)
+  (subed-enable-sync-player-to-point :quiet)
+  (subed-enable-replay-adjusted-subtitle :quiet)
+  (subed-enable-loop-over-current-subtitle :quiet)
+  (subed-enable-show-cps :quiet))
 
 ;;;###autoload
 (define-derived-mode subed-mode text-mode "subed"
@@ -191,7 +124,7 @@ Adjust - Increase or decrease start or stop time of a 
subtitle
 Key bindings:
 \\{subed-mode-map}"
   :group 'subed
-  (subed--init)
+  (add-hook 'subed-mode-hook #'subed-guess-format :local)
   (add-hook 'post-command-hook #'subed--post-command-handler :append :local)
   (add-hook 'before-save-hook #'subed-prepare-to-save :append :local)
   (add-hook 'after-save-hook #'subed-mpv-reload-subtitles :append :local)
@@ -199,31 +132,22 @@ Key bindings:
   (add-hook 'kill-emacs-hook #'subed-mpv-kill :append :local)
   (when subed-trim-overlap-check-on-load
     (add-hook 'subed-mode-hook #'subed-trim-overlap-check :append :local))
+  (add-hook 'subed-mode-hook #'subed-set-up-defaults :append :local)
   (when subed-auto-find-video
-    (let ((video-file (subed-guess-video-file)))
-      (when video-file
-        (subed-debug "Auto-discovered video file: %s" video-file)
-        (condition-case err
-            (subed-mpv-find-video video-file)
-          (error (message "%s -- Set subed-auto-find-video to nil to avoid 
this error."
-                          (car (cdr err))))))))
-  (subed-enable-pause-while-typing :quiet)
-  (subed-enable-sync-point-to-player :quiet)
-  (subed-enable-sync-player-to-point :quiet)
-  (subed-enable-replay-adjusted-subtitle :quiet)
-  (subed-enable-loop-over-current-subtitle :quiet)
-  (subed-enable-show-cps :quiet))
-
-;; Internally, supported formats are listed in `subed--init-alist', which
-;; associates file extensions with format-specific init methods (e.g. "srt" ->
-;; subed-srt--init).  Here we map each file extension as a regexp to
-;; `subed-mode-enable', which will call the format-specific init method and do
-;; generic init stuff.
-;;;###autoload
-(dolist (item subed--init-alist)
-  (let ((file-ext-regex (car item)))
-    (add-to-list 'auto-mode-alist (cons (concat "\\." file-ext-regex "\\'")
-                                        'subed-mode))))
+    (add-hook 'subed-mode-hook #'subed-auto-find-video-maybe :append :local)))
+
+(defun subed-guess-format ()
+  "Set this buffer's format to a more specific subed mode format.
+This is a workaround for the transition to using format-specific
+modes such as `subed-srt-mode' while `auto-mode-alist' might
+still refer to `subed-mode'. It will also switch to the
+format-specific mode if `subed-mode' is called directly."
+  (when (and (eq major-mode 'subed-mode)
+             (buffer-file-name))
+    (pcase (file-name-extension (buffer-file-name))
+      ("vtt" (subed-vtt-mode))
+      ("srt" (subed-srt-mode))
+      ("ass" (subed-ass-mode)))))
 
 (provide 'subed)
 ;;; subed.el ends here
diff --git a/tests/test-subed-ass.el b/tests/test-subed-ass.el
index 8e79522500..cd8cee4571 100644
--- a/tests/test-subed-ass.el
+++ b/tests/test-subed-ass.el
@@ -1,7 +1,8 @@
 ;; -*- eval: (buttercup-minor-mode) -*-
 
-(add-to-list 'load-path "./subed")
+(load-file "./tests/undercover-init.el")
 (require 'subed)
+(require 'subed-ass)
 
 (defvar mock-ass-data
   "[Script Info]
@@ -23,9 +24,9 @@ Dialogue: 0,0:00:17.00,0:00:19.80,Default,,0,0,0,,I hope it 
works.
 ")
 
 (defmacro with-temp-ass-buffer (&rest body)
-  "Call `subed-ass--init' in temporary buffer before running BODY."
+  "Initialize temporary buffer with `subed-ass-mode' and run BODY."
   `(with-temp-buffer
-     (subed-ass--init)
+     (subed-ass-mode)
      (progn ,@body)))
 
 (describe "ASS"
@@ -34,63 +35,63 @@ Dialogue: 0,0:00:17.00,0:00:19.80,Default,,0,0,0,,I hope it 
works.
       (it "returns the time in milliseconds."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "0:00:14.00")
-         (expect (subed-ass--subtitle-msecs-start) :to-equal (* 14 1000))
-         (expect (subed-ass--subtitle-msecs-stop) :to-equal (+ (* 16 1000) 
800))))
+         (subed-jump-to-subtitle-id "0:00:14.00")
+         (expect (subed-subtitle-msecs-start) :to-equal (* 14 1000))
+         (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 16 1000) 800))))
       (it "returns nil if time can't be found."
         (with-temp-ass-buffer
-         (expect (subed-ass--subtitle-msecs-start) :to-be nil)
-         (expect (subed-ass--subtitle-msecs-stop) :to-be nil)))
+         (expect (subed-subtitle-msecs-start) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be nil)))
       )
     (describe "the subtitle text"
       (describe "when text is empty"
         (it "and at the beginning with a trailing newline."
           (with-temp-ass-buffer
            (insert mock-ass-data)
-           (subed-ass--jump-to-subtitle-text "0:00:11.12")
+           (subed-jump-to-subtitle-text "0:00:11.12")
            (kill-line)
-           (expect (subed-ass--subtitle-text) :to-equal "")))))
+           (expect (subed-subtitle-text) :to-equal "")))))
     (describe "when text is not empty"
       (it "and has no linebreaks."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "0:00:14.00")
-         (expect (subed-ass--subtitle-text) :to-equal "This is a test.")))))
+         (subed-jump-to-subtitle-text "0:00:14.00")
+         (expect (subed-subtitle-text) :to-equal "This is a test.")))))
   (describe "Jumping"
     (describe "to current subtitle timestamp"
       (it "can handle different formats of timestamps."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (expect (subed-ass--jump-to-subtitle-id "00:00:11.120") :to-equal 564)
-         (expect (subed-ass--subtitle-msecs-start) :to-equal 11120)))
+         (expect (subed-jump-to-subtitle-id "00:00:11.120") :to-equal 564)
+         (expect (subed-subtitle-msecs-start) :to-equal 11120)))
       (it "returns timestamp's point when point is already on the timestamp."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (subed-ass--jump-to-subtitle-id "0:00:11.12")
-         (expect (subed-ass--jump-to-subtitle-time-start) :to-equal (point))
-         (expect (looking-at subed-ass--regexp-timestamp) :to-be t)
+         (subed-jump-to-subtitle-id "0:00:11.12")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal (point))
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "0:00:11.12")))
       (it "returns timestamp's point when point is on the text."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (search-backward "test")
          (expect (thing-at-point 'word) :to-equal "test")
-         (expect (subed-ass--jump-to-subtitle-time-start) :to-equal 640)
-         (expect (looking-at subed-ass--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 640)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "0:00:14.00")))
       (it "returns nil if buffer is empty."
         (with-temp-ass-buffer
          (expect (buffer-string) :to-equal "")
-         (expect (subed-ass--jump-to-subtitle-time-start) :to-equal nil))))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil))))
     (describe "to specific subtitle by timestamp"
       (it "returns timestamp's point if wanted time exists."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-max))
-         (expect (subed-ass--jump-to-subtitle-id "0:00:11.12") :to-equal 564)
+         (expect (subed-jump-to-subtitle-id "0:00:11.12") :to-equal 564)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:11.12")) :to-be t)
-         (expect (subed-ass--jump-to-subtitle-id "0:00:17.00") :to-equal 694)
+         (expect (subed-jump-to-subtitle-id "0:00:17.00") :to-equal 694)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:17.00")) :to-be 
t)))
       (it "returns nil and does not move if wanted ID does not exists."
         (with-temp-ass-buffer
@@ -98,237 +99,237 @@ Dialogue: 0,0:00:17.00,0:00:19.80,Default,,0,0,0,,I hope 
it works.
          (goto-char (point-min))
          (search-forward "test")
          (let ((stored-point (point)))
-           (expect (subed-ass--jump-to-subtitle-id "0:08:00") :to-equal nil)
+           (expect (subed-jump-to-subtitle-id "0:08:00") :to-equal nil)
            (expect stored-point :to-equal (point))))))
     (describe "to subtitle start time"
       (it "returns start time's point if movement was successful."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (re-search-backward "world")
-         (expect (subed-ass--jump-to-subtitle-time-start) :to-equal 576)
-         (expect (looking-at subed-ass--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 576)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "0:00:11.12")))
       (it "returns nil if movement failed."
         (with-temp-ass-buffer
-         (expect (subed-ass--jump-to-subtitle-time-start) :to-equal nil))))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil))))
     (describe "to subtitle stop time"
       (it "returns stop time's point if movement was successful."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (re-search-backward "test")
-         (expect (subed-ass--jump-to-subtitle-time-stop) :to-equal 651)
-         (expect (looking-at subed-ass--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 651)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "0:00:16.80")))
       (it "returns nil if movement failed."
         (with-temp-ass-buffer
-         (expect (subed-ass--jump-to-subtitle-time-stop) :to-equal nil))))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil))))
     (describe "to subtitle text"
       (it "returns subtitle text's point if movement was successful."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (expect (subed-ass--jump-to-subtitle-text) :to-equal 614)
+         (expect (subed-jump-to-subtitle-text) :to-equal 614)
          (expect (looking-at "Hello, world!") :to-equal t)
          (forward-line 1)
-         (expect (subed-ass--jump-to-subtitle-text) :to-equal 678)
+         (expect (subed-jump-to-subtitle-text) :to-equal 678)
          (expect (looking-at "This is a test.") :to-equal t)))
       (it "returns nil if movement failed."
         (with-temp-ass-buffer
-         (expect (subed-ass--jump-to-subtitle-time-stop) :to-equal nil))))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil))))
     (describe "to end of subtitle text"
       (it "returns point if subtitle end can be found."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (expect (subed-ass--jump-to-subtitle-end) :to-be 627)
+         (expect (subed-jump-to-subtitle-end) :to-be 627)
          (expect (looking-back "Hello, world!") :to-be t)
          (forward-char 2)
-         (expect (subed-ass--jump-to-subtitle-end) :to-be 693)
+         (expect (subed-jump-to-subtitle-end) :to-be 693)
          (expect (looking-back "This is a test.") :to-be t)
          (forward-char 2)
-         (expect (subed-ass--jump-to-subtitle-end) :to-be 760)
+         (expect (subed-jump-to-subtitle-end) :to-be 760)
          (expect (looking-back "I hope it works.") :to-be t)))
       (it "returns nil if subtitle end cannot be found."
         (with-temp-ass-buffer
-         (expect (subed-ass--jump-to-subtitle-end) :to-be nil)))
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
       (it "returns nil if point did not move."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "0:00:11.12")
-         (subed-ass--jump-to-subtitle-end)
-         (expect (subed-ass--jump-to-subtitle-end) :to-be nil)))
+         (subed-jump-to-subtitle-text "0:00:11.12")
+         (subed-jump-to-subtitle-end)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
       (it "works if text is empty."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "00:00:11.12")
+         (subed-jump-to-subtitle-text "00:00:11.12")
          (kill-line)
          (backward-char)
-         (expect (subed-ass--jump-to-subtitle-end) :to-be 614))))
+         (expect (subed-jump-to-subtitle-end) :to-be 614))))
     (describe "to next subtitle ID"
       (it "returns point when there is a next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:11.12")
-         (expect (subed-ass--forward-subtitle-id) :to-be 628)
+         (subed-jump-to-subtitle-id "00:00:11.12")
+         (expect (subed-forward-subtitle-id) :to-be 628)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:14.00")) :to-be 
t)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-ass-buffer
          (expect (thing-at-point 'word) :to-equal nil)
-         (expect (subed-ass--forward-subtitle-id) :to-be nil))
+         (expect (subed-forward-subtitle-id) :to-be nil))
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "0:00:17.00")
-         (expect (subed-ass--forward-subtitle-id) :to-be nil))))
+         (subed-jump-to-subtitle-text "0:00:17.00")
+         (expect (subed-forward-subtitle-id) :to-be nil))))
     (describe "to previous subtitle ID"
       (it "returns point when there is a previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "00:00:14.00")
-         (expect (subed-ass--backward-subtitle-id) :to-be 564)))
+         (subed-jump-to-subtitle-text "00:00:14.00")
+         (expect (subed-backward-subtitle-id) :to-be 564)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-ass-buffer
-         (expect (subed-ass--backward-subtitle-id) :to-be nil))
+         (expect (subed-backward-subtitle-id) :to-be nil))
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:11.12")
-         (expect (subed-ass--backward-subtitle-id) :to-be nil))))
+         (subed-jump-to-subtitle-id "00:00:11.12")
+         (expect (subed-backward-subtitle-id) :to-be nil))))
     (describe "to next subtitle text"
       (it "returns point when there is a next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--forward-subtitle-text) :to-be 744)
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-forward-subtitle-text) :to-be 744)
          (expect (thing-at-point 'word) :to-equal "I")))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-ass-buffer
          (goto-char (point-max))
          (insert (concat mock-ass-data "\n\n"))
-         (subed-ass--jump-to-subtitle-id "00:00:17.00")
-         (expect (subed-ass--forward-subtitle-text) :to-be nil))))
+         (subed-jump-to-subtitle-id "00:00:17.00")
+         (expect (subed-forward-subtitle-text) :to-be nil))))
     (describe "to previous subtitle text"
       (it "returns point when there is a previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--backward-subtitle-text) :to-be 614)
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-backward-subtitle-text) :to-be 614)
          (expect (thing-at-point 'word) :to-equal "Hello")))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (subed-ass--forward-subtitle-time-start)
+         (subed-forward-subtitle-time-start)
          (expect (looking-at (regexp-quote "0:00:11.12")) :to-be t)
-         (expect (subed-ass--backward-subtitle-text) :to-be nil)
+         (expect (subed-backward-subtitle-text) :to-be nil)
          (expect (looking-at (regexp-quote "0:00:11.12")) :to-be t))))
     (describe "to next subtitle end"
       (it "returns point when there is a next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-text "00:00:14.00")
+         (subed-jump-to-subtitle-text "00:00:14.00")
          (expect (thing-at-point 'word) :to-equal "This")
-         (expect (subed-ass--forward-subtitle-end) :to-be 760)))
+         (expect (subed-forward-subtitle-end) :to-be 760)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-ass-buffer
          (insert (concat mock-ass-data "\n\n"))
-         (subed-ass--jump-to-subtitle-text "00:00:17.00")
-         (expect (subed-ass--forward-subtitle-end) :to-be nil))))
+         (subed-jump-to-subtitle-text "00:00:17.00")
+         (expect (subed-forward-subtitle-end) :to-be nil))))
     (describe "to previous subtitle end"
       (it "returns point when there is a previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--backward-subtitle-end) :to-be 627)))
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-backward-subtitle-end) :to-be 627)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (subed-ass--forward-subtitle-id)
+         (subed-forward-subtitle-id)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:11.12")) :to-be t)
-         (expect (subed-ass--backward-subtitle-text) :to-be nil)
+         (expect (subed-backward-subtitle-text) :to-be nil)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:11.12")) :to-be 
t))))
     (describe "to next subtitle start time"
       (it "returns point when there is a next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--forward-subtitle-time-start) :to-be 706)))
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-forward-subtitle-time-start) :to-be 706)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:17.00")
+         (subed-jump-to-subtitle-id "00:00:17.00")
          (let ((pos (point)))
-           (expect (subed-ass--forward-subtitle-time-start) :to-be nil)
+           (expect (subed-forward-subtitle-time-start) :to-be nil)
            (expect (point) :to-be pos)))))
     (describe "to previous subtitle stop"
       (it "returns point when there is a previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--backward-subtitle-time-stop) :to-be 587)))
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-backward-subtitle-time-stop) :to-be 587)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
          (goto-char (point-min))
-         (subed-ass--forward-subtitle-id)
-         (expect (subed-ass--backward-subtitle-time-stop) :to-be nil)
+         (subed-forward-subtitle-id)
+         (expect (subed-backward-subtitle-time-stop) :to-be nil)
          (expect (looking-at (regexp-quote "Dialogue: 0,0:00:11.12")) :to-be 
t))))
     (describe "to next subtitle stop time"
       (it "returns point when there is a next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:14.00")
-         (expect (subed-ass--forward-subtitle-time-stop) :to-be 717)))
+         (subed-jump-to-subtitle-id "00:00:14.00")
+         (expect (subed-forward-subtitle-time-stop) :to-be 717)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-ass-buffer
          (insert mock-ass-data)
-         (subed-ass--jump-to-subtitle-id "00:00:17.00")
+         (subed-jump-to-subtitle-id "00:00:17.00")
          (let ((pos (point)))
-           (expect (subed-ass--forward-subtitle-time-stop) :to-be nil)
+           (expect (subed-forward-subtitle-time-stop) :to-be nil)
            (expect (point) :to-be pos))))))
 
   (describe "Setting start/stop time"
     (it "of subtitle should set it."
       (with-temp-ass-buffer
        (insert mock-ass-data)
-       (subed-ass--jump-to-subtitle-id "00:00:14.00")
-       (subed-ass--set-subtitle-time-start (+ (* 15 1000) 400))
-       (expect (subed-ass--subtitle-msecs-start) :to-be (+ (* 15 1000) 400)))))
+       (subed-jump-to-subtitle-id "00:00:14.00")
+       (subed-set-subtitle-time-start (+ (* 15 1000) 400))
+       (expect (subed-subtitle-msecs-start) :to-be (+ (* 15 1000) 400)))))
 
   (describe "Inserting a subtitle"
     (describe "in an empty buffer"
       (describe "before the current subtitle"
         (it "creates an empty subtitle when passed nothing."
           (with-temp-ass-buffer
-           (subed-ass--prepend-subtitle)
+           (subed-prepend-subtitle)
            (expect (buffer-string) :to-equal (concat "Dialogue: 
0,0:00:00.00,0:00:01.00,Default,,0,0,0,,\n"))))
         (it "creates a subtitle with a start time."
           (with-temp-ass-buffer
-           (subed-ass--prepend-subtitle nil 12340)
+           (subed-prepend-subtitle nil 12340)
            (expect (buffer-string) :to-equal (concat "Dialogue: 
0,0:00:12.34,0:00:13.34,Default,,0,0,0,,\n"))))
         (it "creates a subtitle with a start time and stop time."
           (with-temp-ass-buffer
-           (subed-ass--prepend-subtitle nil 60000 65000) 
+           (subed-prepend-subtitle nil 60000 65000) 
            (expect (buffer-string) :to-equal "Dialogue: 
0,0:01:00.00,0:01:05.00,Default,,0,0,0,,\n")))
         (it "creates a subtitle with start time, stop time and text."
           (with-temp-ass-buffer
-           (subed-ass--prepend-subtitle nil 60000 65000 "Hello world")
+           (subed-prepend-subtitle nil 60000 65000 "Hello world")
            (expect (buffer-string) :to-equal "Dialogue: 
0,0:01:00.00,0:01:05.00,Default,,0,0,0,,Hello world\n"))))
       (describe "after the current subtitle"
         (it "creates an empty subtitle when passed nothing."
           (with-temp-ass-buffer
-           (subed-ass--append-subtitle)
+           (subed-append-subtitle)
            (expect (buffer-string) :to-equal (concat "Dialogue: 
0,0:00:00.00,0:00:01.00,Default,,0,0,0,,\n"))))
         (it "creates a subtitle with a start time."
           (with-temp-ass-buffer
-           (subed-ass--append-subtitle nil 12340)
+           (subed-append-subtitle nil 12340)
            (expect (buffer-string) :to-equal (concat "Dialogue: 
0,0:00:12.34,0:00:13.34,Default,,0,0,0,,\n"))))
         (it "creates a subtitle with a start time and stop time."
           (with-temp-ass-buffer
-           (subed-ass--append-subtitle nil 60000 65000) 
+           (subed-append-subtitle nil 60000 65000) 
            (expect (buffer-string) :to-equal "Dialogue: 
0,0:01:00.00,0:01:05.00,Default,,0,0,0,,\n")))
         (it "creates a subtitle with start time, stop time and text."
           (with-temp-ass-buffer
-           (subed-ass--append-subtitle nil 60000 65000 "Hello world")
+           (subed-append-subtitle nil 60000 65000 "Hello world")
            (expect (buffer-string) :to-equal "Dialogue: 
0,0:01:00.00,0:01:05.00,Default,,0,0,0,,Hello world\n"))))))
   (describe "in a non-empty buffer"
     (describe "before the current subtitle"
@@ -336,16 +337,16 @@ Dialogue: 0,0:00:17.00,0:00:19.80,Default,,0,0,0,,I hope 
it works.
         (it "creates the subtitle before the current one."
           (with-temp-ass-buffer
            (insert mock-ass-data)
-           (subed-ass--jump-to-subtitle-time-stop)
-           (subed-ass--prepend-subtitle)
+           (subed-jump-to-subtitle-time-stop)
+           (subed-prepend-subtitle)
            (expect (buffer-substring (line-beginning-position) 
(line-end-position))
                    :to-equal (concat "Dialogue: 
0,0:00:00.00,0:00:01.00,Default,,0,0,0,,")))))
       (describe "with point on a middle subtitle"
         (it "creates the subtitle before the current one."
           (with-temp-ass-buffer
            (insert mock-ass-data)
-           (subed-ass--jump-to-subtitle-time-stop "0:00:14.00")
-           (subed-ass--prepend-subtitle)
+           (subed-jump-to-subtitle-time-stop "0:00:14.00")
+           (subed-prepend-subtitle)
            (expect (buffer-substring (line-beginning-position) 
(line-end-position))
                    :to-equal (concat "Dialogue: 
0,0:00:00.00,0:00:01.00,Default,,0,0,0,,"))
            (forward-line 1)
@@ -357,35 +358,35 @@ Dialogue: 0,0:00:17.00,0:00:19.80,Default,,0,0,0,,I hope 
it works.
         (it "creates the subtitle after the current one."
           (with-temp-ass-buffer
            (insert mock-ass-data)
-           (subed-ass--jump-to-subtitle-time-stop "0:00:14.00")
-           (subed-ass--append-subtitle)
+           (subed-jump-to-subtitle-time-stop "0:00:14.00")
+           (subed-append-subtitle)
            (expect (buffer-substring (line-beginning-position) 
(line-end-position))
                    :to-equal (concat "Dialogue: 
0,0:00:00.00,0:00:01.00,Default,,0,0,0,,"))
            (forward-line -1)
-           (expect (subed-ass--subtitle-msecs-start) :to-be 14000))))))
+           (expect (subed-subtitle-msecs-start) :to-be 14000))))))
   (describe "Killing a subtitle"
     (it "removes the first subtitle."
       (with-temp-ass-buffer
        (insert mock-ass-data)
-       (subed-ass--jump-to-subtitle-text "0:00:11.12")
-       (subed-ass--kill-subtitle)
-       (expect (subed-ass--subtitle-msecs-start) :to-be 14000)
+       (subed-jump-to-subtitle-text "0:00:11.12")
+       (subed-kill-subtitle)
+       (expect (subed-subtitle-msecs-start) :to-be 14000)
        (forward-line -1)
        (beginning-of-line)
        (expect (looking-at "Format: Layer")))))
   (it "removes it in between."
     (with-temp-ass-buffer
      (insert mock-ass-data)
-     (subed-ass--jump-to-subtitle-text "00:00:14.00")
-     (subed-ass--kill-subtitle)
-     (expect (subed-ass--subtitle-msecs-start) :to-be 17000)))
+     (subed-jump-to-subtitle-text "00:00:14.00")
+     (subed-kill-subtitle)
+     (expect (subed-subtitle-msecs-start) :to-be 17000)))
   (it "removes the last subtitle."
     (with-temp-ass-buffer
      (insert mock-ass-data)
-     (subed-ass--jump-to-subtitle-text "00:00:17.00")
-     (subed-ass--kill-subtitle)
-     (expect (subed-ass--subtitle-msecs-start) :to-be 14000)))
+     (subed-jump-to-subtitle-text "00:00:17.00")
+     (subed-kill-subtitle)
+     (expect (subed-subtitle-msecs-start) :to-be 14000)))
   (describe "Converting msecs to timestamp"
     (it "uses the right format"
       (with-temp-ass-buffer
-       (expect (subed-ass--msecs-to-timestamp 1410) :to-equal "0:00:01.41")))))
+       (expect (subed-msecs-to-timestamp 1410) :to-equal "0:00:01.41")))))
diff --git a/tests/test-subed-common.el b/tests/test-subed-common.el
index 83fcb168e4..5b868dcfb2 100644
--- a/tests/test-subed-common.el
+++ b/tests/test-subed-common.el
@@ -1,7 +1,6 @@
 ;; -*- lexical-binding: t; eval: (buttercup-minor-mode) -*-
 
-(add-to-list 'load-path "./subed")
-(require 'subed)
+(load-file "./tests/undercover-init.el")
 (require 'subed-srt)
 
 (defvar mock-srt-data
@@ -24,2128 +23,2141 @@ Baz.
   `(with-temp-buffer
      ;; subed--init uses file extension to detect format
      (setq buffer-file-name "test.srt")
-     (subed--init)
+     (subed-srt-mode)
      (progn ,@body)))
 
-(describe "Iterating over subtitles"
-  (it "without providing beginning and end."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-time-stop 1)
-      (subed-for-each-subtitle nil nil nil
-        (expect (looking-at "^[0-9]$") :to-be t)
-        (forward-line 2)
-        (kill-line)
-        (insert "Hello."))
-      (expect (subed-subtitle-text 1) :to-equal "Hello.")
-      (expect (subed-subtitle-text 2) :to-equal "Bar.")
-      (expect (subed-subtitle-text 3) :to-equal "Baz.")
-      (expect (point) :to-equal 20)
-      (subed-jump-to-subtitle-time-stop 2)
-      (subed-for-each-subtitle nil nil nil
-        (expect (looking-at "^[0-9]$") :to-be t)
-        (forward-line 2)
-        (kill-line)
-        (insert "HEllo."))
-      (expect (subed-subtitle-text 1) :to-equal "Hello.")
-      (expect (subed-subtitle-text 2) :to-equal "HEllo.")
-      (expect (subed-subtitle-text 3) :to-equal "Baz.")
-      (expect (point) :to-equal 60)
-      (subed-jump-to-subtitle-time-stop 3)
-      (subed-for-each-subtitle nil nil nil
-        (expect (looking-at "^[0-9]$") :to-be t)
-        (forward-line 2)
-        (kill-line)
-        (insert "HELlo."))
-      (expect (subed-subtitle-text 1) :to-equal "Hello.")
-      (expect (subed-subtitle-text 2) :to-equal "HEllo.")
-      (expect (subed-subtitle-text 3) :to-equal "HELlo.")
-      (expect (point) :to-equal 99)))
-  (describe "providing only the beginning"
-    (it "forwards."
+(describe "COMMON"
+  (describe "Iterating over subtitles"
+    (it "without providing beginning and end."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-time-start 1)
-        (expect (point) :to-equal 3)
-        (let ((new-texts (list "A" "B" "C")))
-          (subed-for-each-subtitle 71 nil nil
-            (expect (looking-at "^[0-9]$") :to-be t)
-            (forward-line 2)
-            (kill-line)
-            (insert (pop new-texts))))
-        (expect (subed-subtitle-text 1) :to-equal "Foo.")
-        (expect (subed-subtitle-text 2) :to-equal "A")
-        (expect (subed-subtitle-text 3) :to-equal "B")
-        (expect (point) :to-equal 3)))
-    (it "backwards."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-time-stop 3)
-        (expect (point) :to-equal 95)
-        (let ((new-texts (list "A" "B" "C")))
-          (subed-for-each-subtitle 75 nil :reverse
-            (expect (looking-at "^[0-9]$") :to-be t)
-            (forward-line 2)
-            (kill-line)
-            (insert (pop new-texts))))
-        (expect (subed-subtitle-text 1) :to-equal "Foo.")
-        (expect (subed-subtitle-text 2) :to-equal "B")
-        (expect (subed-subtitle-text 3) :to-equal "A")
-        (expect (point) :to-equal 92)))
-    )
-  (describe "providing beginning and end,"
-    (describe "excluding subtitles above"
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 1)
+       (subed-for-each-subtitle nil nil nil
+         (expect (looking-at "^[0-9]$") :to-be t)
+         (forward-line 2)
+         (kill-line)
+         (insert "Hello."))
+       (expect (subed-subtitle-text 1) :to-equal "Hello.")
+       (expect (subed-subtitle-text 2) :to-equal "Bar.")
+       (expect (subed-subtitle-text 3) :to-equal "Baz.")
+       (expect (point) :to-equal 20)
+       (subed-jump-to-subtitle-time-stop 2)
+       (subed-for-each-subtitle nil nil nil
+         (expect (looking-at "^[0-9]$") :to-be t)
+         (forward-line 2)
+         (kill-line)
+         (insert "HEllo."))
+       (expect (subed-subtitle-text 1) :to-equal "Hello.")
+       (expect (subed-subtitle-text 2) :to-equal "HEllo.")
+       (expect (subed-subtitle-text 3) :to-equal "Baz.")
+       (expect (point) :to-equal 60)
+       (subed-jump-to-subtitle-time-stop 3)
+       (subed-for-each-subtitle nil nil nil
+         (expect (looking-at "^[0-9]$") :to-be t)
+         (forward-line 2)
+         (kill-line)
+         (insert "HELlo."))
+       (expect (subed-subtitle-text 1) :to-equal "Hello.")
+       (expect (subed-subtitle-text 2) :to-equal "HEllo.")
+       (expect (subed-subtitle-text 3) :to-equal "HELlo.")
+       (expect (point) :to-equal 99)))
+    (describe "providing only the beginning"
       (it "forwards."
         (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-time-stop 1)
-          (expect (point) :to-equal 20)
-          (let ((new-texts (list "A" "B" "C")))
-            (subed-for-each-subtitle 71 79 nil
-              (expect (looking-at "^[0-9]$") :to-be t)
-              (forward-line 2)
-              (kill-line)
-              (insert (pop new-texts))))
-          (expect (subed-subtitle-text 1) :to-equal "Foo.")
-          (expect (subed-subtitle-text 2) :to-equal "A")
-          (expect (subed-subtitle-text 3) :to-equal "B")
-          (expect (point) :to-equal 20)))
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-time-start 1)
+         (expect (point) :to-equal 3)
+         (let ((new-texts (list "A" "B" "C")))
+           (subed-for-each-subtitle 71 nil nil
+             (expect (looking-at "^[0-9]$") :to-be t)
+             (forward-line 2)
+             (kill-line)
+             (insert (pop new-texts))))
+         (expect (subed-subtitle-text 1) :to-equal "Foo.")
+         (expect (subed-subtitle-text 2) :to-equal "A")
+         (expect (subed-subtitle-text 3) :to-equal "B")
+         (expect (point) :to-equal 3)))
       (it "backwards."
         (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-time-start 3)
-          (expect (point) :to-equal 79)
-          (let ((new-texts (list "A" "B" "C")))
-            (subed-for-each-subtitle 39 77 :reverse
-              (expect (looking-at "^[0-9]$") :to-be t)
-              (forward-line 2)
-              (kill-line)
-              (insert (pop new-texts))))
-          (expect (subed-subtitle-text 1) :to-equal "Foo.")
-          (expect (subed-subtitle-text 2) :to-equal "B")
-          (expect (subed-subtitle-text 3) :to-equal "A")
-          (expect (point) :to-equal 76)))
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-time-stop 3)
+         (expect (point) :to-equal 95)
+         (let ((new-texts (list "A" "B" "C")))
+           (subed-for-each-subtitle 75 nil :reverse
+             (expect (looking-at "^[0-9]$") :to-be t)
+             (forward-line 2)
+             (kill-line)
+             (insert (pop new-texts))))
+         (expect (subed-subtitle-text 1) :to-equal "Foo.")
+         (expect (subed-subtitle-text 2) :to-equal "B")
+         (expect (subed-subtitle-text 3) :to-equal "A")
+         (expect (point) :to-equal 92)))
       )
-    (describe "excluding subtitles below"
-      (it "forwards."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-text 3)
-          (expect (point) :to-equal 106)
-          (let ((new-texts (list "A" "B" "C")))
-            (subed-for-each-subtitle 5 76 nil
-              (expect (looking-at "^[0-9]$") :to-be t)
-              (forward-line 2)
-              (kill-line)
-              (insert (pop new-texts))))
-          (expect (subed-subtitle-text 1) :to-equal "A")
-          (expect (subed-subtitle-text 2) :to-equal "B")
-          (expect (subed-subtitle-text 3) :to-equal "Baz.")
-          (expect (point) :to-equal 100)))
-      (it "backwards."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-jump-to-subtitle-time-stop 2)
-          (expect (point) :to-equal 58)
-          (let ((new-texts (list "A" "B" "C")))
-            (subed-for-each-subtitle 20 76 :reverse
-              (expect (looking-at "^[0-9]$") :to-be t)
-              (forward-line 2)
-              (kill-line)
-              (insert (pop new-texts))))
-          (expect (subed-subtitle-text 1) :to-equal "B")
-          (expect (subed-subtitle-text 2) :to-equal "A")
-          (expect (subed-subtitle-text 3) :to-equal "Baz.")
-          (expect (point) :to-equal 55)))
+    (describe "providing beginning and end,"
+      (describe "excluding subtitles above"
+        (it "forwards."
+          (with-temp-srt-buffer
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-time-stop 1)
+           (expect (point) :to-equal 20)
+           (let ((new-texts (list "A" "B" "C")))
+             (subed-for-each-subtitle 71 79 nil
+               (expect (looking-at "^[0-9]$") :to-be t)
+               (forward-line 2)
+               (kill-line)
+               (insert (pop new-texts))))
+           (expect (subed-subtitle-text 1) :to-equal "Foo.")
+           (expect (subed-subtitle-text 2) :to-equal "A")
+           (expect (subed-subtitle-text 3) :to-equal "B")
+           (expect (point) :to-equal 20)))
+        (it "backwards."
+          (with-temp-srt-buffer
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-time-start 3)
+           (expect (point) :to-equal 79)
+           (let ((new-texts (list "A" "B" "C")))
+             (subed-for-each-subtitle 39 77 :reverse
+               (expect (looking-at "^[0-9]$") :to-be t)
+               (forward-line 2)
+               (kill-line)
+               (insert (pop new-texts))))
+           (expect (subed-subtitle-text 1) :to-equal "Foo.")
+           (expect (subed-subtitle-text 2) :to-equal "B")
+           (expect (subed-subtitle-text 3) :to-equal "A")
+           (expect (point) :to-equal 76)))
+        )
+      (describe "excluding subtitles below"
+        (it "forwards."
+          (with-temp-srt-buffer
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 3)
+           (expect (point) :to-equal 106)
+           (let ((new-texts (list "A" "B" "C")))
+             (subed-for-each-subtitle 5 76 nil
+               (expect (looking-at "^[0-9]$") :to-be t)
+               (forward-line 2)
+               (kill-line)
+               (insert (pop new-texts))))
+           (expect (subed-subtitle-text 1) :to-equal "A")
+           (expect (subed-subtitle-text 2) :to-equal "B")
+           (expect (subed-subtitle-text 3) :to-equal "Baz.")
+           (expect (point) :to-equal 100)))
+        (it "backwards."
+          (with-temp-srt-buffer
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-time-stop 2)
+           (expect (point) :to-equal 58)
+           (let ((new-texts (list "A" "B" "C")))
+             (subed-for-each-subtitle 20 76 :reverse
+               (expect (looking-at "^[0-9]$") :to-be t)
+               (forward-line 2)
+               (kill-line)
+               (insert (pop new-texts))))
+           (expect (subed-subtitle-text 1) :to-equal "B")
+           (expect (subed-subtitle-text 2) :to-equal "A")
+           (expect (subed-subtitle-text 3) :to-equal "Baz.")
+           (expect (point) :to-equal 55)))
+        )
       )
     )
-  )
 
-(describe "Adjusting subtitle start/stop time"
-  :var (subed-subtitle-time-adjusted-hook)
-  (it "runs the appropriate hook."
-    (let ((foo (setf (symbol-function 'foo) (lambda (msecs) ()))))
-      (spy-on 'foo)
+  (describe "Adjusting subtitle start/stop time"
+    :var (subed-subtitle-time-adjusted-hook)
+    (it "runs the appropriate hook."
+      (let ((foo (setf (symbol-function 'foo) (lambda (msecs) ()))))
+        (spy-on 'foo)
+        (with-temp-srt-buffer
+         (add-hook 'subed-subtitle-time-adjusted-hook 'foo)
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (subed-adjust-subtitle-time-start 100) :to-equal 100)
+         (expect 'foo :to-have-been-called-with 61100)
+         (expect 'foo :to-have-been-called-times 1)
+         (expect (subed-adjust-subtitle-time-stop 123) :to-equal 123)
+         (expect 'foo :to-have-been-called-with 61100)
+         (expect 'foo :to-have-been-called-times 2)
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-start 6) :to-equal 6)
+         (expect 'foo :to-have-been-called-with 122240)
+         (expect 'foo :to-have-been-called-times 3)
+         (expect (subed-adjust-subtitle-time-stop 123) :to-equal 123)
+         (expect 'foo :to-have-been-called-with 122240)
+         (expect 'foo :to-have-been-called-times 4))))
+    (it "adjusts the start/stop time."
       (with-temp-srt-buffer
-        (add-hook 'subed-subtitle-time-adjusted-hook 'foo)
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 1)
-        (expect (subed-adjust-subtitle-time-start 100) :to-equal 100)
-        (expect 'foo :to-have-been-called-with 61100)
-        (expect 'foo :to-have-been-called-times 1)
-        (expect (subed-adjust-subtitle-time-stop 123) :to-equal 123)
-        (expect 'foo :to-have-been-called-with 61100)
-        (expect 'foo :to-have-been-called-times 2)
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-start 6) :to-equal 6)
-        (expect 'foo :to-have-been-called-with 122240)
-        (expect 'foo :to-have-been-called-times 3)
-        (expect (subed-adjust-subtitle-time-stop 123) :to-equal 123)
-        (expect 'foo :to-have-been-called-with 122240)
-        (expect 'foo :to-have-been-called-times 4))))
-  (it "adjusts the start/stop time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-id 1)
-      (expect (subed-adjust-subtitle-time-start 100) :to-equal 100)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "00:01:01,100 
--> 00:01:05,123\n")
-      (expect (subed-adjust-subtitle-time-start -200) :to-equal -200)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,123\n")
-      (expect (subed-adjust-subtitle-time-stop 200) :to-equal 200)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,323\n")
-      (expect (subed-adjust-subtitle-time-stop -100) :to-equal -100)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,223\n")))
-  (describe "enforces boundaries"
-    (describe "when decreasing start time"
-      (it "of the first subtitle."
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 1)
+       (expect (subed-adjust-subtitle-time-start 100) :to-equal 100)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "00:01:01,100 
--> 00:01:05,123\n")
+       (expect (subed-adjust-subtitle-time-start -200) :to-equal -200)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,123\n")
+       (expect (subed-adjust-subtitle-time-stop 200) :to-equal 200)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,323\n")
+       (expect (subed-adjust-subtitle-time-stop -100) :to-equal -100)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "00:01:00,900 
--> 00:01:05,223\n")))
+    (describe "enforces boundaries"
+      (describe "when decreasing start time"
+        (it "of the first subtitle."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n"))
+           (expect (subed-adjust-subtitle-time-start -999) :to-be -999)
+           (expect (subed-subtitle-msecs-start) :to-be 1)
+           (expect (subed-adjust-subtitle-time-start -1) :to-be -1)
+           (expect (subed-subtitle-msecs-start) :to-be 0)
+           (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
+           (expect (subed-subtitle-msecs-start) :to-be 0)))
+        (it "of a non-first subtitle."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n\n"
+                           "2\n"
+                           "00:00:03,000 --> 00:00:04,000\n"
+                           "Bar.\n\n"))
+           (subed-jump-to-subtitle-id 2)
+           (expect (subed-adjust-subtitle-time-start -899) :to-be -899)
+           (expect (subed-subtitle-msecs-start) :to-be 2101)
+           (expect (subed-adjust-subtitle-time-start -1) :to-be -1)
+           (expect (subed-subtitle-msecs-start) :to-be 2100)
+           (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
+           (expect (subed-subtitle-msecs-start) :to-be 2100)))
+        )
+      (it "when increasing start time."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:03,000 --> 00:00:04,000\n"
+                         "Bar.\n\n"))
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-start 999) :to-be 999)
+         (expect (subed-subtitle-msecs-start) :to-be 3999)
+         (expect (subed-adjust-subtitle-time-start 1) :to-be 1)
+         (expect (subed-subtitle-msecs-start) :to-be 4000)
+         (expect (subed-adjust-subtitle-time-start 1) :to-be nil)
+         (expect (subed-subtitle-msecs-start) :to-be 4000)))
+      (it "when decreasing stop time."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:03,000 --> 00:00:04,000\n"
+                         "Bar.\n\n"))
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-stop -999) :to-be -999)
+         (expect (subed-subtitle-msecs-stop) :to-be 3001)
+         (expect (subed-adjust-subtitle-time-stop -1) :to-be -1)
+         (expect (subed-subtitle-msecs-stop) :to-be 3000)
+         (expect (subed-adjust-subtitle-time-stop -1) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be 3000)))
+      (describe "when increasing stop time"
+        (it "of the last subtitle."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n\n"
+                           "2\n"
+                           "00:00:03,000 --> 00:00:04,000\n"
+                           "Bar.\n\n"))
+           (subed-jump-to-subtitle-id 2)
+           (expect (subed-adjust-subtitle-time-stop 1000000):to-be 1000000)
+           (expect (subed-subtitle-msecs-stop) :to-be 1004000)))
+        (it "of a non-last subtitle."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n\n"
+                           "2\n"
+                           "00:00:03,000 --> 00:00:04,000\n"
+                           "Bar.\n\n"))
+           (subed-jump-to-subtitle-id 1)
+           (expect (subed-adjust-subtitle-time-stop 899) :to-be 899)
+           (expect (subed-subtitle-msecs-stop) :to-be 2899)
+           (expect (subed-adjust-subtitle-time-stop 1) :to-be 1)
+           (expect (subed-subtitle-msecs-stop) :to-be 2900)
+           (expect (subed-adjust-subtitle-time-stop 1) :to-be nil)
+           (expect (subed-subtitle-msecs-stop) :to-be 2900)))
+        )
+      (it "without undershooting the target time."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n"))
-          (expect (subed-adjust-subtitle-time-start -999) :to-be -999)
-          (expect (subed-subtitle-msecs-start) :to-be 1)
-          (expect (subed-adjust-subtitle-time-start -1) :to-be -1)
-          (expect (subed-subtitle-msecs-start) :to-be 0)
-          (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
-          (expect (subed-subtitle-msecs-start) :to-be 0)))
-      (it "of a non-first subtitle."
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,000 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 1)
+         (expect (subed-adjust-subtitle-time-stop 1) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-equal 2000)))
+      (it "without overshooting the target time."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n\n"
-                          "2\n"
-                          "00:00:03,000 --> 00:00:04,000\n"
-                          "Bar.\n\n"))
-          (subed-jump-to-subtitle-id 2)
-          (expect (subed-adjust-subtitle-time-start -899) :to-be -899)
-          (expect (subed-subtitle-msecs-start) :to-be 2101)
-          (expect (subed-adjust-subtitle-time-start -1) :to-be -1)
-          (expect (subed-subtitle-msecs-start) :to-be 2100)
-          (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
-          (expect (subed-subtitle-msecs-start) :to-be 2100)))
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,000 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
+         (expect (subed-subtitle-msecs-start) :to-equal 2000)))
       )
-    (it "when increasing start time."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:03,000 --> 00:00:04,000\n"
-                        "Bar.\n\n"))
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-start 999) :to-be 999)
-        (expect (subed-subtitle-msecs-start) :to-be 3999)
-        (expect (subed-adjust-subtitle-time-start 1) :to-be 1)
-        (expect (subed-subtitle-msecs-start) :to-be 4000)
-        (expect (subed-adjust-subtitle-time-start 1) :to-be nil)
-        (expect (subed-subtitle-msecs-start) :to-be 4000)))
-    (it "when decreasing stop time."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:03,000 --> 00:00:04,000\n"
-                        "Bar.\n\n"))
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-stop -999) :to-be -999)
-        (expect (subed-subtitle-msecs-stop) :to-be 3001)
-        (expect (subed-adjust-subtitle-time-stop -1) :to-be -1)
-        (expect (subed-subtitle-msecs-stop) :to-be 3000)
-        (expect (subed-adjust-subtitle-time-stop -1) :to-be nil)
-        (expect (subed-subtitle-msecs-stop) :to-be 3000)))
-    (describe "when increasing stop time"
-      (it "of the last subtitle."
+    (describe "ignores negative duration if the first argument is truthy"
+      (it "when adjusting start time."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n\n"
-                          "2\n"
-                          "00:00:03,000 --> 00:00:04,000\n"
-                          "Bar.\n\n"))
-          (subed-jump-to-subtitle-id 2)
-          (expect (subed-adjust-subtitle-time-stop 1000000):to-be 1000000)
-          (expect (subed-subtitle-msecs-stop) :to-be 1004000)))
-      (it "of a non-last subtitle."
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-start 2000 t) :to-be 2000)
+         (expect (subed-subtitle-msecs-start) :to-be 3000)
+         (expect (subed-subtitle-msecs-stop) :to-be 2000)
+         (expect (subed-adjust-subtitle-time-start -500 t) :to-be -500)
+         (expect (subed-subtitle-msecs-start) :to-be 2500)
+         (expect (subed-subtitle-msecs-stop) :to-be 2000)))
+      (it "when adjusting stop time."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n\n"
-                          "2\n"
-                          "00:00:03,000 --> 00:00:04,000\n"
-                          "Bar.\n\n"))
-          (subed-jump-to-subtitle-id 1)
-          (expect (subed-adjust-subtitle-time-stop 899) :to-be 899)
-          (expect (subed-subtitle-msecs-stop) :to-be 2899)
-          (expect (subed-adjust-subtitle-time-stop 1) :to-be 1)
-          (expect (subed-subtitle-msecs-stop) :to-be 2900)
-          (expect (subed-adjust-subtitle-time-stop 1) :to-be nil)
-          (expect (subed-subtitle-msecs-stop) :to-be 2900)))
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-stop -1500 t) :to-be -1500)
+         (expect (subed-subtitle-msecs-stop) :to-be 500)
+         (expect (subed-subtitle-msecs-start) :to-be 1000)
+         (expect (subed-adjust-subtitle-time-stop 200 t) :to-be 200)
+         (expect (subed-subtitle-msecs-stop) :to-be 700)
+         (expect (subed-subtitle-msecs-start) :to-be 1000)))
       )
-    (it "without undershooting the target time."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,000 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 1)
-        (expect (subed-adjust-subtitle-time-stop 1) :to-be nil)
-        (expect (subed-subtitle-msecs-stop) :to-equal 2000)))
-    (it "without overshooting the target time."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,000 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
-        (expect (subed-subtitle-msecs-start) :to-equal 2000)))
-    )
-  (describe "ignores negative duration if the first argument is truthy"
-    (it "when adjusting start time."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-start 2000 t) :to-be 2000)
-        (expect (subed-subtitle-msecs-start) :to-be 3000)
-        (expect (subed-subtitle-msecs-stop) :to-be 2000)
-        (expect (subed-adjust-subtitle-time-start -500 t) :to-be -500)
-        (expect (subed-subtitle-msecs-start) :to-be 2500)
-        (expect (subed-subtitle-msecs-stop) :to-be 2000)))
-    (it "when adjusting stop time."
+    (describe "ignores subtitle spacing if the second argument is truthy"
+      (it "when adjusting start time."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,200 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-start -150 nil t) :to-be -150)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2050)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2000)
+         (expect (subed-adjust-subtitle-time-start -51 nil t) :to-be -51)
+         (expect (subed-subtitle-msecs-start 2) :to-be 1999)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2000)))
+      (it "when adjusting stop time."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,200 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 1)
+         (expect (subed-adjust-subtitle-time-stop 150 nil t) :to-be 150)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2150)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2200)
+         (expect (subed-adjust-subtitle-time-stop 51 nil t) :to-be 51)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2201)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2200)))
+      )
+    (describe "ignores negative duration if subed-enforce-time-boundaries is 
falsy"
+      (it "when adjusting start time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-start 2000) :to-be 2000)
+         (expect (subed-subtitle-msecs-start) :to-be 3000)
+         (expect (subed-subtitle-msecs-stop) :to-be 2000)
+         (expect (subed-adjust-subtitle-time-start -500) :to-be -500)
+         (expect (subed-subtitle-msecs-start) :to-be 2500)
+         (expect (subed-subtitle-msecs-stop) :to-be 2000)))
+      (it "when adjusting stop time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-stop -1500) :to-be -1500)
+         (expect (subed-subtitle-msecs-stop) :to-be 500)
+         (expect (subed-subtitle-msecs-start) :to-be 1000)
+         (expect (subed-adjust-subtitle-time-stop 200) :to-be 200)
+         (expect (subed-subtitle-msecs-stop) :to-be 700)
+         (expect (subed-subtitle-msecs-start) :to-be 1000)))
+      )
+    (describe "ignores subtitle spacing if subed-enforce-time-boundaries is 
falsy"
+      (it "when adjusting start time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,200 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-adjust-subtitle-time-start -150) :to-be -150)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2050)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2000)
+         (expect (subed-adjust-subtitle-time-start -51) :to-be -51)
+         (expect (subed-subtitle-msecs-start 2) :to-be 1999)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2000)))
+      (it "when adjusting stop time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,200 --> 00:00:03,000\n"
+                         "Bar.\n"))
+         (subed-jump-to-subtitle-id 1)
+         (expect (subed-adjust-subtitle-time-stop 150) :to-be 150)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2150)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2200)
+         (expect (subed-adjust-subtitle-time-stop 51) :to-be 51)
+         (expect (subed-subtitle-msecs-stop 1) :to-be 2201)
+         (expect (subed-subtitle-msecs-start 2) :to-be 2200)))
+      )
+    (describe "prevents negative time even if subed-enforce-time-boundaries is 
falsy"
+      (it "when adjusting start time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-start -1000) :to-be -1000)
+         (expect (subed-subtitle-msecs-start) :to-be 0)
+         (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
+         (expect (subed-subtitle-msecs-start) :to-be 0)))
+      (it "when adjusting stop time."
+        (with-temp-srt-buffer
+         (setq-local subed-enforce-time-boundaries nil)
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"))
+         (expect (subed-adjust-subtitle-time-stop -2000) :to-be -2000)
+         (expect (subed-subtitle-msecs-stop) :to-be 0)
+         (expect (subed-adjust-subtitle-time-stop -1) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be 0)))
+      )
+    (it "does nothing if no timestamp can be found."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-stop -1500 t) :to-be -1500)
-        (expect (subed-subtitle-msecs-stop) :to-be 500)
-        (expect (subed-subtitle-msecs-start) :to-be 1000)
-        (expect (subed-adjust-subtitle-time-stop 200 t) :to-be 200)
-        (expect (subed-subtitle-msecs-stop) :to-be 700)
-        (expect (subed-subtitle-msecs-start) :to-be 1000)))
+       (insert "foo")
+       (goto-char (point-min))
+       (expect (subed-adjust-subtitle-time-start 123) :to-be nil)
+       (expect (buffer-string) :to-equal "foo")
+       (expect (subed-adjust-subtitle-time-start -123) :to-be nil)
+       (expect (buffer-string) :to-equal "foo")))
     )
-  (describe "ignores subtitle spacing if the second argument is truthy"
-    (it "when adjusting start time."
+
+  (describe "Copy start/stop time from player"
+    :var (subed-mpv-playback-position)
+    (it "does nothing in an empty buffer."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,200 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-start -150 nil t) :to-be -150)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2050)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2000)
-        (expect (subed-adjust-subtitle-time-start -51 nil t) :to-be -51)
-        (expect (subed-subtitle-msecs-start 2) :to-be 1999)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2000)))
-    (it "when adjusting stop time."
+       (let ((subed-mpv-playback-position 12345))
+         (expect (subed-copy-player-pos-to-start-time) :to-be nil)
+         (expect (subed-copy-player-pos-to-stop-time) :to-be nil)
+         (expect (buffer-string) :to-equal ""))))
+    (it "does nothing if player position is unknown."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,200 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 1)
-        (expect (subed-adjust-subtitle-time-stop 150 nil t) :to-be 150)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2150)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2200)
-        (expect (subed-adjust-subtitle-time-stop 51 nil t) :to-be 51)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2201)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2200)))
-    )
-  (describe "ignores negative duration if subed-enforce-time-boundaries is 
falsy"
-    (it "when adjusting start time."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n"))
+       (let ((subed-mpv-playback-position nil))
+         (expect (subed-copy-player-pos-to-start-time) :to-be nil)
+         (expect (subed-copy-player-pos-to-stop-time) :to-be nil)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:00:01,000 --> 
00:00:02,000\n"
+                                                   "Foo.\n")))))
+    (it "sets start/stop time when possible."
       (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-start 2000) :to-be 2000)
-        (expect (subed-subtitle-msecs-start) :to-be 3000)
-        (expect (subed-subtitle-msecs-stop) :to-be 2000)
-        (expect (subed-adjust-subtitle-time-start -500) :to-be -500)
-        (expect (subed-subtitle-msecs-start) :to-be 2500)
-        (expect (subed-subtitle-msecs-stop) :to-be 2000)))
-    (it "when adjusting stop time."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n"))
+       (let ((subed-mpv-playback-position (+ 60000 2000 123)))
+         (expect (subed-copy-player-pos-to-start-time) :to-be 
subed-mpv-playback-position)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:01:02,123 --> 
00:00:02,000\n"
+                                                   "Foo.\n")))
+       (let ((subed-mpv-playback-position (+ 60000 5000 456)))
+         (expect (subed-copy-player-pos-to-stop-time) :to-be 
subed-mpv-playback-position)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:01:02,123 --> 
00:01:05,456\n"
+                                                   "Foo.\n")))))
+    (it "runs the appropriate hook."
       (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-stop -1500) :to-be -1500)
-        (expect (subed-subtitle-msecs-stop) :to-be 500)
-        (expect (subed-subtitle-msecs-start) :to-be 1000)
-        (expect (subed-adjust-subtitle-time-stop 200) :to-be 200)
-        (expect (subed-subtitle-msecs-stop) :to-be 700)
-        (expect (subed-subtitle-msecs-start) :to-be 1000)))
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n"))
+       (let ((foo (setf (symbol-function 'foo) (lambda (msecs) ()))))
+         (spy-on 'foo)
+         (add-hook 'subed-subtitle-time-adjusted-hook 'foo)
+         (let ((subed-mpv-playback-position (+ 60000 2000 123)))
+           (expect (subed-copy-player-pos-to-start-time) :to-be 
subed-mpv-playback-position)
+           (expect (buffer-string) :to-equal (concat "1\n"
+                                                     "00:01:02,123 --> 
00:00:02,000\n"
+                                                     "Foo.\n"))
+           (expect (spy-calls-args-for 'foo 0) :to-equal `(,(+ 60000 2000 
123)))
+           (expect (spy-calls-count 'foo) :to-equal 1)))
+       (let ((subed-mpv-playback-position (+ 60000 5000 456)))
+         (expect (subed-copy-player-pos-to-stop-time) :to-be 
subed-mpv-playback-position)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:01:02,123 --> 
00:01:05,456\n"
+                                                   "Foo.\n"))
+         (expect (spy-calls-args-for 'foo 0) :to-equal `(,(+ 60000 2000 123)))
+         (expect (spy-calls-count 'foo) :to-equal 2)))
+      (remove-hook 'subed-subtitle-time-adjusted-hook 'foo))
     )
-  (describe "ignores subtitle spacing if subed-enforce-time-boundaries is 
falsy"
-    (it "when adjusting start time."
-      (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,200 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 2)
-        (expect (subed-adjust-subtitle-time-start -150) :to-be -150)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2050)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2000)
-        (expect (subed-adjust-subtitle-time-start -51) :to-be -51)
-        (expect (subed-subtitle-msecs-start 2) :to-be 1999)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2000)))
-    (it "when adjusting stop time."
+
+  (describe "Jumping"
+    (describe "to subtitle text given msecs"
+      (it "finds the right subtitle"
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text-at-msecs 122234)
+         (expect (looking-at "Bar\\.") :to-equal t)))))
+  (describe "Moving"
+    (it "adjusts start and stop time by the same amount."
       (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,200 --> 00:00:03,000\n"
-                        "Bar.\n"))
-        (subed-jump-to-subtitle-id 1)
-        (expect (subed-adjust-subtitle-time-stop 150) :to-be 150)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2150)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2200)
-        (expect (subed-adjust-subtitle-time-stop 51) :to-be 51)
-        (expect (subed-subtitle-msecs-stop 1) :to-be 2201)
-        (expect (subed-subtitle-msecs-start 2) :to-be 2200)))
-    )
-  (describe "prevents negative time even if subed-enforce-time-boundaries is 
falsy"
-    (it "when adjusting start time."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n"))
+       (let ((orig-point (subed-jump-to-subtitle-text 1)))
+         (subed-move-subtitle-forward 100)
+         (expect (subed-subtitle-msecs-start) :to-equal 1100)
+         (expect (subed-subtitle-msecs-stop) :to-equal 2100)
+         (subed-move-subtitle-backward 200)
+         (expect (subed-subtitle-msecs-start) :to-equal 900)
+         (expect (subed-subtitle-msecs-stop) :to-equal 1900)
+         (expect (point) :to-equal orig-point))))
+    (it "adjusts start and stop time by the same amount when bumping into next 
subtitle."
       (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-start -1000) :to-be -1000)
-        (expect (subed-subtitle-msecs-start) :to-be 0)
-        (expect (subed-adjust-subtitle-time-start -1) :to-be nil)
-        (expect (subed-subtitle-msecs-start) :to-be 0)))
-    (it "when adjusting stop time."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:01,600\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:02,000 --> 00:00:03,000\n"
+                       "Bar.\n"))
+       (let ((orig-point (subed-jump-to-subtitle-id 1)))
+         (subed-move-subtitle-forward 1000)
+         (expect (subed-subtitle-msecs-start) :to-equal 1300)
+         (expect (subed-subtitle-msecs-stop) :to-equal 1900)
+         (expect (point) :to-equal orig-point))))
+    (it "adjusts start and stop time by the same amount when bumping into 
previous subtitle."
       (with-temp-srt-buffer
-        (setq-local subed-enforce-time-boundaries nil)
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"))
-        (expect (subed-adjust-subtitle-time-stop -2000) :to-be -2000)
-        (expect (subed-subtitle-msecs-stop) :to-be 0)
-        (expect (subed-adjust-subtitle-time-stop -1) :to-be nil)
-        (expect (subed-subtitle-msecs-stop) :to-be 0)))
-    )
-  (it "does nothing if no timestamp can be found."
-    (with-temp-srt-buffer
-      (insert "foo")
-      (goto-char (point-min))
-      (expect (subed-adjust-subtitle-time-start 123) :to-be nil)
-      (expect (buffer-string) :to-equal "foo")
-      (expect (subed-adjust-subtitle-time-start -123) :to-be nil)
-      (expect (buffer-string) :to-equal "foo")))
-  )
-
-(describe "Copy start/stop time from player"
-  :var (subed-mpv-playback-position)
-  (it "does nothing in an empty buffer."
-    (with-temp-srt-buffer
-      (let ((subed-mpv-playback-position 12345))
-        (expect (subed-copy-player-pos-to-start-time) :to-be nil)
-        (expect (subed-copy-player-pos-to-stop-time) :to-be nil)
-        (expect (buffer-string) :to-equal ""))))
-  (it "does nothing if player position is unknown."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n"))
-      (let ((subed-mpv-playback-position nil))
-        (expect (subed-copy-player-pos-to-start-time) :to-be nil)
-        (expect (subed-copy-player-pos-to-stop-time) :to-be nil)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:00:01,000 --> 
00:00:02,000\n"
-                                                  "Foo.\n")))))
-  (it "sets start/stop time when possible."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n"))
-      (let ((subed-mpv-playback-position (+ 60000 2000 123)))
-        (expect (subed-copy-player-pos-to-start-time) :to-be 
subed-mpv-playback-position)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:01:02,123 --> 
00:00:02,000\n"
-                                                  "Foo.\n")))
-      (let ((subed-mpv-playback-position (+ 60000 5000 456)))
-        (expect (subed-copy-player-pos-to-stop-time) :to-be 
subed-mpv-playback-position)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:01:02,123 --> 
00:01:05,456\n"
-                                                  "Foo.\n")))))
-  (it "runs the appropriate hook."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n"))
-      (let ((foo (setf (symbol-function 'foo) (lambda (msecs) ()))))
-        (spy-on 'foo)
-        (add-hook 'subed-subtitle-time-adjusted-hook 'foo)
-        (let ((subed-mpv-playback-position (+ 60000 2000 123)))
-          (expect (subed-copy-player-pos-to-start-time) :to-be 
subed-mpv-playback-position)
-          (expect (buffer-string) :to-equal (concat "1\n"
-                                                    "00:01:02,123 --> 
00:00:02,000\n"
-                                                    "Foo.\n"))
-          (expect (spy-calls-args-for 'foo 0) :to-equal `(,(+ 60000 2000 123)))
-          (expect (spy-calls-count 'foo) :to-equal 1)))
-        (let ((subed-mpv-playback-position (+ 60000 5000 456)))
-          (expect (subed-copy-player-pos-to-stop-time) :to-be 
subed-mpv-playback-position)
-          (expect (buffer-string) :to-equal (concat "1\n"
-                                                    "00:01:02,123 --> 
00:01:05,456\n"
-                                                    "Foo.\n"))
-          (expect (spy-calls-args-for 'foo 0) :to-equal `(,(+ 60000 2000 123)))
-          (expect (spy-calls-count 'foo) :to-equal 2)))
-        (remove-hook 'subed-subtitle-time-adjusted-hook 'foo))
-  )
-
-(describe "Moving"
-  (it "adjusts start and stop time by the same amount."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n"))
-      (let ((orig-point (subed-jump-to-subtitle-text 1)))
-        (subed-move-subtitle-forward 100)
-        (expect (subed-subtitle-msecs-start) :to-equal 1100)
-        (expect (subed-subtitle-msecs-stop) :to-equal 2100)
-        (subed-move-subtitle-backward 200)
-        (expect (subed-subtitle-msecs-start) :to-equal 900)
-        (expect (subed-subtitle-msecs-stop) :to-equal 1900)
-        (expect (point) :to-equal orig-point))))
-  (it "adjusts start and stop time by the same amount when bumping into next 
subtitle."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:01,600\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:02,000 --> 00:00:03,000\n"
-                      "Bar.\n"))
-      (let ((orig-point (subed-jump-to-subtitle-id 1)))
-        (subed-move-subtitle-forward 1000)
-        (expect (subed-subtitle-msecs-start) :to-equal 1300)
-        (expect (subed-subtitle-msecs-stop) :to-equal 1900)
-        (expect (point) :to-equal orig-point))))
-  (it "adjusts start and stop time by the same amount when bumping into 
previous subtitle."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:01,600\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:02,000 --> 00:00:03,000\n"
-                      "Bar.\n"))
-      (let ((orig-point (subed-jump-to-subtitle-id 2)))
-        (subed-move-subtitle-backward 1000)
-        (expect (subed-subtitle-msecs-start) :to-equal 1700)
-        (expect (subed-subtitle-msecs-stop) :to-equal 2700)
-        (expect (point) :to-equal orig-point))))
-  (it "does not adjust anything if subtitle cannot be moved forward at all."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:02,000 --> 00:00:03,000\n"
-                      "Bar.\n"))
-      (let ((orig-point (subed-jump-to-subtitle-id 1)))
-        (subed-move-subtitle-forward 1)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-        (expect (point) :to-equal orig-point))))
-  (it "does not adjust anything if subtitle cannot be moved backward at all."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:02,000 --> 00:00:03,000\n"
-                      "Bar.\n"))
-      (let ((orig-point (subed-jump-to-subtitle-id 2)))
-        (subed-move-subtitle-backward 1)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-        (expect (point) :to-equal orig-point))))
-  (describe "adjusts subtitles in the active region,"
-    (it "excluding the first subtitle."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:01,600\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:02,000 --> 00:00:03,000\n"
+                       "Bar.\n"))
+       (let ((orig-point (subed-jump-to-subtitle-id 2)))
+         (subed-move-subtitle-backward 1000)
+         (expect (subed-subtitle-msecs-start) :to-equal 1700)
+         (expect (subed-subtitle-msecs-stop) :to-equal 2700)
+         (expect (point) :to-equal orig-point))))
+    (it "does not adjust anything if subtitle cannot be moved forward at all."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:03,000 --> 00:00:04,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:05,000 --> 00:00:06,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 2))
-        (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-start 3))
-        (let ((orig-point (subed-jump-to-subtitle-text 2)))
-          (subed-move-subtitle-forward 100)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 3100)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 4100)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 5100)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 6100)
-          (expect (point) :to-equal orig-point)
-          (subed-move-subtitle-backward 200)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 2900)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 3900)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 4900)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 5900)
-          (expect (point) :to-equal orig-point))))
-    (it "excluding the last subtitle."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:02,000 --> 00:00:03,000\n"
+                       "Bar.\n"))
+       (let ((orig-point (subed-jump-to-subtitle-id 1)))
+         (subed-move-subtitle-forward 1)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+         (expect (point) :to-equal orig-point))))
+    (it "does not adjust anything if subtitle cannot be moved backward at all."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:03,000 --> 00:00:04,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:05,000 --> 00:00:06,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 1))
-        (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-stop 2))
-        (let ((orig-point (subed-jump-to-subtitle-time-stop 3)))
-          (subed-move-subtitle-forward 500)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1500)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2500)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 4500)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-          (expect (point) :to-equal orig-point)
-          (subed-move-subtitle-backward 300)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1200)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2200)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 3200)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 4200)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-          (expect (point) :to-equal orig-point))))
-    (describe "not changing spacing between subtitles"
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:02,000 --> 00:00:03,000\n"
+                       "Bar.\n"))
+       (let ((orig-point (subed-jump-to-subtitle-id 2)))
+         (subed-move-subtitle-backward 1)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+         (expect (point) :to-equal orig-point))))
+    (describe "adjusts subtitles in the active region,"
+      (it "excluding the first subtitle."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:03,000 --> 00:00:04,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:05,000 --> 00:00:06,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 2))
+         (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-start 3))
+         (let ((orig-point (subed-jump-to-subtitle-text 2)))
+           (subed-move-subtitle-forward 100)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 3100)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 4100)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 5100)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 6100)
+           (expect (point) :to-equal orig-point)
+           (subed-move-subtitle-backward 200)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 2900)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3900)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 4900)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 5900)
+           (expect (point) :to-equal orig-point))))
+      (it "excluding the last subtitle."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:03,000 --> 00:00:04,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:05,000 --> 00:00:06,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 1))
+         (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-stop 2))
+         (let ((orig-point (subed-jump-to-subtitle-time-stop 3)))
+           (subed-move-subtitle-forward 500)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1500)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2500)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 4500)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+           (expect (point) :to-equal orig-point)
+           (subed-move-subtitle-backward 300)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1200)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2200)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 3200)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 4200)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+           (expect (point) :to-equal orig-point))))
+      (describe "not changing spacing between subtitles"
+        (it "when moving forward."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n\n"
+                           "2\n"
+                           "00:00:10,000 --> 00:00:11,000\n"
+                           "Bar.\n\n"
+                           "3\n"
+                           "00:00:12,000 --> 00:00:13,000\n"
+                           "Baz.\n"))
+           (setq mark-active t)
+           (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 1))
+           (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 
2))
+           (let ((orig-point (subed-jump-to-subtitle-time-start 1)))
+             (subed-move-subtitle-forward 2000)
+             (expect (subed-subtitle-msecs-start 1) :to-equal 1900)
+             (expect (subed-subtitle-msecs-stop 1) :to-equal 2900)
+             (expect (subed-subtitle-msecs-start 2) :to-equal 10900)
+             (expect (subed-subtitle-msecs-stop 2) :to-equal 11900)
+             (expect (subed-subtitle-msecs-start 3) :to-equal 12000)
+             (expect (subed-subtitle-msecs-stop 3) :to-equal 13000)
+             (expect (point) :to-equal orig-point))))
+        (it "when moving backward."
+          (with-temp-srt-buffer
+           (insert (concat "1\n"
+                           "00:00:01,000 --> 00:00:02,000\n"
+                           "Foo.\n\n"
+                           "2\n"
+                           "00:00:3,000 --> 00:00:4,000\n"
+                           "Bar.\n\n"
+                           "3\n"
+                           "00:00:10,000 --> 00:00:11,000\n"
+                           "Baz.\n"))
+           (setq mark-active t)
+           (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 2))
+           (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 
3))
+           (let ((orig-point (subed-jump-to-subtitle-time-start 2)))
+             (subed-move-subtitle-backward 10000)
+             (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+             (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+             (expect (subed-subtitle-msecs-start 2) :to-equal 2100)
+             (expect (subed-subtitle-msecs-stop 2) :to-equal 3100)
+             (expect (subed-subtitle-msecs-start 3) :to-equal 9100)
+             (expect (subed-subtitle-msecs-stop 3) :to-equal 10100)
+             (expect (point) :to-equal orig-point))))
+        )
+      )
+    (describe "unless there is no space left"
       (it "when moving forward."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n\n"
-                          "2\n"
-                          "00:00:10,000 --> 00:00:11,000\n"
-                          "Bar.\n\n"
-                          "3\n"
-                          "00:00:12,000 --> 00:00:13,000\n"
-                          "Baz.\n"))
-          (setq mark-active t)
-          (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 1))
-          (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 
2))
-          (let ((orig-point (subed-jump-to-subtitle-time-start 1)))
-            (subed-move-subtitle-forward 2000)
-            (expect (subed-subtitle-msecs-start 1) :to-equal 1900)
-            (expect (subed-subtitle-msecs-stop 1) :to-equal 2900)
-            (expect (subed-subtitle-msecs-start 2) :to-equal 10900)
-            (expect (subed-subtitle-msecs-stop 2) :to-equal 11900)
-            (expect (subed-subtitle-msecs-start 3) :to-equal 12000)
-            (expect (subed-subtitle-msecs-stop 3) :to-equal 13000)
-            (expect (point) :to-equal orig-point))))
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:10,000 --> 00:00:11,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:11,000 --> 00:00:12,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 1))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
+         (let ((orig-point (subed-jump-to-subtitle-text 1)))
+           (subed-move-subtitle-forward 1)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 10000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 11000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 11000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 12000)
+           (expect (point) :to-equal orig-point))))
       (it "when moving backward."
         (with-temp-srt-buffer
-          (insert (concat "1\n"
-                          "00:00:01,000 --> 00:00:02,000\n"
-                          "Foo.\n\n"
-                          "2\n"
-                          "00:00:3,000 --> 00:00:4,000\n"
-                          "Bar.\n\n"
-                          "3\n"
-                          "00:00:10,000 --> 00:00:11,000\n"
-                          "Baz.\n"))
-          (setq mark-active t)
-          (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 2))
-          (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 
3))
-          (let ((orig-point (subed-jump-to-subtitle-time-start 2)))
-            (subed-move-subtitle-backward 10000)
-            (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-            (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-            (expect (subed-subtitle-msecs-start 2) :to-equal 2100)
-            (expect (subed-subtitle-msecs-stop 2) :to-equal 3100)
-            (expect (subed-subtitle-msecs-start 3) :to-equal 9100)
-            (expect (subed-subtitle-msecs-stop 3) :to-equal 10100)
-            (expect (point) :to-equal orig-point))))
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:02,000 --> 00:00:03,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:11,000 --> 00:00:12,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 2))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
+         (let ((orig-point (subed-jump-to-subtitle-id 3)))
+           (subed-move-subtitle-backward 1)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 11000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 12000)
+           (expect (point) :to-equal orig-point))))
       )
-    )
-  (describe "unless there is no space left"
-    (it "when moving forward."
+    (describe "ignoring spacing for non-leading subtitles"
+      (it "when moving forward."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:00,000 --> 00:00:01,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:01,050 --> 00:00:02,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:05,000 --> 00:00:6,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 1))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
+         (let ((orig-point (subed-jump-to-subtitle-time-start 3)))
+           (subed-move-subtitle-forward 1000)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 2050)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+           (expect (point) :to-equal orig-point))))
+      (it "when moving backward."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:04,000 --> 00:00:05,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:05,000 --> 00:00:05,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 2))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
+         (let ((orig-point (subed-jump-to-subtitle-time-stop 1)))
+           (subed-move-subtitle-backward 1000)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 3000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 4000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 4000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 4000)
+           (expect (point) :to-equal orig-point))))
+      )
+    (describe "ignoring overlapping subtitles"
+      (it "when moving forward."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:01,500\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:01,300 --> 00:00:02,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:05,000 --> 00:00:6,000\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 1))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
+         (let ((orig-point (subed-jump-to-subtitle-text 2)))
+           (subed-move-subtitle-forward 1000)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2500)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 2300)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+           (expect (point) :to-equal orig-point))))
+      (it "when moving backward."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "Foo.\n\n"
+                         "2\n"
+                         "00:00:04,500 --> 00:00:04,000\n"
+                         "Bar.\n\n"
+                         "3\n"
+                         "00:00:04,500 --> 00:00:04,490\n"
+                         "Baz.\n"))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-id 2))
+         (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
+         (let ((orig-point (subed-jump-to-subtitle-text 1)))
+           (subed-move-subtitle-backward 1000)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 3500)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 3490)
+           (expect (point) :to-equal orig-point))))
+      )
+    (it "ignoring start time being larger than stop time."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:10,000 --> 00:00:11,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:11,000 --> 00:00:12,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
1))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
-        (let ((orig-point (subed-jump-to-subtitle-text 1)))
-          (subed-move-subtitle-forward 1)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 10000)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 11000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 11000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 12000)
-          (expect (point) :to-equal orig-point))))
-    (it "when moving backward."
+       (insert (concat "1\n"
+                       "00:00:01,500 --> 00:00:01,400\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:02,500 --> 00:00:02,499\n"
+                       "Bar.\n\n"
+                       "3\n"
+                       "00:00:05,000 --> 00:00:06,000\n"
+                       "Bar.\n"))
+       (setq mark-active t)
+       (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 1))
+       (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-start 2))
+       (let ((orig-point (subed-jump-to-subtitle-time-stop 1)))
+         (subed-move-subtitle-forward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 2500)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2400)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 3499)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+         (expect (point) :to-equal orig-point)
+         (subed-move-subtitle-backward 500)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 2000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 1900)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 3000)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 2999)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+         (expect (point) :to-equal orig-point))))
+    (it "ignoring stop time being smaller than start time."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:02,000 --> 00:00:03,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:11,000 --> 00:00:12,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
2))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
-        (let ((orig-point (subed-jump-to-subtitle-id 3)))
-          (subed-move-subtitle-backward 1)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 2000)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 11000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 12000)
-          (expect (point) :to-equal orig-point))))
-    )
-  (describe "ignoring spacing for non-leading subtitles"
-    (it "when moving forward."
+       (insert (concat "1\n"
+                       "00:00:01,000 --> 00:00:02,000\n"
+                       "Foo.\n\n"
+                       "2\n"
+                       "00:00:04,100 --> 00:00:04,099\n"
+                       "Bar.\n\n"
+                       "3\n"
+                       "00:00:05,500 --> 00:00:05,000\n"
+                       "Bar.\n"))
+       (setq mark-active t)
+       (spy-on 'region-beginning :and-return-value 
(subed-jump-to-subtitle-text 2))
+       (spy-on 'region-end :and-return-value 
(subed-jump-to-subtitle-time-start 3))
+       (let ((orig-point (subed-jump-to-subtitle-text 1)))
+         (subed-move-subtitle-forward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 5100)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 5099)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 6500)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
+         (expect (point) :to-equal orig-point)
+         (subed-move-subtitle-backward 500)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 4600)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 4599)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 6000)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 5500)
+         (expect (point) :to-equal orig-point))))
+    (it "disables subtitle replay while moving subtitles."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:00,000 --> 00:00:01,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:01,050 --> 00:00:02,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:05,000 --> 00:00:6,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
1))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
-        (let ((orig-point (subed-jump-to-subtitle-time-start 3)))
-          (subed-move-subtitle-forward 1000)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 2050)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-          (expect (point) :to-equal orig-point))))
-    (it "when moving backward."
+       (insert mock-srt-data)
+       (subed-enable-replay-adjusted-subtitle :quiet)
+       (spy-on 'subed-enable-replay-adjusted-subtitle :and-call-through)
+       (spy-on 'subed-disable-replay-adjusted-subtitle :and-call-through)
+       (spy-on 'subed-adjust-subtitle-time-start :and-call-fake
+               (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
+       (spy-on 'subed-adjust-subtitle-stop :and-call-fake
+               (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
+       (subed-move-subtitle-forward 100)
+       (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
+       (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
+       (subed-move-subtitle-backward 100)
+       (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 2)
+       (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 2)))
+    (it "does not enable subtitle replay afterwards if it is disabled."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:04,000 --> 00:00:05,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:05,000 --> 00:00:05,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
2))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
-        (let ((orig-point (subed-jump-to-subtitle-time-stop 1)))
-          (subed-move-subtitle-backward 1000)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 3000)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 4000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 4000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 4000)
-          (expect (point) :to-equal orig-point))))
-    )
-  (describe "ignoring overlapping subtitles"
-    (it "when moving forward."
+       (insert mock-srt-data)
+       (subed-disable-replay-adjusted-subtitle :quiet)
+       (spy-on 'subed-enable-replay-adjusted-subtitle :and-call-through)
+       (spy-on 'subed-disable-replay-adjusted-subtitle :and-call-through)
+       (spy-on 'subed-adjust-subtitle-time-start :and-call-fake
+               (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
+       (spy-on 'subed-adjust-subtitle-stop :and-call-fake
+               (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
+       (subed-move-subtitle-forward 100)
+       (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
+       (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 0)
+       (subed-move-subtitle-backward 100)
+       (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 2)
+       (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 0)))
+    (it "seeks player to current subtitle if region is not active."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:01,500\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:01,300 --> 00:00:02,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:05,000 --> 00:00:6,000\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
1))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 2))
-        (let ((orig-point (subed-jump-to-subtitle-text 2)))
-          (subed-move-subtitle-forward 1000)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2500)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 2300)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-          (expect (point) :to-equal orig-point))))
-    (it "when moving backward."
+       (insert mock-srt-data)
+       (spy-on 'subed-replay-adjusted-subtitle-p :and-return-value t)
+       (spy-on 'subed-mpv-jump)
+       (subed-move-subtitle-forward 100)
+       (expect 'subed-mpv-jump :to-have-been-called-times 1)
+       (expect 'subed-mpv-jump :to-have-been-called-with 183550)
+       (subed-move-subtitle-backward 200)
+       (expect 'subed-mpv-jump :to-have-been-called-times 2)
+       (expect 'subed-mpv-jump :to-have-been-called-with 183350)))
+    (it "seeks player to first subtitle in active region."
       (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "Foo.\n\n"
-                        "2\n"
-                        "00:00:04,500 --> 00:00:04,000\n"
-                        "Bar.\n\n"
-                        "3\n"
-                        "00:00:04,500 --> 00:00:04,490\n"
-                        "Baz.\n"))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-id 
2))
-        (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-text 3))
-        (let ((orig-point (subed-jump-to-subtitle-text 1)))
-          (subed-move-subtitle-backward 1000)
-          (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-          (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
-          (expect (subed-subtitle-msecs-stop 2) :to-equal 3000)
-          (expect (subed-subtitle-msecs-start 3) :to-equal 3500)
-          (expect (subed-subtitle-msecs-stop 3) :to-equal 3490)
-          (expect (point) :to-equal orig-point))))
+       (insert mock-srt-data)
+       (let ((beg 15)
+             (end (point-max)))
+         (setq mark-active t)
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'subed-replay-adjusted-subtitle-p :and-return-value t)
+         (spy-on 'subed-mpv-jump)
+         (subed-move-subtitle-forward 100)
+         (expect 'subed-mpv-jump :to-have-been-called-times 1)
+         (expect 'subed-mpv-jump :to-have-been-called-with '61100)
+         (subed-move-subtitle-backward 300)
+         (expect 'subed-mpv-jump :to-have-been-called-times 2)
+         (expect 'subed-mpv-jump :to-have-been-called-with '60800))))
     )
-  (it "ignoring start time being larger than stop time."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,500 --> 00:00:01,400\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:02,500 --> 00:00:02,499\n"
-                      "Bar.\n\n"
-                      "3\n"
-                      "00:00:05,000 --> 00:00:06,000\n"
-                      "Bar.\n"))
-      (setq mark-active t)
-      (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-text 
1))
-      (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-time-start 
2))
-      (let ((orig-point (subed-jump-to-subtitle-time-stop 1)))
-        (subed-move-subtitle-forward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 2500)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 2400)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 3500)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 3499)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-        (expect (point) :to-equal orig-point)
-        (subed-move-subtitle-backward 500)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 2000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 1900)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 3000)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 2999)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 5000)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-        (expect (point) :to-equal orig-point))))
-  (it "ignoring stop time being smaller than start time."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:01,000 --> 00:00:02,000\n"
-                      "Foo.\n\n"
-                      "2\n"
-                      "00:00:04,100 --> 00:00:04,099\n"
-                      "Bar.\n\n"
-                      "3\n"
-                      "00:00:05,500 --> 00:00:05,000\n"
-                      "Bar.\n"))
-      (setq mark-active t)
-      (spy-on 'region-beginning :and-return-value (subed-jump-to-subtitle-text 
2))
-      (spy-on 'region-end :and-return-value (subed-jump-to-subtitle-time-start 
3))
-      (let ((orig-point (subed-jump-to-subtitle-text 1)))
-        (subed-move-subtitle-forward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 5100)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 5099)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 6500)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 6000)
-        (expect (point) :to-equal orig-point)
-        (subed-move-subtitle-backward 500)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 4600)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 4599)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 6000)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 5500)
-        (expect (point) :to-equal orig-point))))
-  (it "disables subtitle replay while moving subtitles."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-enable-replay-adjusted-subtitle :quiet)
-      (spy-on 'subed-enable-replay-adjusted-subtitle :and-call-through)
-      (spy-on 'subed-disable-replay-adjusted-subtitle :and-call-through)
-      (spy-on 'subed-adjust-subtitle-time-start :and-call-fake
-              (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
-      (spy-on 'subed-adjust-subtitle-stop :and-call-fake
-              (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
-      (subed-move-subtitle-forward 100)
-      (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
-      (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
-      (subed-move-subtitle-backward 100)
-      (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 2)
-      (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 2)))
-  (it "does not enable subtitle replay afterwards if it is disabled."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-disable-replay-adjusted-subtitle :quiet)
-      (spy-on 'subed-enable-replay-adjusted-subtitle :and-call-through)
-      (spy-on 'subed-disable-replay-adjusted-subtitle :and-call-through)
-      (spy-on 'subed-adjust-subtitle-time-start :and-call-fake
-              (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
-      (spy-on 'subed-adjust-subtitle-stop :and-call-fake
-              (lambda (msecs &optional a b) (expect 
(subed-replay-adjusted-subtitle-p) :to-be nil)))
-      (subed-move-subtitle-forward 100)
-      (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 1)
-      (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 0)
-      (subed-move-subtitle-backward 100)
-      (expect 'subed-disable-replay-adjusted-subtitle 
:to-have-been-called-times 2)
-      (expect 'subed-enable-replay-adjusted-subtitle 
:to-have-been-called-times 0)))
-  (it "seeks player to current subtitle if region is not active."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (spy-on 'subed-replay-adjusted-subtitle-p :and-return-value t)
-      (spy-on 'subed-mpv-jump)
-      (subed-move-subtitle-forward 100)
-      (expect 'subed-mpv-jump :to-have-been-called-times 1)
-      (expect 'subed-mpv-jump :to-have-been-called-with 183550)
-      (subed-move-subtitle-backward 200)
-      (expect 'subed-mpv-jump :to-have-been-called-times 2)
-      (expect 'subed-mpv-jump :to-have-been-called-with 183350)))
-  (it "seeks player to first subtitle in active region."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg 15)
-            (end (point-max)))
-        (setq mark-active t)
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'subed-replay-adjusted-subtitle-p :and-return-value t)
-        (spy-on 'subed-mpv-jump)
-        (subed-move-subtitle-forward 100)
-        (expect 'subed-mpv-jump :to-have-been-called-times 1)
-        (expect 'subed-mpv-jump :to-have-been-called-with '61100)
-        (subed-move-subtitle-backward 300)
-        (expect 'subed-mpv-jump :to-have-been-called-times 2)
-        (expect 'subed-mpv-jump :to-have-been-called-with '60800))))
-  )
 
-(describe "Inserting evenly spaced"
-  (describe "in an empty buffer,"
-    (describe "appending"
-      (it "a single subtile."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtiles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:01,100 --> 
00:00:02,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "prepending"
-      (it "a single subtile."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtiles."
-        (cl-loop for arg in (list -2 (list -16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:01,100 --> 
00:00:02,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    )
-  (describe "in a non-empty buffer"
-    (describe "prepending between subtitles"
-      (it "a single subtitle."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 2)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:30,000 --> 
00:01:31,000\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list -2 (list 16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 2)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:20,000 --> 
00:01:21,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:40,000 --> 
00:01:41,000\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "appending between subtitles"
-      (it "a single subtitle."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:30,000 --> 
00:01:31,000\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:20,000 --> 
00:01:21,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:40,000 --> 
00:01:41,000\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "prepending to the first subtitle"
-      (it "a single subtitle."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:01:00,000 --> 00:01:01,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:30,000 --> 
00:00:31,000\n"
-                                                             "\n\n"
-                                                             "1\n"
-                                                             "00:01:00,000 --> 
00:01:01,000\n"
-                                                             "Foo.\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list -2 (list 16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:01:00,000 --> 00:01:01,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:20,000 --> 
00:00:21,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:40,000 --> 
00:00:41,000\n"
-                                                             "\n\n"
-                                                             "1\n"
-                                                             "00:01:00,000 --> 
00:01:01,000\n"
-                                                             "Foo.\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "appending to the last subtitle"
-      (it "a single subtitle."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 3)
-                   (expect (subed-insert-subtitle arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:01,200 --> 
00:01:02,200\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 71))))
+  (describe "Inserting evenly spaced"
+    (describe "in an empty buffer,"
+      (describe "appending"
+        (it "a single subtile."
+          (cl-loop for arg in (list nil 1) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtiles."
+          (cl-loop for arg in (list 2) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:01,100 
--> 00:00:02,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "prepending"
+        (it "a single subtile."
+          (cl-loop for arg in (list '- -1 (list 4)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtiles."
+          (cl-loop for arg in (list -2 (list -16)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:01,100 
--> 00:00:02,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
       )
-    (describe "when there is not enough time for the subtitles"
-      (describe "to append"
+    (describe "in a non-empty buffer"
+      (describe "prepending between subtitles"
+        (it "a single subtitle."
+          (cl-loop for arg in (list '- -1 (list 4)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 2)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:30,000 
--> 00:01:31,000\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtitles."
+          (cl-loop for arg in (list -2 (list 16)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 2)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:20,000 
--> 00:01:21,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:40,000 
--> 00:01:41,000\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "appending between subtitles"
         (it "a single subtitle."
           (cl-loop for arg in (list nil 1) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:59,000 --> 00:01:00,000\n"
-                                     "Foo.\n\n"
-                                     "2\n"
-                                     "00:01:00,600 --> 00:01:02,000\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle arg) :to-equal 71)
-                     (expect (buffer-string) :to-equal (concat "1\n"
-                                                               "00:00:59,000 
--> 00:01:00,000\n"
-                                                               "Foo.\n\n"
-                                                               "0\n"
-                                                               "00:01:00,100 
--> 00:01:00,500\n"
-                                                               "\n\n"
-                                                               "2\n"
-                                                               "00:01:00,600 
--> 00:01:02,000\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 71)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:30,000 
--> 00:01:31,000\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         (it "multiple subtitles."
           (cl-loop for arg in (list 2) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:59,000 --> 00:01:00,000\n"
-                                     "Foo.\n\n"
-                                     "2\n"
-                                     "00:01:00,600 --> 00:01:02,000\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle arg) :to-equal 71)
-                     (expect (buffer-string) :to-equal (concat "1\n"
-                                                               "00:00:59,000 
--> 00:01:00,000\n"
-                                                               "Foo.\n\n"
-                                                               "0\n"
-                                                               "00:01:00,100 
--> 00:01:00,250\n"
-                                                               "\n\n"
-                                                               "0\n"
-                                                               "00:01:00,350 
--> 00:01:00,500\n"
-                                                               "\n\n"
-                                                               "2\n"
-                                                               "00:01:00,600 
--> 00:01:02,000\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 71)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:20,000 
--> 00:01:21,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:40,000 
--> 00:01:41,000\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         )
-      (describe "to prepend"
-        (describe "between subtitles"
+      (describe "prepending to the first subtitle"
+        (it "a single subtitle."
+          (cl-loop for arg in (list '- -1 (list 4)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:01:00,000 --> 00:01:01,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:30,000 
--> 00:00:31,000\n"
+                                                              "\n\n"
+                                                              "1\n"
+                                                              "00:01:00,000 
--> 00:01:01,000\n"
+                                                              "Foo.\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtitles."
+          (cl-loop for arg in (list -2 (list 16)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:01:00,000 --> 00:01:01,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:20,000 
--> 00:00:21,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:40,000 
--> 00:00:41,000\n"
+                                                              "\n\n"
+                                                              "1\n"
+                                                              "00:01:00,000 
--> 00:01:01,000\n"
+                                                              "Foo.\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "appending to the last subtitle"
+        (it "a single subtitle."
+          (cl-loop for arg in (list nil 1) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtitles."
+          (cl-loop for arg in (list 2) do
+                   (with-temp-srt-buffer
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 3)
+                    (expect (subed-insert-subtitle arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:01,200 
--> 00:01:02,200\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 71))))
+        )
+      (describe "when there is not enough time for the subtitles"
+        (describe "to append"
           (it "a single subtitle."
-            (cl-loop for arg in (list '- -1 (list 4)) do
+            (cl-loop for arg in (list nil 1) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:57,000 --> 00:00:59,100\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,000 --> 00:01:02,000\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:57,000 
--> 00:00:59,100\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,200 
--> 00:00:59,900\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,000 
--> 00:01:02,000\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:59,000 --> 00:01:00,000\n"
+                                      "Foo.\n\n"
+                                      "2\n"
+                                      "00:01:00,600 --> 00:01:02,000\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle arg) :to-equal 71)
+                      (expect (buffer-string) :to-equal (concat "1\n"
+                                                                "00:00:59,000 
--> 00:01:00,000\n"
+                                                                "Foo.\n\n"
+                                                                "0\n"
+                                                                "00:01:00,100 
--> 00:01:00,500\n"
+                                                                "\n\n"
+                                                                "2\n"
+                                                                "00:01:00,600 
--> 00:01:02,000\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 71)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           (it "multiple subtitles."
-            (cl-loop for arg in (list -2 (list 16)) do
+            (cl-loop for arg in (list 2) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:57,000 --> 00:00:59,100\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,000 --> 00:01:02,000\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:57,000 
--> 00:00:59,100\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,200 
--> 00:00:59,500\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,600 
--> 00:00:59,900\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,000 
--> 00:01:02,000\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:59,000 --> 00:01:00,000\n"
+                                      "Foo.\n\n"
+                                      "2\n"
+                                      "00:01:00,600 --> 00:01:02,000\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle arg) :to-equal 71)
+                      (expect (buffer-string) :to-equal (concat "1\n"
+                                                                "00:00:59,000 
--> 00:01:00,000\n"
+                                                                "Foo.\n\n"
+                                                                "0\n"
+                                                                "00:01:00,100 
--> 00:01:00,250\n"
+                                                                "\n\n"
+                                                                "0\n"
+                                                                "00:01:00,350 
--> 00:01:00,500\n"
+                                                                "\n\n"
+                                                                "2\n"
+                                                                "00:01:00,600 
--> 00:01:02,000\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 71)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
+          )
+        (describe "to prepend"
+          (describe "between subtitles"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:57,000 --> 00:00:59,100\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,000 --> 00:01:02,000\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:57,000 --> 00:00:59,100\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,200 --> 00:00:59,900\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,000 --> 00:01:02,000\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:57,000 --> 00:00:59,100\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,000 --> 00:01:02,000\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:57,000 --> 00:00:59,100\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,200 --> 00:00:59,500\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,600 --> 00:00:59,900\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,000 --> 00:01:02,000\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          (describe "before the first subtitle"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:00,500 --> 00:00:02,000\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle arg) :to-equal 33)
+                        (expect (buffer-string) :to-equal (concat "0\n"
+                                                                  
"00:00:00,100 --> 00:00:00,400\n"
+                                                                  "\n\n"
+                                                                  "1\n"
+                                                                  
"00:00:00,500 --> 00:00:02,000\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 33)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:00,600 --> 00:00:01,500\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle arg) :to-equal 33)
+                        (expect (buffer-string) :to-equal (concat "0\n"
+                                                                  
"00:00:00,100 --> 00:00:00,250\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:00,350 --> 00:00:00,500\n"
+                                                                  "\n\n"
+                                                                  "1\n"
+                                                                  
"00:00:00,600 --> 00:00:01,500\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 33)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          )
+        )
+      (describe "when there is not enough time for spacing"
+        (describe "between subtitles"
+          (describe "when prepending"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:55,000 --> 00:00:59,950\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,000 --> 00:01:02,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:55,000 --> 00:00:59,950\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,950 --> 00:00:59,950\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,000 --> 00:01:02,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:57,000 --> 00:00:59,999\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,000 --> 00:01:02,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:57,000 --> 00:00:59,999\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,999 --> 00:00:59,999\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:59,999 --> 00:00:59,999\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,000 --> 00:01:02,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          (describe "when appending"
+            (it "a single subtitle."
+              (cl-loop for arg in (list nil 1) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,010 --> 00:01:02,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,010 --> 00:01:02,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list 2) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,100 --> 00:01:02,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle arg) :to-equal 71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,100 --> 00:01:02,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
           )
         (describe "before the first subtitle"
           (it "a single subtitle."
             (cl-loop for arg in (list '- -1 (list 4)) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:00,500 --> 00:00:02,000\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle arg) :to-equal 33)
-                       (expect (buffer-string) :to-equal (concat "0\n"
-                                                                 "00:00:00,100 
--> 00:00:00,400\n"
-                                                                 "\n\n"
-                                                                 "1\n"
-                                                                 "00:00:00,500 
--> 00:00:02,000\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 33)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:00,050 --> 00:00:02,000\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle arg) :to-equal 33)
+                      (expect (buffer-string) :to-equal (concat "0\n"
+                                                                "00:00:00,000 
--> 00:00:00,000\n"
+                                                                "\n\n"
+                                                                "1\n"
+                                                                "00:00:00,050 
--> 00:00:02,000\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 33)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           (it "multiple subtitles."
             (cl-loop for arg in (list -2 (list 16)) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:00,600 --> 00:00:01,500\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle arg) :to-equal 33)
-                       (expect (buffer-string) :to-equal (concat "0\n"
-                                                                 "00:00:00,100 
--> 00:00:00,250\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:00:00,350 
--> 00:00:00,500\n"
-                                                                 "\n\n"
-                                                                 "1\n"
-                                                                 "00:00:00,600 
--> 00:00:01,500\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 33)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:00,100 --> 00:00:01,500\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle arg) :to-equal 33)
+                      (expect (buffer-string) :to-equal (concat "0\n"
+                                                                "00:00:00,000 
--> 00:00:00,000\n"
+                                                                "\n\n"
+                                                                "0\n"
+                                                                "00:00:00,000 
--> 00:00:00,000\n"
+                                                                "\n\n"
+                                                                "1\n"
+                                                                "00:00:00,100 
--> 00:00:01,500\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 33)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           )
         )
       )
-    (describe "when there is not enough time for spacing"
-      (describe "between subtitles"
-        (describe "when prepending"
-          (it "a single subtitle."
-            (cl-loop for arg in (list '- -1 (list 4)) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:55,000 --> 00:00:59,950\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,000 --> 00:01:02,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:55,000 
--> 00:00:59,950\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,950 
--> 00:00:59,950\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,000 
--> 00:01:02,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          (it "multiple subtitles."
-            (cl-loop for arg in (list -2 (list 16)) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:57,000 --> 00:00:59,999\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,000 --> 00:01:02,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:57,000 
--> 00:00:59,999\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,999 
--> 00:00:59,999\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:00:59,999 
--> 00:00:59,999\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,000 
--> 00:01:02,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          )
-        (describe "when appending"
-          (it "a single subtitle."
-            (cl-loop for arg in (list nil 1) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,010 --> 00:01:02,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,010 
--> 00:01:02,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          (it "multiple subtitles."
-            (cl-loop for arg in (list 2) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,100 --> 00:01:02,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle arg) :to-equal 71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,100 
--> 00:01:02,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          )
+    )
+
+  (describe "Inserting adjacent"
+    (describe "in an empty buffer,"
+      (describe "appending"
+        (it "a single subtile."
+          (cl-loop for arg in (list nil 1) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtiles."
+          (cl-loop for arg in (list 2) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:01,100 
--> 00:00:02,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "prepending"
+        (it "a single subtile."
+          (cl-loop for arg in (list '- -1 (list 4)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtiles."
+          (cl-loop for arg in (list -2 (list -16)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:00,000 
--> 00:00:01,000\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:01,100 
--> 00:00:02,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         )
-      (describe "before the first subtitle"
+      )
+    (describe "in a non-empty buffer"
+      (describe "prepending between subtitles"
         (it "a single subtitle."
           (cl-loop for arg in (list '- -1 (list 4)) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:00,050 --> 00:00:02,000\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle arg) :to-equal 33)
-                     (expect (buffer-string) :to-equal (concat "0\n"
-                                                               "00:00:00,000 
--> 00:00:00,000\n"
-                                                               "\n\n"
-                                                               "1\n"
-                                                               "00:00:00,050 
--> 00:00:02,000\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 33)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 2)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:58,900 
--> 00:01:59,900\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         (it "multiple subtitles."
           (cl-loop for arg in (list -2 (list 16)) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:00,100 --> 00:00:01,500\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle arg) :to-equal 33)
-                     (expect (buffer-string) :to-equal (concat "0\n"
-                                                               "00:00:00,000 
--> 00:00:00,000\n"
-                                                               "\n\n"
-                                                               "0\n"
-                                                               "00:00:00,000 
--> 00:00:00,000\n"
-                                                               "\n\n"
-                                                               "1\n"
-                                                               "00:00:00,100 
--> 00:00:01,500\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 33)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 2)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:57,800 
--> 00:01:58,800\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:58,900 
--> 00:01:59,900\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         )
-      )
-    )
-  )
-
-(describe "Inserting adjacent"
-  (describe "in an empty buffer,"
-    (describe "appending"
-      (it "a single subtile."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtiles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:01,100 --> 
00:00:02,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "prepending"
-      (it "a single subtile."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtiles."
-        (cl-loop for arg in (list -2 (list -16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:00,000 --> 
00:00:01,000\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:01,100 --> 
00:00:02,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    )
-  (describe "in a non-empty buffer"
-    (describe "prepending between subtitles"
-      (it "a single subtitle."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 2)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:58,900 --> 
00:01:59,900\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list -2 (list 16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 2)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:57,800 --> 
00:01:58,800\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:58,900 --> 
00:01:59,900\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "appending between subtitles"
-      (it "a single subtitle."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n\n"
-                                   "2\n"
-                                   "00:02:00,000 --> 00:02:01,000\n"
-                                   "Bar.\n"))
-                   (subed-jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:01,200 --> 
00:01:02,200\n"
-                                                             "\n\n"
-                                                             "2\n"
-                                                             "00:02:00,000 --> 
00:02:01,000\n"
-                                                             "Bar.\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "prepending to the first subtitle"
-      (it "a single subtitle."
-        (cl-loop for arg in (list '- -1 (list 4)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:01:00,000 --> 00:01:01,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:58,900 --> 
00:00:59,900\n"
-                                                             "\n\n"
-                                                             "1\n"
-                                                             "00:01:00,000 --> 
00:01:01,000\n"
-                                                             "Foo.\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list -2 (list 16)) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:01:00,000 --> 00:01:01,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                   (expect (buffer-string) :to-equal (concat "0\n"
-                                                             "00:00:57,800 --> 
00:00:58,800\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:00:58,900 --> 
00:00:59,900\n"
-                                                             "\n\n"
-                                                             "1\n"
-                                                             "00:01:00,000 --> 
00:01:01,000\n"
-                                                             "Foo.\n"))
-                   (expect (point) :to-equal 33)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "appending to the last subtitle"
-      (it "a single subtitle."
-        (cl-loop for arg in (list nil 1) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 1)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      (it "multiple subtitles."
-        (cl-loop for arg in (list 2) do
-                 (with-temp-srt-buffer
-                   (spy-on 'subed-regenerate-ids-soon)
-                   (insert (concat "1\n"
-                                   "00:00:59,000 --> 00:01:00,000\n"
-                                   "Foo.\n"))
-                   (subed-srt--jump-to-subtitle-text 3)
-                   (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                   (expect (buffer-string) :to-equal (concat "1\n"
-                                                             "00:00:59,000 --> 
00:01:00,000\n"
-                                                             "Foo.\n\n"
-                                                             "0\n"
-                                                             "00:01:00,100 --> 
00:01:01,100\n"
-                                                             "\n\n"
-                                                             "0\n"
-                                                             "00:01:01,200 --> 
00:01:02,200\n"
-                                                             "\n"))
-                   (expect (point) :to-equal 71)
-                   (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                   (spy-calls-reset 'subed-regenerate-ids-soon))))
-      )
-    (describe "when there is not enough time for the subtitles"
-      (describe "to append"
+      (describe "appending between subtitles"
         (it "a single subtitle."
           (cl-loop for arg in (list nil 1) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:59,000 --> 00:01:00,000\n"
-                                     "Foo.\n\n"
-                                     "2\n"
-                                     "00:01:00,500 --> 00:01:05,000\n"
-                                     "Bar.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                     (expect (buffer-string) :to-equal (concat "1\n"
-                                                               "00:00:59,000 
--> 00:01:00,000\n"
-                                                               "Foo.\n\n"
-                                                               "0\n"
-                                                               "00:01:00,100 
--> 00:01:00,400\n"
-                                                               "\n\n"
-                                                               "2\n"
-                                                               "00:01:00,500 
--> 00:01:05,000\n"
-                                                               "Bar.\n"))
-                     (expect (point) :to-equal 71)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         (it "multiple subtitles."
           (cl-loop for arg in (list 2) do
                    (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:59,000 --> 00:01:00,000\n"
-                                     "Foo.\n\n"
-                                     "2\n"
-                                     "00:01:00,500 --> 00:01:05,000\n"
-                                     "Bar.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
-                     (expect (buffer-string) :to-equal (concat "1\n"
-                                                               "00:00:59,000 
--> 00:01:00,000\n"
-                                                               "Foo.\n\n"
-                                                               "0\n"
-                                                               "00:01:00,100 
--> 00:01:00,200\n"
-                                                               "\n\n"
-                                                               "0\n"
-                                                               "00:01:00,300 
--> 00:01:00,400\n"
-                                                               "\n\n"
-                                                               "2\n"
-                                                               "00:01:00,500 
--> 00:01:05,000\n"
-                                                               "Bar.\n"))
-                     (expect (point) :to-equal 71)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n\n"
+                                    "2\n"
+                                    "00:02:00,000 --> 00:02:01,000\n"
+                                    "Bar.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:01,200 
--> 00:01:02,200\n"
+                                                              "\n\n"
+                                                              "2\n"
+                                                              "00:02:00,000 
--> 00:02:01,000\n"
+                                                              "Bar.\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
         )
-      (describe "to prepend"
-        (describe "between subtitles"
+      (describe "prepending to the first subtitle"
+        (it "a single subtitle."
+          (cl-loop for arg in (list '- -1 (list 4)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:01:00,000 --> 00:01:01,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:58,900 
--> 00:00:59,900\n"
+                                                              "\n\n"
+                                                              "1\n"
+                                                              "00:01:00,000 
--> 00:01:01,000\n"
+                                                              "Foo.\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtitles."
+          (cl-loop for arg in (list -2 (list 16)) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:01:00,000 --> 00:01:01,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
+                    (expect (buffer-string) :to-equal (concat "0\n"
+                                                              "00:00:57,800 
--> 00:00:58,800\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:00:58,900 
--> 00:00:59,900\n"
+                                                              "\n\n"
+                                                              "1\n"
+                                                              "00:01:00,000 
--> 00:01:01,000\n"
+                                                              "Foo.\n"))
+                    (expect (point) :to-equal 33)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "appending to the last subtitle"
+        (it "a single subtitle."
+          (cl-loop for arg in (list nil 1) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 1)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (it "multiple subtitles."
+          (cl-loop for arg in (list 2) do
+                   (with-temp-srt-buffer
+                    (spy-on 'subed-regenerate-ids-soon)
+                    (insert (concat "1\n"
+                                    "00:00:59,000 --> 00:01:00,000\n"
+                                    "Foo.\n"))
+                    (subed-jump-to-subtitle-text 3)
+                    (expect (subed-insert-subtitle-adjacent arg) :to-equal 71)
+                    (expect (buffer-string) :to-equal (concat "1\n"
+                                                              "00:00:59,000 
--> 00:01:00,000\n"
+                                                              "Foo.\n\n"
+                                                              "0\n"
+                                                              "00:01:00,100 
--> 00:01:01,100\n"
+                                                              "\n\n"
+                                                              "0\n"
+                                                              "00:01:01,200 
--> 00:01:02,200\n"
+                                                              "\n"))
+                    (expect (point) :to-equal 71)
+                    (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                    (spy-calls-reset 'subed-regenerate-ids-soon))))
+        )
+      (describe "when there is not enough time for the subtitles"
+        (describe "to append"
           (it "a single subtitle."
-            (cl-loop for arg in (list '- -1 (list 4)) do
+            (cl-loop for arg in (list nil 1) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,700 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,100 
--> 00:01:00,600\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,700 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:59,000 --> 00:01:00,000\n"
+                                      "Foo.\n\n"
+                                      "2\n"
+                                      "00:01:00,500 --> 00:01:05,000\n"
+                                      "Bar.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                      (expect (buffer-string) :to-equal (concat "1\n"
+                                                                "00:00:59,000 
--> 00:01:00,000\n"
+                                                                "Foo.\n\n"
+                                                                "0\n"
+                                                                "00:01:00,100 
--> 00:01:00,400\n"
+                                                                "\n\n"
+                                                                "2\n"
+                                                                "00:01:00,500 
--> 00:01:05,000\n"
+                                                                "Bar.\n"))
+                      (expect (point) :to-equal 71)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           (it "multiple subtitles."
-            (cl-loop for arg in (list -2 (list 16)) do
+            (cl-loop for arg in (list 2) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,500 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,100 
--> 00:01:00,200\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,300 
--> 00:01:00,400\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,500 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:59,000 --> 00:01:00,000\n"
+                                      "Foo.\n\n"
+                                      "2\n"
+                                      "00:01:00,500 --> 00:01:05,000\n"
+                                      "Bar.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                      (expect (buffer-string) :to-equal (concat "1\n"
+                                                                "00:00:59,000 
--> 00:01:00,000\n"
+                                                                "Foo.\n\n"
+                                                                "0\n"
+                                                                "00:01:00,100 
--> 00:01:00,200\n"
+                                                                "\n\n"
+                                                                "0\n"
+                                                                "00:01:00,300 
--> 00:01:00,400\n"
+                                                                "\n\n"
+                                                                "2\n"
+                                                                "00:01:00,500 
--> 00:01:05,000\n"
+                                                                "Bar.\n"))
+                      (expect (point) :to-equal 71)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           )
-        (describe "before the first subtitle"
-          (it "a single subtitle."
-            (cl-loop for arg in (list '- -1 (list 4)) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:01,000 --> 00:00:02,000\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
-                       (expect (buffer-string) :to-equal (concat "0\n"
-                                                                 "00:00:00,100 
--> 00:00:00,900\n"
-                                                                 "\n\n"
-                                                                 "1\n"
-                                                                 "00:00:01,000 
--> 00:00:02,000\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 33)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          (it "multiple subtitles."
-            (cl-loop for arg in (list -2 (list 16)) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:00,800 --> 00:00:03,000\n"
-                                       "Foo.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
-                       (expect (buffer-string) :to-equal (concat "0\n"
-                                                                 "00:00:00,100 
--> 00:00:00,350\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:00:00,450 
--> 00:00:00,700\n"
-                                                                 "\n\n"
-                                                                 "1\n"
-                                                                 "00:00:00,800 
--> 00:00:03,000\n"
-                                                                 "Foo.\n"))
-                       (expect (point) :to-equal 33)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+        (describe "to prepend"
+          (describe "between subtitles"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,700 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,100 --> 00:01:00,600\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,700 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,500 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,100 --> 00:01:00,200\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,300 --> 00:01:00,400\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,500 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          (describe "before the first subtitle"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:01,000 --> 00:00:02,000\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
+                        (expect (buffer-string) :to-equal (concat "0\n"
+                                                                  
"00:00:00,100 --> 00:00:00,900\n"
+                                                                  "\n\n"
+                                                                  "1\n"
+                                                                  
"00:00:01,000 --> 00:00:02,000\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 33)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:00,800 --> 00:00:03,000\n"
+                                        "Foo.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
+                        (expect (buffer-string) :to-equal (concat "0\n"
+                                                                  
"00:00:00,100 --> 00:00:00,350\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:00:00,450 --> 00:00:00,700\n"
+                                                                  "\n\n"
+                                                                  "1\n"
+                                                                  
"00:00:00,800 --> 00:00:03,000\n"
+                                                                  "Foo.\n"))
+                        (expect (point) :to-equal 33)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
           )
         )
-      )
-    (describe "when there is not enough time for spacing"
-      (describe "between subtitles"
-        (describe "when prepending"
+      (describe "when there is not enough time for spacing"
+        (describe "between subtitles"
+          (describe "when prepending"
+            (it "a single subtitle."
+              (cl-loop for arg in (list '- -1 (list 4)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,005 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,005 --> 00:01:00,005\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,005 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list -2 (list 16)) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,025 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 2)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,025 --> 00:01:00,025\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,025 --> 00:01:00,025\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,025 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          (describe "when appending"
+            (it "a single subtitle."
+              (cl-loop for arg in (list nil 1) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,099 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,099 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            (it "multiple subtitles."
+              (cl-loop for arg in (list 2) do
+                       (with-temp-srt-buffer
+                        (spy-on 'subed-regenerate-ids-soon)
+                        (insert (concat "1\n"
+                                        "00:00:59,000 --> 00:01:00,000\n"
+                                        "Foo.\n\n"
+                                        "2\n"
+                                        "00:01:00,075 --> 00:01:05,000\n"
+                                        "Bar.\n"))
+                        (subed-jump-to-subtitle-text 1)
+                        (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
+                        (expect (buffer-string) :to-equal (concat "1\n"
+                                                                  
"00:00:59,000 --> 00:01:00,000\n"
+                                                                  "Foo.\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "0\n"
+                                                                  
"00:01:00,000 --> 00:01:00,000\n"
+                                                                  "\n\n"
+                                                                  "2\n"
+                                                                  
"00:01:00,075 --> 00:01:05,000\n"
+                                                                  "Bar.\n"))
+                        (expect (point) :to-equal 71)
+                        (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                        (spy-calls-reset 'subed-regenerate-ids-soon))))
+            )
+          )
+        (describe "before the first subtitle"
           (it "a single subtitle."
             (cl-loop for arg in (list '- -1 (list 4)) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,005 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,005 
--> 00:01:00,005\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,005 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:00,040 --> 00:00:05,000\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
+                      (expect (buffer-string) :to-equal (concat "0\n"
+                                                                "00:00:00,040 
--> 00:00:00,040\n"
+                                                                "\n\n"
+                                                                "1\n"
+                                                                "00:00:00,040 
--> 00:00:05,000\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 33)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           (it "multiple subtitles."
             (cl-loop for arg in (list -2 (list 16)) do
                      (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,025 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 2)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,025 
--> 00:01:00,025\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,025 
--> 00:01:00,025\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,025 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          )
-        (describe "when appending"
-          (it "a single subtitle."
-            (cl-loop for arg in (list nil 1) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,099 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,099 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
-          (it "multiple subtitles."
-            (cl-loop for arg in (list 2) do
-                     (with-temp-srt-buffer
-                       (spy-on 'subed-regenerate-ids-soon)
-                       (insert (concat "1\n"
-                                       "00:00:59,000 --> 00:01:00,000\n"
-                                       "Foo.\n\n"
-                                       "2\n"
-                                       "00:01:00,075 --> 00:01:05,000\n"
-                                       "Bar.\n"))
-                       (subed-srt--jump-to-subtitle-text 1)
-                       (expect (subed-insert-subtitle-adjacent arg) :to-equal 
71)
-                       (expect (buffer-string) :to-equal (concat "1\n"
-                                                                 "00:00:59,000 
--> 00:01:00,000\n"
-                                                                 "Foo.\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "0\n"
-                                                                 "00:01:00,000 
--> 00:01:00,000\n"
-                                                                 "\n\n"
-                                                                 "2\n"
-                                                                 "00:01:00,075 
--> 00:01:05,000\n"
-                                                                 "Bar.\n"))
-                       (expect (point) :to-equal 71)
-                       (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                       (spy-calls-reset 'subed-regenerate-ids-soon))))
+                      (spy-on 'subed-regenerate-ids-soon)
+                      (insert (concat "1\n"
+                                      "00:00:00,024 --> 00:00:05,000\n"
+                                      "Foo.\n"))
+                      (subed-jump-to-subtitle-text 1)
+                      (expect (subed-insert-subtitle-adjacent arg) :to-equal 
33)
+                      (expect (buffer-string) :to-equal (concat "0\n"
+                                                                "00:00:00,024 
--> 00:00:00,024\n"
+                                                                "\n\n"
+                                                                "0\n"
+                                                                "00:00:00,024 
--> 00:00:00,024\n"
+                                                                "\n\n"
+                                                                "1\n"
+                                                                "00:00:00,024 
--> 00:00:05,000\n"
+                                                                "Foo.\n"))
+                      (expect (point) :to-equal 33)
+                      (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
+                      (spy-calls-reset 'subed-regenerate-ids-soon))))
           )
         )
-      (describe "before the first subtitle"
-        (it "a single subtitle."
-          (cl-loop for arg in (list '- -1 (list 4)) do
-                   (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:00,040 --> 00:00:05,000\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                     (expect (buffer-string) :to-equal (concat "0\n"
-                                                               "00:00:00,040 
--> 00:00:00,040\n"
-                                                               "\n\n"
-                                                               "1\n"
-                                                               "00:00:00,040 
--> 00:00:05,000\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 33)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
-        (it "multiple subtitles."
-          (cl-loop for arg in (list -2 (list 16)) do
-                   (with-temp-srt-buffer
-                     (spy-on 'subed-regenerate-ids-soon)
-                     (insert (concat "1\n"
-                                     "00:00:00,024 --> 00:00:05,000\n"
-                                     "Foo.\n"))
-                     (subed-srt--jump-to-subtitle-text 1)
-                     (expect (subed-insert-subtitle-adjacent arg) :to-equal 33)
-                     (expect (buffer-string) :to-equal (concat "0\n"
-                                                               "00:00:00,024 
--> 00:00:00,024\n"
-                                                               "\n\n"
-                                                               "0\n"
-                                                               "00:00:00,024 
--> 00:00:00,024\n"
-                                                               "\n\n"
-                                                               "1\n"
-                                                               "00:00:00,024 
--> 00:00:05,000\n"
-                                                               "Foo.\n"))
-                     (expect (point) :to-equal 33)
-                     (expect 'subed-regenerate-ids-soon 
:to-have-been-called-times 1)
-                     (spy-calls-reset 'subed-regenerate-ids-soon))))
-        )
       )
     )
-  )
-
-(describe "Syncing player to point"
-  :var (subed-mpv-playback-position)
-  (before-each
-    (setq subed-mpv-playback-position 0)
-    (spy-on 'subed-subtitle-msecs-start :and-return-value 5000)
-    (spy-on 'subed-subtitle-msecs-stop :and-return-value 6500)
-    (spy-on 'subed-mpv-jump))
-  (it "does not seek player if point is on current subtitle."
-    (setq subed-mpv-playback-position 5000)
-    (subed--sync-player-to-point)
-    (expect 'subed-mpv-jump :not :to-have-been-called)
-    (setq subed-mpv-playback-position 6500)
-    (subed--sync-player-to-point)
-    (expect 'subed-mpv-jump :not :to-have-been-called))
-  (it "seeks player if point is on future subtitle."
-    (subed-srt--init)
-    (setq subed-mpv-playback-position 6501)
-    (subed--sync-player-to-point)
-    (expect 'subed-mpv-jump :to-have-been-called-with 5000))
-  (it "seeks player if point is on past subtitle."
-    (subed-srt--init)
-    (setq subed-mpv-playback-position 4999)
-    (subed--sync-player-to-point)
-    (expect 'subed-mpv-jump :to-have-been-called-with 5000))
-  )
 
-(describe "Temporarily disabling point-to-player syncing"
-  (before-each
-    (spy-on 'subed-disable-sync-point-to-player))
-  (describe "when point-to-player syncing is disabled"
+  (describe "Syncing player to point"
+    :var (subed-mpv-playback-position)
     (before-each
-      (spy-on 'subed-sync-point-to-player-p :and-return-value nil)
-      (spy-on 'run-at-time))
-    (it "does not disable point-to-player syncing."
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'subed-disable-sync-point-to-player :not :to-have-been-called))
-    (it "does not schedule re-enabling of point-to-player syncing."
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'run-at-time :not :to-have-been-called)
-      (expect subed--point-sync-delay-after-motion-timer :to-be nil))
+      (setq subed-mpv-playback-position 0)
+      (spy-on 'subed-subtitle-msecs-start :and-return-value 5000)
+      (spy-on 'subed-subtitle-msecs-stop :and-return-value 6500)
+      (spy-on 'subed-mpv-jump))
+    (it "does not seek player if point is on current subtitle."
+      (setq subed-mpv-playback-position 5000)
+      (subed--sync-player-to-point)
+      (expect 'subed-mpv-jump :not :to-have-been-called)
+      (setq subed-mpv-playback-position 6500)
+      (subed--sync-player-to-point)
+      (expect 'subed-mpv-jump :not :to-have-been-called))
+    (it "seeks player if point is on future subtitle."
+      (with-temp-buffer
+        (subed-srt-mode)
+        (setq subed-mpv-playback-position 6501)
+        (subed--sync-player-to-point)
+        (expect 'subed-mpv-jump :to-have-been-called-with 5000)))
+    (it "seeks player if point is on past subtitle."
+      (with-temp-buffer
+        (subed-srt-mode)
+        (setq subed-mpv-playback-position 4999)
+        (subed--sync-player-to-point)
+        (expect 'subed-mpv-jump :to-have-been-called-with 5000)))
     )
-  (describe "when point-to-player syncing is enabled"
-    :var (subed--point-sync-delay-after-motion-timer)
+
+  (describe "Temporarily disabling point-to-player syncing"
     (before-each
-      (spy-on 'subed-sync-point-to-player-p :and-return-value t)
-      (spy-on 'run-at-time :and-return-value "mock timer")
-      (spy-on 'cancel-timer)
-      (setq subed--point-sync-delay-after-motion-timer nil))
-    (it "disables point-to-player syncing."
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'subed-disable-sync-point-to-player :to-have-been-called))
-    (it "schedules re-enabling of point-to-player syncing."
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'run-at-time :to-have-been-called-with
-              subed-point-sync-delay-after-motion nil
-              '(closure (t) nil
-                        (setq subed--point-sync-delay-after-motion-timer nil)
-                        (subed-enable-sync-point-to-player :quiet))))
-    (it "cancels previously scheduled re-enabling of point-to-player syncing."
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'cancel-timer :not :to-have-been-called-with "mock timer")
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'cancel-timer :to-have-been-called-with "mock timer")
-      (expect 'cancel-timer :to-have-been-called-times 1)
-      (subed-disable-sync-point-to-player-temporarily)
-      (expect 'cancel-timer :to-have-been-called-with "mock timer")
-      (expect 'cancel-timer :to-have-been-called-times 2))
+      (spy-on 'subed-disable-sync-point-to-player))
+    (describe "when point-to-player syncing is disabled"
+      (before-each
+        (spy-on 'subed-sync-point-to-player-p :and-return-value nil)
+        (spy-on 'run-at-time))
+      (it "does not disable point-to-player syncing."
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'subed-disable-sync-point-to-player :not :to-have-been-called))
+      (it "does not schedule re-enabling of point-to-player syncing."
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'run-at-time :not :to-have-been-called)
+        (expect subed--point-sync-delay-after-motion-timer :to-be nil))
+      )
+    (describe "when point-to-player syncing is enabled"
+      :var (subed--point-sync-delay-after-motion-timer)
+      (before-each
+        (spy-on 'subed-sync-point-to-player-p :and-return-value t)
+        (spy-on 'run-at-time :and-return-value "mock timer")
+        (spy-on 'cancel-timer)
+        (setq subed--point-sync-delay-after-motion-timer nil))
+      (it "disables point-to-player syncing."
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'subed-disable-sync-point-to-player :to-have-been-called))
+      (it "schedules re-enabling of point-to-player syncing."
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'run-at-time :to-have-been-called)
+        ;; Does not play well with undercover and edebug
+        ;; (expect 'run-at-time :to-have-been-called-with
+        ;;         subed-point-sync-delay-after-motion nil
+        ;;         '(closure (t) nil
+        ;;                   (setq subed--point-sync-delay-after-motion-timer 
nil)
+        ;;                   (subed-enable-sync-point-to-player :quiet)))
+        )
+      (it "cancels previously scheduled re-enabling of point-to-player 
syncing."
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'cancel-timer :not :to-have-been-called-with "mock timer")
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'cancel-timer :to-have-been-called-with "mock timer")
+        (expect 'cancel-timer :to-have-been-called-times 1)
+        (subed-disable-sync-point-to-player-temporarily)
+        (expect 'cancel-timer :to-have-been-called-with "mock timer")
+        (expect 'cancel-timer :to-have-been-called-times 2))
+      )
     )
-  )
 
-(describe "Splitting subtitles"
-  (it "handles empty subtitles"
-    (with-temp-srt-buffer
-     (insert "1
+  (describe "Splitting subtitles"
+    (it "handles empty subtitles"
+      (with-temp-srt-buffer
+       (insert "1
 00:01:23,000 --> 00:02:34,567
 
 ")
-     (forward-line -1)
-     (let ((subed-subtitle-spacing 100))
-       (subed-split-subtitle 100))
-     (expect (buffer-string) :to-equal
-"1
+       (forward-line -1)
+       (let ((subed-subtitle-spacing 100))
+         (subed-split-subtitle 100))
+       (expect (buffer-string) :to-equal
+               "1
 00:01:23,000 --> 00:01:23,100
 
 
@@ -2153,22 +2165,22 @@ Baz.
 00:01:23,200 --> 00:02:34,567
 
 ")))
-  (describe "when there are multiple lines"
-    (describe "at the last subtitle"
-      :var ((text "1
+    (describe "when there are multiple lines"
+      (describe "at the last subtitle"
+        :var ((text "1
 00:01:23,000 --> 00:02:34,567
 This is a subtitle
 that has two lines.
 
 ")
-            (subed-subtitle-spacing 100))
-      (it "properly splits text when called at the beginning of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a subtitle")
-         (goto-char (match-beginning 0))
-         (save-excursion (subed-split-subtitle 100))
-         (expect (buffer-string) :to-equal "1
+              (subed-subtitle-spacing 100))
+        (it "properly splits text when called at the beginning of the 
subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a subtitle")
+           (goto-char (match-beginning 0))
+           (save-excursion (subed-split-subtitle 100))
+           (expect (buffer-string) :to-equal "1
 00:01:23,000 --> 00:01:23,100
 
 
@@ -2177,31 +2189,31 @@ that has two lines.
 This is a subtitle
 that has two lines.
 ")))
-      (it "properly splits text when called in the middle of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a")
-         (goto-char (match-end 0))
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "subtitle\nthat has two 
lines.")))
-      (it "properly splits text when called at the end of a line in the middle 
of the subtitle"
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a subtitle")
-         (goto-char (match-end 0))
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
-      (it "properly splits text when called at the beginning of a line in the 
middle of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "that has two lines")
-         (goto-char (match-beginning 0))
-         (subed-split-subtitle 100)
-         (expect (buffer-string) :to-equal "1
+        (it "properly splits text when called in the middle of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a")
+           (goto-char (match-end 0))
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "subtitle\nthat has two 
lines.")))
+        (it "properly splits text when called at the end of a line in the 
middle of the subtitle"
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a subtitle")
+           (goto-char (match-end 0))
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
+        (it "properly splits text when called at the beginning of a line in 
the middle of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "that has two lines")
+           (goto-char (match-beginning 0))
+           (subed-split-subtitle 100)
+           (expect (buffer-string) :to-equal "1
 00:01:23,000 --> 00:01:23,100
 This is a subtitle
 
@@ -2209,27 +2221,27 @@ This is a subtitle
 00:01:23,200 --> 00:02:34,567
 that has two lines.
 ")  (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
-      (it "properly splits text when called at the end of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (subed-jump-to-subtitle-end 1)
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "")))
-      (it "properly splits text when called before whitespace at the end of 
the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (subed-jump-to-subtitle-end 1)
-         (save-excursion (insert "  "))
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal ""))))
-    (describe "with another subtitle after it"
-      :var ((text "1
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
+        (it "properly splits text when called at the end of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (subed-jump-to-subtitle-end 1)
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "")))
+        (it "properly splits text when called before whitespace at the end of 
the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (subed-jump-to-subtitle-end 1)
+           (save-excursion (insert "  "))
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal ""))))
+      (describe "with another subtitle after it"
+        :var ((text "1
 00:01:23,000 --> 00:02:34,567
 This is a subtitle
 that has two lines.
@@ -2238,14 +2250,14 @@ that has two lines.
 00:05:00,000 --> 00:06:00,000
 This is another.
 ")
-            (subed-subtitle-spacing 100))
-      (it "properly splits text when called at the beginning of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a subtitle")
-         (goto-char (match-beginning 0))
-         (save-excursion (subed-split-subtitle 100))
-         (expect (buffer-string) :to-equal "1
+              (subed-subtitle-spacing 100))
+        (it "properly splits text when called at the beginning of the 
subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a subtitle")
+           (goto-char (match-beginning 0))
+           (save-excursion (subed-split-subtitle 100))
+           (expect (buffer-string) :to-equal "1
 00:01:23,000 --> 00:01:23,100
 
 0
@@ -2257,32 +2269,32 @@ that has two lines.
 00:05:00,000 --> 00:06:00,000
 This is another.
 ")))
-      (it "properly splits text when called in the middle of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a subtitle")
-         (goto-char (match-end 0))
-         (backward-word 1)
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "subtitle\nthat has two 
lines.")))
-      (it "properly splits text when called at the end of a line in the middle 
of the subtitle"
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "This is a subtitle")
-         (goto-char (match-end 0))
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
-      (it "properly splits text when called at the beginning of a line in the 
middle of the subtitle."
-        (with-temp-srt-buffer
-         (insert text)
-         (re-search-backward "that has two lines")
-         (goto-char (match-beginning 0))
-         (subed-split-subtitle 100)
-         (expect (buffer-string) :to-equal "1
+        (it "properly splits text when called in the middle of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a subtitle")
+           (goto-char (match-end 0))
+           (backward-word 1)
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "subtitle\nthat has two 
lines.")))
+        (it "properly splits text when called at the end of a line in the 
middle of the subtitle"
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "This is a subtitle")
+           (goto-char (match-end 0))
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
+        (it "properly splits text when called at the beginning of a line in 
the middle of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (re-search-backward "that has two lines")
+           (goto-char (match-beginning 0))
+           (subed-split-subtitle 100)
+           (expect (buffer-string) :to-equal "1
 00:01:23,000 --> 00:01:23,100
 This is a subtitle
 
@@ -2294,326 +2306,326 @@ that has two lines.
 00:05:00,000 --> 00:06:00,000
 This is another.
 ")  (expect (subed-subtitle-text 1) :to-equal "This is a subtitle")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
-      (it "properly splits text when called at the end of the subtitle."
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "that has two lines.")))
+        (it "properly splits text when called at the end of the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (subed-jump-to-subtitle-end 1)
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "")))
+        (it "properly splits text when called before whitespace at the end of 
the subtitle."
+          (with-temp-srt-buffer
+           (insert text)
+           (subed-jump-to-subtitle-end 1)
+           (save-excursion (insert "  "))
+           (subed-split-subtitle 100)
+           (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
+           (subed-regenerate-ids)
+           (expect (subed-subtitle-text 2) :to-equal "")))))
+    (describe "when playing the video in MPV"
+      (it "splits at point in the middle of the subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (end-of-line)
+         (save-excursion (insert " Some text here."))
+         (setq-local subed-mpv-playback-position 61600)
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle)
+         (expect (subed-subtitle-msecs-start) :to-equal 61700)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (expect (subed-subtitle-text) :to-equal "Some text here.")
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-msecs-stop) :to-equal 61600)
+         (expect (subed-subtitle-text) :to-equal "Foo.")))
+      (it "splits at the end even if there are spaces."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (subed-jump-to-subtitle-end)
+         (insert " ")
+         (setq-local subed-mpv-playback-position 61600)
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle)
+         (expect (subed-subtitle-text) :to-equal "")
+         (expect (subed-subtitle-msecs-start) :to-equal 61700)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-text) :to-equal "Foo.")
+         (expect (subed-subtitle-msecs-stop) :to-equal 61600)))
+      (it "splits at the beginning."
+        (with-temp-srt-buffer
+         (save-excursion (insert mock-srt-data))
+         (subed-jump-to-subtitle-text)
+         (setq-local subed-mpv-playback-position 61600)
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle)
+         (expect (subed-subtitle-text) :to-equal "Foo.")
+         (expect (subed-subtitle-msecs-start) :to-equal 61700)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-text) :to-equal "")
+         (expect (subed-subtitle-msecs-stop) :to-equal 61600))))
+    (describe "when a positive offset is specified"
+      (it "splits from the starting time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (end-of-line)
+         (save-excursion (insert " Some text here."))
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle 300)
+         (expect (subed-subtitle-msecs-start) :to-equal 61400)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (expect (subed-subtitle-text) :to-equal "Some text here.")
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-msecs-stop) :to-equal 61300)
+         (expect (subed-subtitle-text) :to-equal "Foo.")))
+      (it "uses the offset instead of the playing position."
         (with-temp-srt-buffer
-         (insert text)
-         (subed-jump-to-subtitle-end 1)
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "")))
-      (it "properly splits text when called before whitespace at the end of 
the subtitle."
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (setq-local subed-mpv-playback-position 61600)
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle 300)
+         (expect (subed-subtitle-msecs-start) :to-equal 61400)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123))))
+    (describe "when a negative offset is specified"
+      (it "splits from the ending time."
         (with-temp-srt-buffer
-         (insert text)
-         (subed-jump-to-subtitle-end 1)
-         (save-excursion (insert "  "))
-         (subed-split-subtitle 100)
-         (expect (subed-subtitle-text 1) :to-equal "This is a subtitle\nthat 
has two lines.")
-         (subed-regenerate-ids)
-         (expect (subed-subtitle-text 2) :to-equal "")))))
-  (describe "when playing the video in MPV"
-    (it "splits at point in the middle of the subtitle."
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (end-of-line)
+         (save-excursion (insert " Some text here."))
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle -300)
+         (expect (subed-subtitle-msecs-start) :to-equal 64923)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (expect (subed-subtitle-text) :to-equal "Some text here.")
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-msecs-stop) :to-equal 64823)
+         (expect (subed-subtitle-text) :to-equal "Foo.")))
+      (it "uses the offset instead of the playing position."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (setq-local subed-subtitle-spacing 100)
+         (setq-local subed-mpv-playback-position 61600)
+         (subed-split-subtitle -300)
+         (expect (subed-subtitle-msecs-start) :to-equal 64923)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-msecs-stop) :to-equal 64823))))
+    (describe "when nothing is specified"
+      (it "splits proportional to the location."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (re-search-backward "Foo\\.")
+         (end-of-line)
+         (save-excursion (insert " Bar"))
+         (setq-local subed-subtitle-spacing 100)
+         (subed-split-subtitle)
+         (expect (subed-subtitle-msecs-start) :to-equal 63161)
+         (expect (subed-subtitle-msecs-stop) :to-equal 65123)
+         (expect (subed-subtitle-text) :to-equal "Bar")
+         (subed-backward-subtitle-time-start)
+         (expect (subed-subtitle-msecs-stop) :to-equal 63061)
+         (expect (subed-subtitle-text) :to-equal "Foo.")))))
+
+  (describe "Scaling subtitles"
+    (it "without providing beginning and end."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (end-of-line)
-        (save-excursion (insert " Some text here."))
-        (setq-local subed-mpv-playback-position 61600)
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle)
-        (expect (subed-subtitle-msecs-start) :to-equal 61700)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (expect (subed-subtitle-text) :to-equal "Some text here.")
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-msecs-stop) :to-equal 61600)
-        (expect (subed-subtitle-text) :to-equal "Foo.")))
-    (it "splits at the end even if there are spaces."
+       (insert mock-srt-data)
+       (spy-on 'subed-scale-subtitles :and-call-through)
+       (subed-scale-subtitles-forward 1000)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+       (subed-scale-subtitles-backward 1000)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+       (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
+               '((+1000 nil nil)
+                 (-1000 nil nil)))))
+    (it "without providing end."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (subed-jump-to-subtitle-end)
-        (insert " ")
-        (setq-local subed-mpv-playback-position 61600)
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle)
-        (expect (subed-subtitle-text) :to-equal "")
-        (expect (subed-subtitle-msecs-start) :to-equal 61700)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-text) :to-equal "Foo.")
-        (expect (subed-subtitle-msecs-stop) :to-equal 61600)))
-    (it "splits at the beginning."
+       (insert mock-srt-data)
+       (subed-scale-subtitles 1000 (point-min) nil)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+       (subed-scale-subtitles -1000 (point-min) nil)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+    (it "without providing beginning."
       (with-temp-srt-buffer
-        (save-excursion (insert mock-srt-data))
-        (subed-jump-to-subtitle-text)
-        (setq-local subed-mpv-playback-position 61600)
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle)
-        (expect (subed-subtitle-text) :to-equal "Foo.")
-        (expect (subed-subtitle-msecs-start) :to-equal 61700)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-text) :to-equal "")
-        (expect (subed-subtitle-msecs-stop) :to-equal 61600))))
-  (describe "when a positive offset is specified"
-    (it "splits from the starting time."
+       (insert mock-srt-data)
+       (subed-scale-subtitles 1000 nil (point-max))
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+       (subed-scale-subtitles -1000 nil (point-max))
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+    (it "with active region on entire buffer."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (end-of-line)
-        (save-excursion (insert " Some text here."))
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle 300)
-        (expect (subed-subtitle-msecs-start) :to-equal 61400)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (expect (subed-subtitle-text) :to-equal "Some text here.")
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-msecs-stop) :to-equal 61300)
-        (expect (subed-subtitle-text) :to-equal "Foo.")))
-    (it "uses the offset instead of the playing position."
+       (insert mock-srt-data)
+       (let ((beg (point-min))
+             (end (point-max)))
+         (spy-on 'subed-scale-subtitles :and-call-through)
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (setq mark-active t)
+         (subed-scale-subtitles-forward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
+         (subed-scale-subtitles-backward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+         (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
+                 `((+1000 ,beg ,end)
+                   (-1000 ,beg ,end))))))
+    (it "with a zero msec extension/contraction."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (setq-local subed-mpv-playback-position 61600)
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle 300)
-        (expect (subed-subtitle-msecs-start) :to-equal 61400)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123))))
-  (describe "when a negative offset is specified"
-    (it "splits from the ending time."
+       (insert mock-srt-data)
+       (subed-scale-subtitles-forward 0)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
+       (subed-scale-subtitles-backward 0)
+       (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+       (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+       (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
+       (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
+       (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
+    (it "with active region on one subtitle."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (end-of-line)
-        (save-excursion (insert " Some text here."))
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle -300)
-        (expect (subed-subtitle-msecs-start) :to-equal 64923)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (expect (subed-subtitle-text) :to-equal "Some text here.")
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-msecs-stop) :to-equal 64823)
-        (expect (subed-subtitle-text) :to-equal "Foo.")))
-    (it "uses the offset instead of the playing position."
+       (insert mock-srt-data)
+       (let ((beg 77)                  ; point at ID of third subtitle
+             (end (point-max)))
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'user-error :and-call-through)
+         (setq mark-active t)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with fewer than 3 subtitles")))
+         (expect (buffer-string) :to-equal mock-srt-data))))
+    (it "with active region on two subtitles."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (setq-local subed-subtitle-spacing 100)
-        (setq-local subed-mpv-playback-position 61600)
-        (subed-split-subtitle -300)
-        (expect (subed-subtitle-msecs-start) :to-equal 64923)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-msecs-stop) :to-equal 64823))))
-  (describe "when nothing is specified"
-    (it "splits proportional to the location."
+       (insert mock-srt-data)
+       (let ((beg 39)                 ; point at ID of second subtitle
+             (end (point-max)))
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'user-error :and-call-through)
+         (setq mark-active t)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with only 2 subtitles")))
+         (expect (buffer-string) :to-equal mock-srt-data))))
+    (it "with active region contraction."
       (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (re-search-backward "Foo\\.")
-        (end-of-line)
-        (save-excursion (insert " Bar"))
-        (setq-local subed-subtitle-spacing 100)
-        (subed-split-subtitle)
-        (expect (subed-subtitle-msecs-start) :to-equal 63161)
-        (expect (subed-subtitle-msecs-stop) :to-equal 65123)
-        (expect (subed-subtitle-text) :to-equal "Bar")
-        (subed-backward-subtitle-time-start)
-        (expect (subed-subtitle-msecs-stop) :to-equal 63061)
-        (expect (subed-subtitle-text) :to-equal "Foo.")))))
-
-(describe "Scaling subtitles"
-  (it "without providing beginning and end."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (spy-on 'subed-scale-subtitles :and-call-through)
-      (subed-scale-subtitles-forward 1000)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
-      (subed-scale-subtitles-backward 1000)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
-      (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
-              '((+1000 nil nil)
-                (-1000 nil nil)))))
-  (it "without providing end."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-scale-subtitles 1000 (point-min) nil)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
-      (subed-scale-subtitles -1000 (point-min) nil)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
-  (it "without providing beginning."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-scale-subtitles 1000 nil (point-max))
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
-      (subed-scale-subtitles -1000 nil (point-max))
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
-  (it "with active region on entire buffer."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg (point-min))
-            (end (point-max)))
-        (spy-on 'subed-scale-subtitles :and-call-through)
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (setq mark-active t)
-        (subed-scale-subtitles-forward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 122734)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 130845)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 184450)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 196500)
-        (subed-scale-subtitles-backward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
-        (expect (spy-calls-all-args 'subed-scale-subtitles) :to-equal
-                `((+1000 ,beg ,end)
-                  (-1000 ,beg ,end))))))
-  (it "with a zero msec extension/contraction."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-scale-subtitles-forward 0)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)
-      (subed-scale-subtitles-backward 0)
-      (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-      (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-      (expect (subed-subtitle-msecs-start 2) :to-equal 122234)
-      (expect (subed-subtitle-msecs-stop 2) :to-equal 130345)
-      (expect (subed-subtitle-msecs-start 3) :to-equal 183450)
-      (expect (subed-subtitle-msecs-stop 3) :to-equal 195500)))
-  (it "with active region on one subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg 77) ; point at ID of third subtitle
-            (end (point-max)))
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'user-error :and-call-through)
-        (setq mark-active t)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with fewer than 3 subtitles")))
-        (expect (buffer-string) :to-equal mock-srt-data))))
-  (it "with active region on two subtitles."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg 39) ; point at ID of second subtitle
-            (end (point-max)))
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'user-error :and-call-through)
-        (setq mark-active t)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with only 2 subtitles")))
-        (expect (buffer-string) :to-equal mock-srt-data))))
-  (it "with active region contraction."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:43,233 --> 00:00:45,861\n"
-                      "a\n"
-                      "\n"
-                      "2\n"
-                      "00:00:51,675 --> 00:00:54,542\n"
-                      "b\n"
-                      "\n"
-                      "3\n"
-                      "00:01:00,717 --> 00:01:02,378\n"
-                      "c\n"
-                      "\n"
-                      "4\n"
-                      "00:01:02,452 --> 00:01:05,216\n"
-                      "d\n"))
-      (let ((beg (point-min))
-            (end 103)) ; point at TEXT of third subtitle
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (setq mark-active t)
-        (subed-scale-subtitles-backward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 51192)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 54059)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 59717)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 61378)
-        (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
-        (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
-  (it "with active region extension."
-    (with-temp-srt-buffer
-      (insert (concat "1\n"
-                      "00:00:43,233 --> 00:00:45,861\n"
-                      "a\n"
-                      "\n"
-                      "2\n"
-                      "00:00:51,192 --> 00:00:54,059\n"
-                      "b\n"
-                      "\n"
-                      "3\n"
-                      "00:00:59,717 --> 00:01:01,378\n"
-                      "c\n"
-                      "\n"
-                      "4\n"
-                      "00:01:02,452 --> 00:01:05,216\n"
-                      "d\n"))
-      (let ((beg (point-min))
-            (end 103)) ; point at TEXT of third subtitle
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (setq mark-active t)
-        (setq-local subed-subtitle-spacing 0)
-        (subed-scale-subtitles-forward 1000)
-        (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 51675)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 54542)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 60717)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 62378)
-        (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
-        (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
-  (it "when active region extension overlaps next subtitle."
-    (with-temp-srt-buffer
-      (let ((initial-contents
+       (insert (concat "1\n"
+                       "00:00:43,233 --> 00:00:45,861\n"
+                       "a\n"
+                       "\n"
+                       "2\n"
+                       "00:00:51,675 --> 00:00:54,542\n"
+                       "b\n"
+                       "\n"
+                       "3\n"
+                       "00:01:00,717 --> 00:01:02,378\n"
+                       "c\n"
+                       "\n"
+                       "4\n"
+                       "00:01:02,452 --> 00:01:05,216\n"
+                       "d\n"))
+       (let ((beg (point-min))
+             (end 103))              ; point at TEXT of third subtitle
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (setq mark-active t)
+         (subed-scale-subtitles-backward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 51192)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 54059)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 59717)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 61378)
+         (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
+         (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
+    (it "with active region extension."
+      (with-temp-srt-buffer
+       (insert (concat "1\n"
+                       "00:00:43,233 --> 00:00:45,861\n"
+                       "a\n"
+                       "\n"
+                       "2\n"
+                       "00:00:51,192 --> 00:00:54,059\n"
+                       "b\n"
+                       "\n"
+                       "3\n"
+                       "00:00:59,717 --> 00:01:01,378\n"
+                       "c\n"
+                       "\n"
+                       "4\n"
+                       "00:01:02,452 --> 00:01:05,216\n"
+                       "d\n"))
+       (let ((beg (point-min))
+             (end 103))              ; point at TEXT of third subtitle
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (setq mark-active t)
+         (setq-local subed-subtitle-spacing 0)
+         (subed-scale-subtitles-forward 1000)
+         (expect (subed-subtitle-msecs-start 1) :to-equal 43233)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 45861)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 51675)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 54542)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 60717)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 62378)
+         (expect (subed-subtitle-msecs-start 4) :to-equal 62452)
+         (expect (subed-subtitle-msecs-stop 4) :to-equal 65216))))
+    (it "when active region extension overlaps next subtitle."
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:00:43,233 --> 00:00:45,861\n"
                       "a\n"
@@ -2629,67 +2641,67 @@ This is another.
                       "4\n"
                       "00:01:02,452 --> 00:01:05,216\n"
                       "d\n"))
-            (beg 1)
-            (end 103)) ; point at TEXT of third subtitle
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'user-error :and-call-through)
-        (insert initial-contents)
-        (setq mark-active t)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when extension would overlap subsequent 
subtitles")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "when end subtitle start time moved to same time as begin subtitle start 
time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg (point-min))
-            (end (point-max))
-            (delta (- (subed-subtitle-msecs-start 3)
-                      (subed-subtitle-msecs-start 1))))
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'user-error :and-call-through)
-        (setq mark-active t)
-        (expect (subed-scale-subtitles-backward delta) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when contraction would eliminate region")))
-        (expect (buffer-string) :to-equal mock-srt-data))))
-  (it "when end subtitle start time moved to just before begin subtitle start 
time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg (point-min))
-            (end (point-max))
-            (delta (- (subed-subtitle-msecs-start 3)
-                      (subed-subtitle-msecs-start 1))))
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (spy-on 'user-error :and-call-through)
-        (setq mark-active t)
-        (expect (subed-scale-subtitles-backward (+ delta 1)) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when contraction would eliminate region")))
-        (expect (buffer-string) :to-equal mock-srt-data))))
-  (it "when end subtitle start time moved to just after begin subtitle start 
time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (let ((beg (point-min))
-            (end (point-max))
-            (delta (- (subed-subtitle-msecs-start 3)
-                      (subed-subtitle-msecs-start 1))))
-        (spy-on 'region-beginning :and-return-value beg)
-        (spy-on 'region-end :and-return-value end)
-        (setq mark-active t)
-        (subed-scale-subtitles-backward (- delta 1))
-        (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
-        (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
-        (expect (subed-subtitle-msecs-start 2) :to-equal 61001)
-        (expect (subed-subtitle-msecs-stop 2) :to-equal 69112)
-        (expect (subed-subtitle-msecs-start 3) :to-equal 61001)
-        (expect (subed-subtitle-msecs-stop 3) :to-equal 73051))))
-  (it "when begin start time same as end start time."
-    (with-temp-srt-buffer
-     (let ((initial-contents
+             (beg 1)
+             (end 103))              ; point at TEXT of third subtitle
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'user-error :and-call-through)
+         (insert initial-contents)
+         (setq mark-active t)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when extension would overlap subsequent 
subtitles")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "when end subtitle start time moved to same time as begin subtitle 
start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (let ((beg (point-min))
+             (end (point-max))
+             (delta (- (subed-subtitle-msecs-start 3)
+                       (subed-subtitle-msecs-start 1))))
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'user-error :and-call-through)
+         (setq mark-active t)
+         (expect (subed-scale-subtitles-backward delta) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when contraction would eliminate region")))
+         (expect (buffer-string) :to-equal mock-srt-data))))
+    (it "when end subtitle start time moved to just before begin subtitle 
start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (let ((beg (point-min))
+             (end (point-max))
+             (delta (- (subed-subtitle-msecs-start 3)
+                       (subed-subtitle-msecs-start 1))))
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (spy-on 'user-error :and-call-through)
+         (setq mark-active t)
+         (expect (subed-scale-subtitles-backward (+ delta 1)) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when contraction would eliminate region")))
+         (expect (buffer-string) :to-equal mock-srt-data))))
+    (it "when end subtitle start time moved to just after begin subtitle start 
time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (let ((beg (point-min))
+             (end (point-max))
+             (delta (- (subed-subtitle-msecs-start 3)
+                       (subed-subtitle-msecs-start 1))))
+         (spy-on 'region-beginning :and-return-value beg)
+         (spy-on 'region-end :and-return-value end)
+         (setq mark-active t)
+         (subed-scale-subtitles-backward (- delta 1))
+         (expect (subed-subtitle-msecs-start 1) :to-equal 61000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 65123)
+         (expect (subed-subtitle-msecs-start 2) :to-equal 61001)
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 69112)
+         (expect (subed-subtitle-msecs-start 3) :to-equal 61001)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 73051))))
+    (it "when begin start time same as end start time."
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:01:01,000 --> 00:01:05,123\n"
                       "Foo.\n"
@@ -2701,50 +2713,50 @@ This is another.
                       "3\n"
                       "00:01:01,000 --> 00:01:05,123\n"
                       "Baz.\n")))
-        (spy-on 'user-error :and-call-through)
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale subtitle range with 0 time interval")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale subtitle range with 0 time interval")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "when buffer is empty."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-      (expect (spy-calls-all-args 'user-error) :to-equal
-              '(("Can't scale with fewer than 3 subtitles")))
-      (expect (buffer-string) :to-equal "")
-      (spy-calls-reset 'user-error)
-      (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-      (expect (spy-calls-all-args 'user-error) :to-equal
-              '(("Can't scale with fewer than 3 subtitles")))
-      (expect (buffer-string) :to-equal "")))
-  (it "when buffer contains one subtitle."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (spy-on 'user-error :and-call-through)
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale subtitle range with 0 time interval")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale subtitle range with 0 time interval")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "when buffer is empty."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+       (expect (spy-calls-all-args 'user-error) :to-equal
+               '(("Can't scale with fewer than 3 subtitles")))
+       (expect (buffer-string) :to-equal "")
+       (spy-calls-reset 'user-error)
+       (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+       (expect (spy-calls-all-args 'user-error) :to-equal
+               '(("Can't scale with fewer than 3 subtitles")))
+       (expect (buffer-string) :to-equal "")))
+    (it "when buffer contains one subtitle."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:01:01,000 --> 00:01:05,123\n"
                       "Foo.\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with fewer than 3 subtitles")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with fewer than 3 subtitles")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "when buffer contains two subtitles."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with fewer than 3 subtitles")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with fewer than 3 subtitles")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "when buffer contains two subtitles."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:01:01,000 --> 00:01:05,123\n"
                       "Foo.\n"
@@ -2752,20 +2764,20 @@ This is another.
                       "2\n"
                       "00:02:02,234 --> 00:02:10,345\n"
                       "Bar.\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with only 2 subtitles")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale with only 2 subtitles")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "with subtitle in region containing start time after end start time."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with only 2 subtitles")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale with only 2 subtitles")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "with subtitle in region containing start time after end start time."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:01:01,000 --> 00:01:05,123\n"
                       "Foo.\n"
@@ -2777,20 +2789,20 @@ This is another.
                       "3\n"
                       "00:02:02,234 --> 00:02:10,345\n"
                       "Bar.\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when nonchronological subtitles exist")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when nonchronological subtitles exist")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "with first subtitle containing no timestamp."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when nonchronological subtitles exist")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when nonchronological subtitles exist")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "with first subtitle containing no timestamp."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "a\n"
                       "\n"
@@ -2801,20 +2813,20 @@ This is another.
                       "3\n"
                       "00:01:00,717 --> 00:01:02,378\n"
                       "c\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when first subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when first subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "with last subtitle containing no timestamp."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when first subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when first subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "with last subtitle containing no timestamp."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:00:43,233 --> 00:00:45,861\n"
                       "a\n"
@@ -2825,20 +2837,20 @@ This is another.
                       "\n"
                       "3\n"
                       "c\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when last subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when last subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "with subtitle in region containing no timestamp."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-      (let ((initial-contents
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when last subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when last subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "with subtitle in region containing no timestamp."
+      (spy-on 'user-error :and-call-through)
+      (with-temp-srt-buffer
+       (let ((initial-contents
               (concat "1\n"
                       "00:00:43,233 --> 00:00:45,861\n"
                       "a\n"
@@ -2849,251 +2861,307 @@ This is another.
                       "3\n"
                       "00:01:00,717 --> 00:01:02,378\n"
                       "c\n")))
-        (insert initial-contents)
-        (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents)
-        (spy-calls-reset 'user-error)
-        (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
-        (expect (spy-calls-all-args 'user-error) :to-equal
-                '(("Can't scale when subtitle timestamp missing")))
-        (expect (buffer-string) :to-equal initial-contents))))
-  (it "with out-of-order range."
-    (spy-on 'user-error :and-call-through)
-    (with-temp-srt-buffer
-     (expect (subed-scale-subtitles 1000 5 4) :to-throw 'error)
-     (expect (spy-calls-all-args 'user-error) :to-equal
-             '(("Can't scale with improper range"))))))
-
-(describe "Trimming subtitles"
-  (describe "when spacing is 0"
-    (it "detects overlaps"
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:05,000\nA\n\n"
-               "2\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 0))
-         (expect (subed--identify-overlaps)
-                 :to-equal '(1)))))
-    (it "ignores non-overlapping subtitles"
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,000\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 0))
-         (expect (subed--identify-overlaps)
-                 :to-equal nil)))))
-  (describe "when spacing is 1"
-    (it "detects overlaps"
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:04,000\nA\n\n"
-               "2\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 1))
-         (expect (subed--identify-overlaps)
-                 :to-equal '(1)))))
-    (it "ignores non-overlapping subtitles"
+         (insert initial-contents)
+         (expect (subed-scale-subtitles-forward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents)
+         (spy-calls-reset 'user-error)
+         (expect (subed-scale-subtitles-backward 1000) :to-throw 'error)
+         (expect (spy-calls-all-args 'user-error) :to-equal
+                 '(("Can't scale when subtitle timestamp missing")))
+         (expect (buffer-string) :to-equal initial-contents))))
+    (it "with out-of-order range."
+      (spy-on 'user-error :and-call-through)
       (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,999\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,000\nA\n\n")
-       (let ((subed-subtitle-spacing 1))
-         (expect (subed--identify-overlaps)
-                 :to-equal nil)))))
-  (describe "when spacing is greater"
-    (it "detects overlaps because of spacing"
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,999\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:05,000\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (expect (subed--identify-overlaps)
-                 :to-equal '(1 2)))))
-    (it "ignores non-overlapping subtitles."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:03,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (expect (subed--identify-overlaps)
-                 :to-equal nil)))))
-  (describe "overlap end time"
-    (it "sets it to the next timestamp minus spacing."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 2)
-         (subed-trim-overlap-stop)
-         (expect (subed-subtitle-msecs-stop) :to-equal 3900))))
-    (it "sets it to the next timestamp minus the argument."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 2)
-         (subed-trim-overlap-stop 500)
-         (expect (subed-subtitle-msecs-stop) :to-equal 3500))))
-    (it "ignores non-overlapping subtitles."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 1)
-         (subed-trim-overlap-stop)
-         (expect (subed-subtitle-msecs-stop) :to-equal 2000))))
-    (it "handles the last subtitle gracefully."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 3)
+       (expect (subed-scale-subtitles 1000 5 4) :to-throw 'error)
+       (expect (spy-calls-all-args 'user-error) :to-equal
+               '(("Can't scale with improper range"))))))
+
+  (describe "Trimming subtitles"
+    (describe "when spacing is 0"
+      (it "detects overlaps"
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:05,000\nA\n\n"
+                 "2\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 0))
+           (expect (subed--identify-overlaps)
+                   :to-equal '(1)))))
+      (it "ignores non-overlapping subtitles"
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,000\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 0))
+           (expect (subed--identify-overlaps)
+                   :to-equal nil)))))
+    (describe "when spacing is 1"
+      (it "detects overlaps"
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:04,000\nA\n\n"
+                 "2\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 1))
+           (expect (subed--identify-overlaps)
+                   :to-equal '(1)))))
+      (it "ignores non-overlapping subtitles"
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,999\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,000\nA\n\n")
+         (let ((subed-subtitle-spacing 1))
+           (expect (subed--identify-overlaps)
+                   :to-equal nil)))))
+    (describe "when spacing is greater"
+      (it "detects overlaps because of spacing"
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,999\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:05,000\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (expect (subed--identify-overlaps)
+                   :to-equal '(1 2)))))
+      (it "ignores non-overlapping subtitles."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:03,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (expect (subed--identify-overlaps)
+                   :to-equal nil)))))
+    (describe "overlap end time"
+      (it "sets it to the next timestamp minus spacing."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 2)
+           (subed-trim-overlap-stop)
+           (expect (subed-subtitle-msecs-stop) :to-equal 3900))))
+      (it "sets it to the next timestamp minus the argument."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 2)
+           (subed-trim-overlap-stop 500)
+           (expect (subed-subtitle-msecs-stop) :to-equal 3500))))
+      (it "ignores non-overlapping subtitles."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 1)
+           (subed-trim-overlap-stop)
+           (expect (subed-subtitle-msecs-stop) :to-equal 2000))))
+      (it "handles the last subtitle gracefully."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 3)
+           (subed-trim-overlap-stop 500)
+           (expect (subed-subtitle-msecs-stop) :to-equal 6000))))
+      (it "handles empty buffers gracefully."
+        (with-temp-srt-buffer
          (subed-trim-overlap-stop 500)
-         (expect (subed-subtitle-msecs-stop) :to-equal 6000))))
-    (it "handles empty buffers gracefully."
-      (with-temp-srt-buffer
-       (subed-trim-overlap-stop 500)
-       (expect (subed-subtitle-msecs-stop) :to-equal nil)))
-    (it "adjusts the stop time if the new stop would be before the start time."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,500 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 1)
-         (expect (subed-trim-overlap-stop) :to-equal -500)
-         (expect (subed-subtitle-msecs-stop 1) :to-equal 1500)
-         (expect (subed-subtitle-msecs-start 1) :to-equal 1500)))))
-  (describe "overlap start time"
-    (it "sets next start to the current timestamp plus spacing."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 2)
-         (subed-trim-overlap-next-start)
-         (subed-forward-subtitle-time-start)
-         (expect (subed-subtitle-msecs-start) :to-equal 4600))))
-    (it "sets next start to the current timestamp plus the argument."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 2)
-         (subed-trim-overlap-next-start 500)
-         (subed-forward-subtitle-time-start)
-         (expect (subed-subtitle-msecs-start) :to-equal 5000))))
-    (it "handles the last subtitle gracefully."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 3)
+         (expect (subed-subtitle-msecs-stop) :to-equal nil)))
+      (it "adjusts the stop time if the new stop would be before the start 
time."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,500 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 1)
+           (expect (subed-trim-overlap-stop) :to-equal -500)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 1500)
+           (expect (subed-subtitle-msecs-start 1) :to-equal 1500)))))
+    (describe "overlap start time"
+      (it "sets next start to the current timestamp plus spacing."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 2)
+           (subed-trim-overlap-next-start)
+           (subed-forward-subtitle-time-start)
+           (expect (subed-subtitle-msecs-start) :to-equal 4600))))
+      (it "sets next start to the current timestamp plus the argument."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 2)
+           (subed-trim-overlap-next-start 500)
+           (subed-forward-subtitle-time-start)
+           (expect (subed-subtitle-msecs-start) :to-equal 5000))))
+      (it "handles the last subtitle gracefully."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 3)
+           (subed-trim-overlap-next-start 500)
+           (expect (subed-subtitle-msecs-start) :to-equal 4000))))
+      (it "adjusts the timestamp if the new start is past the stop time."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:01,500 --> 00:00:02,000\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-jump-to-subtitle-id 1)
+           (expect (subed-trim-overlap-next-start 500) :to-equal 500)
+           (expect (subed-subtitle-msecs-start 2) :to-equal 2000))))
+      (it "handles empty buffers gracefully."
+        (with-temp-srt-buffer
          (subed-trim-overlap-next-start 500)
-         (expect (subed-subtitle-msecs-start) :to-equal 4000))))
-    (it "adjusts the timestamp if the new start is past the stop time."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:01,500 --> 00:00:02,000\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-jump-to-subtitle-id 1)
-         (expect (subed-trim-overlap-next-start 500) :to-equal 500)
-         (expect (subed-subtitle-msecs-start 2) :to-equal 2000))))
-    (it "handles empty buffers gracefully."
-      (with-temp-srt-buffer
-       (subed-trim-overlap-next-start 500)
-       (expect (subed-subtitle-msecs-stop) :to-equal nil))))
-  (describe "trimming overlaps"
-    (it "adjusts stop times by default."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-               "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-trim-overlaps))
-       (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-       (expect (subed-subtitle-msecs-stop 2) :to-equal 3900)
-       (expect (subed-subtitle-msecs-stop 3) :to-equal 4900)))
-    (it "adjusts start times if specified."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-               "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100)
-             (subed-trim-overlap-use-start t))
-         (subed-trim-overlaps)
+         (expect (subed-subtitle-msecs-stop) :to-equal nil))))
+    (describe "trimming overlaps"
+      (it "adjusts stop times by default."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
+                 "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (subed-trim-overlaps))
          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-         (expect (subed-subtitle-msecs-stop 2) :to-equal 4500)
-         (expect (subed-subtitle-msecs-start 3) :to-equal 4600)
-         (expect (subed-subtitle-msecs-start 4) :to-equal 6000))))
-    (it "can specify the number of milliseconds."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-               "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (subed-trim-overlaps 200))
-       (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-       (expect (subed-subtitle-msecs-stop 2) :to-equal 3800)
-       (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))
-    (it "handles empty buffers gracefully."
-      (with-temp-srt-buffer
-       (expect (subed-trim-overlaps) :not :to-throw)))
-    (it "handles single subtitles gracefully."
-      (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n")
-       (let ((subed-subtitle-spacing 100))
-         (expect (subed-trim-overlaps) :not :to-throw))
-       (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
-       (expect (subed-subtitle-msecs-stop 1) :to-equal 2000))))
-  (describe "when configured to trim on save,"
-    (it "trims overlaps after sorting."
-      (with-temp-srt-buffer
-       (let ((subed-trim-overlap-on-save t)
-             (subed-subtitle-spacing 200))
+         (expect (subed-subtitle-msecs-stop 2) :to-equal 3900)
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 4900)))
+      (it "adjusts start times if specified."
+        (with-temp-srt-buffer
          (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-                 "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-                 "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
+                 "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100)
+               (subed-trim-overlap-use-start t))
+           (subed-trim-overlaps)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 4500)
+           (expect (subed-subtitle-msecs-start 3) :to-equal 4600)
+           (expect (subed-subtitle-msecs-start 4) :to-equal 6000))))
+      (it "can specify the number of milliseconds."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "3\n00:00:04,000 --> 00:00:06,000\nA\n\n"
                  "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-         (subed-prepare-to-save)
+         (let ((subed-subtitle-spacing 100))
+           (subed-trim-overlaps 200))
          (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
          (expect (subed-subtitle-msecs-stop 2) :to-equal 3800)
-         (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))))
-  (describe "when configured to check on save,"
-    (it "reports overlaps after sorting."
+         (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))
+      (it "handles empty buffers gracefully."
+        (with-temp-srt-buffer
+         (expect (subed-trim-overlaps) :not :to-throw)))
+      (it "handles single subtitles gracefully."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n")
+         (let ((subed-subtitle-spacing 100))
+           (expect (subed-trim-overlaps) :not :to-throw))
+         (expect (subed-subtitle-msecs-start 1) :to-equal 1000)
+         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000))))
+    (describe "when configured to trim on save,"
+      (it "trims overlaps after sorting."
+        (with-temp-srt-buffer
+         (let ((subed-trim-overlap-on-save t)
+               (subed-subtitle-spacing 200))
+           (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                   "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
+                   "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                   "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
+           (subed-prepare-to-save)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3800)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))))
+    (describe "when configured to check on save,"
+      (it "reports overlaps after sorting."
+        (with-temp-srt-buffer
+         (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                 "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
+                 "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                 "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
+         (let ((subed-trim-overlap-check-on-save t)
+               (subed-subtitle-spacing 200))
+           (spy-on 'yes-or-no-p :and-return-value t)
+           (subed-prepare-to-save)
+           (expect 'yes-or-no-p :to-have-been-called)
+           (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
+           (expect (subed-subtitle-msecs-stop 2) :to-equal 3800)
+           (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))))
+    (describe "when configured to check on load,"
+      (it "reports overlaps."
+        (with-temp-buffer
+          (setq buffer-file-name "test.srt")
+          (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
+                  "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
+                  "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
+                  "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
+          (let ((subed-trim-overlap-check-on-load t)
+                (subed-subtitle-spacing 200))
+            (spy-on 'subed-trim-overlap-check :and-return-value nil)
+            (subed-srt-mode)
+            (expect subed--subtitle-format :to-equal "srt")
+            (expect 'subed-trim-overlap-check :to-have-been-called))))))
+  (describe "Getting a list of subtitles"
+    (it "returns nil in an empty buffer."
       (with-temp-srt-buffer
-       (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-               "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-               "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-               "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-       (let ((subed-trim-overlap-check-on-save t)
-             (subed-subtitle-spacing 200))
-         (spy-on 'yes-or-no-p :and-return-value t)
-         (subed-prepare-to-save)
-         (expect 'yes-or-no-p :to-have-been-called)
-         (expect (subed-subtitle-msecs-stop 1) :to-equal 2000)
-         (expect (subed-subtitle-msecs-stop 2) :to-equal 3800)
-         (expect (subed-subtitle-msecs-stop 3) :to-equal 4800)))))
-  (describe "when configured to check on load,"
-    (it "reports overlaps."
-      (with-temp-buffer
-        (setq buffer-file-name "test.srt")
-        (insert "1\n00:00:01,000 --> 00:00:02,000\nA\n\n"
-                "2\n00:00:04,000 --> 00:00:06,000\nA\n\n"
-                "3\n00:00:03,000 --> 00:00:04,500\nA\n\n"
-                "4\n00:00:05,000 --> 00:00:06,000\nA\n\n")
-        (let ((subed-trim-overlap-check-on-load t)
-              (subed-subtitle-spacing 200))
-          (spy-on 'subed-trim-overlap-check :and-return-value nil)
-          (subed-mode)
-          (expect subed--subtitle-format :to-equal "srt")
-          (expect 'subed-trim-overlap-check :to-have-been-called))))))
+       (expect (subed-subtitle-list) :to-equal nil)))
+    (it "returns the list."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (expect (subed-subtitle-list) :to-equal
+               '((1 61000 65123 "Foo.")
+                 (2 122234 130345 "Bar.")
+                 (3 183450 195500 "Baz.")))))
+    (it "returns a subset when bounds are specified."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 3)
+       (backward-char 1)
+       (expect (subed-subtitle-list (point-min) (point))
+               :to-equal
+               '((1 61000 65123 "Foo.")
+                 (2 122234 130345 "Bar.")))))
+    )
+  )
+
+(describe "An old generic function"
+  :var ((function-list
+         (list "subtitle-id" "subtitle-id-max" "subtitle-id-at-msecs"
+               "subtitle-msecs-start" "subtitle-msecs-stop"
+               "subtitle-text" "subtitle-relative-point"
+               "msecs-to-timestamp" "timestamp-to-msecs"
+               "jump-to-subtitle-id" "jump-to-subtitle-id-at-msecs"
+               "jump-to-subtitle-time-start" "jump-to-subtitle-time-stop"
+               "jump-to-subtitle-text" "jump-to-subtitle-text-at-msecs"
+               "jump-to-subtitle-end"
+               "forward-subtitle-id" "backward-subtitle-id"
+               "forward-subtitle-text" "backward-subtitle-text"
+               "forward-subtitle-end" "backward-subtitle-end"
+               "forward-subtitle-time-start" "backward-subtitle-time-start"
+               "forward-subtitle-time-stop" "backward-subtitle-time-stop"
+               "set-subtitle-time-start" "set-subtitle-time-stop"
+               "prepend-subtitle" "append-subtitle" "kill-subtitle" 
"merge-with-next"
+               "regenerate-ids" "regenerate-ids-soon"
+               "sanitize" "validate" "sort" "make-subtitle")))
+  (it "is declared as a common function"
+    (mapc (lambda (f)
+            (let ((function-name (format "subed-%s" f)))
+              (unless (functionp (intern function-name))
+                (buttercup-fail "%s is not a function" function-name))))
+          function-list))
+  (it "has format-specific internal functions"
+    (mapc (lambda (f)
+            (mapc (lambda (sub-format)
+                    (let ((function-name (format "subed-%s--%s" sub-format f)))
+                      (unless (functionp (intern function-name))
+                        (buttercup-fail "%s is not a function" 
function-name))))
+                  '("srt" "vtt" "ass")))
+          function-list)))
diff --git a/tests/test-subed-mpv.el b/tests/test-subed-mpv.el
index 7613a31959..3c292a28b8 100644
--- a/tests/test-subed-mpv.el
+++ b/tests/test-subed-mpv.el
@@ -1,7 +1,7 @@
 ;; -*- eval: (buttercup-minor-mode) -*-
 
-(add-to-list 'load-path "./subed")
-(require 'subed)
+(load-file "./tests/undercover-init.el")
+(require 'subed-mpv)
 
 (describe "Starting mpv"
   (it "passes arguments to make-process."
diff --git a/tests/test-subed-srt.el b/tests/test-subed-srt.el
index 63a9158ddc..957bb4b13a 100644
--- a/tests/test-subed-srt.el
+++ b/tests/test-subed-srt.el
@@ -1,8 +1,7 @@
 ;; -*- eval: (buttercup-minor-mode) -*-
 
-(add-to-list 'load-path "./subed")
-(require 'subed)
-
+(load-file "./tests/undercover-init.el")
+(require 'subed-srt)
 (defvar mock-srt-data
   "1
 00:01:01,000 --> 00:01:05,123
@@ -18,1491 +17,1510 @@ Baz.
 ")
 
 (defmacro with-temp-srt-buffer (&rest body)
-  "Call `subed-srt--init' in temporary buffer before running BODY."
+  "Initialize buffer to `subed-srt-mode' and run BODY."
   `(with-temp-buffer
-    (subed-srt--init)
+    (subed-srt-mode)
     (progn ,@body)))
 
-(describe "Getting"
-  (describe "the subtitle ID"
-    (it "returns the subtitle ID if it can be found."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 2)
-        (expect (subed-srt--subtitle-id) :to-equal 2)))
-    (it "returns nil if no subtitle ID can be found."
-      (with-temp-srt-buffer
-        (expect (subed-srt--subtitle-id) :to-equal nil)))
-    )
-  (describe "the subtitle ID at playback time"
-    (it "returns subtitle ID if time is equal to start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (subed-srt--subtitle-msecs-start target-id)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-srt--jump-to-subtitle-id outset-id)
-                              (expect (subed-srt--subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns subtitle ID if time is equal to stop time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (subed-srt--subtitle-msecs-stop target-id)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-srt--jump-to-subtitle-id outset-id)
-                              (expect (subed-srt--subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns subtitle ID if time is between start and stop time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 3 do
-                 (let ((msecs (+ 1 (subed-srt--subtitle-msecs-start 
target-id))))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-srt--jump-to-subtitle-id outset-id)
-                              (expect (subed-srt--subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
-    (it "returns nil if time is before the first subtitle's start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (let ((msecs (- (save-excursion
-                          (goto-char (point-min))
-                          (subed-srt--subtitle-msecs-start)) 1)))
-          (cl-loop for outset-id from 1 to 3 do
-                   (progn
-                     (subed-srt--jump-to-subtitle-id outset-id)
-                     (expect (subed-srt--subtitle-id-at-msecs msecs) :to-equal 
nil))))))
-    (it "returns nil if time is after the last subtitle's start time."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (let ((msecs (+ (save-excursion
-                          (goto-char (point-max))
-                          (subed-srt--subtitle-msecs-stop)) 1)))
-          (cl-loop for outset-id from 1 to 3 do
-                   (progn
-                     (subed-srt--jump-to-subtitle-id outset-id)
-                     (expect (subed-srt--subtitle-id-at-msecs msecs) :to-equal 
nil))))))
-    (it "returns nil if time is between subtitles."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (cl-loop for target-id from 1 to 2 do
-                 (let ((msecs (+ (subed-srt--subtitle-msecs-stop target-id) 
1)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-srt--jump-to-subtitle-id outset-id)
-                              (expect (subed-srt--subtitle-id-at-msecs msecs) 
:to-equal nil))))
-                 (let ((msecs (- (subed-srt--subtitle-msecs-start (+ target-id 
1)) 1)))
-                   (cl-loop for outset-id from 1 to 3 do
-                            (progn
-                              (subed-srt--jump-to-subtitle-id outset-id)
-                              (expect (subed-srt--subtitle-id-at-msecs msecs) 
:to-equal nil)))))))
-    (it "doesn't fail if start time is invalid."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 2)
-        (let ((msecs (- (subed-srt--subtitle-msecs-start) 1)))
-          (subed-srt--jump-to-subtitle-time-start)
-          (forward-char 8) (delete-char 1)
-          (expect (subed-srt--subtitle-id-at-msecs msecs) :to-equal 2))))
-    )
-  (describe "the subtitle start/stop time"
-    (it "returns the time in milliseconds."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 2)
-        (expect (subed-srt--subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 
2 1000) 234))
-        (expect (subed-srt--subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 
10 1000) 345))))
-    (it "handles lack of digits in milliseconds gracefully."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                                (thing-at-point 'line)) :to-equal "00:03:03,45 
--> 00:03:15,5\n")
-        (expect (subed-srt--subtitle-msecs-start) :to-equal (+ (* 3 60 1000) 
(*  3 1000) 450))
-        (expect (subed-srt--subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) 
(* 15 1000) 500))))
-    (it "returns nil if time can't be found."
-      (with-temp-srt-buffer
-        (expect (subed-srt--subtitle-msecs-start) :to-be nil)
-        (expect (subed-srt--subtitle-msecs-stop) :to-be nil)))
-    )
-  (describe "the subtitle text"
-    (describe "when text is empty"
-      (it "and at the beginning with a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 1)
-          (kill-line)
-          (expect (subed-srt--subtitle-text) :to-equal "")))
-      (it "and at the beginning without a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 1)
-          (kill-whole-line)
-          (expect (subed-srt--subtitle-text) :to-equal "")))
-      (it "and in the middle."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 2)
-          (kill-line)
-          (expect (subed-srt--subtitle-text) :to-equal "")))
-      (it "and at the end with a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 3)
-          (kill-line)
-          (expect (subed-srt--subtitle-text) :to-equal "")))
-      (it "and at the end without a trailing newline."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 3)
-          (kill-whole-line)
-          (expect (subed-srt--subtitle-text) :to-equal "")))
-      )
-    (describe "when text is not empty"
-      (it "and has no linebreaks."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 2)
-          (expect (subed-srt--subtitle-text) :to-equal "Bar.")))
-      (it "and has linebreaks."
-        (with-temp-srt-buffer
-          (insert mock-srt-data)
-          (subed-srt--jump-to-subtitle-text 2)
-          (insert "Bar.\n")
-          (expect (subed-srt--subtitle-text) :to-equal "Bar.\nBar.")))
+(describe "SRT"
+  (describe "Getting"
+    (describe "the subtitle ID"
+      (it "returns the subtitle ID if it can be found."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (subed-subtitle-id) :to-equal 2)))
+      (it "returns nil if no subtitle ID can be found."
+        (with-temp-srt-buffer
+         (expect (subed-subtitle-id) :to-equal nil)))
       )
-    )
-  (describe "the point within the subtitle"
-    (it "returns the relative point if we can find an ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 2)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 0)
-        (forward-line)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 2)
-        (forward-line)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 32)
-        (forward-char)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 33)
-        (forward-line)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 37)
-        (forward-line)
-        (expect (subed-srt--subtitle-relative-point) :to-equal 0)))
-    (it "returns nil if we can't find an ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (insert "foo")
-        (expect (subed-srt--subtitle-relative-point) :to-equal nil)))
-    )
-  )
-
-(describe "Jumping"
-  (describe "to current subtitle ID"
-    (it "returns ID's point when point is already on the ID."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    (it "returns ID's point when point is on the duration."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (search-backward ",234")
-        (expect (thing-at-point 'word) :to-equal "02")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns ID's point when point is on the text."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (search-backward "Baz.")
-        (expect (thing-at-point 'word) :to-equal "Baz")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns ID's point when point is between subtitles."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Bar.\n")
-        (expect (thing-at-point 'line) :to-equal "\n")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns nil if buffer is empty."
-      (with-temp-srt-buffer
-        (expect (buffer-string) :to-equal "")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal nil)))
-    (it "returns ID's point when buffer starts with blank lines."
-      (with-temp-srt-buffer
-        (insert (concat " \n \t \n" mock-srt-data))
-        (search-backward "Foo.")
-        (expect (thing-at-point 'line) :to-equal "Foo.\n")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 7)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    (it "returns ID's point when subtitles are separated with blank lines."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Foo.\n")
-        (insert " \n \t \n")
-        (expect (subed-srt--jump-to-subtitle-id) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to specific subtitle ID"
-    (it "returns ID's point if wanted ID exists."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-max))
-        (expect (subed-srt--jump-to-subtitle-id 2) :to-equal 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (expect (subed-srt--jump-to-subtitle-id 1) :to-equal 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--jump-to-subtitle-id 3) :to-equal 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns nil and does not move if wanted ID does not exists."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (search-forward "Foo")
-        (let ((stored-point (point)))
-          (expect (subed-srt--jump-to-subtitle-id 4) :to-equal nil)
-          (expect stored-point :to-equal (point)))))
-    )
-  (describe "to subtitle ID at specific time"
-    (it "returns ID's point if point changed."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-max))
-        (spy-on 'subed-srt--subtitle-id-at-msecs :and-return-value (point-min))
-        (expect (subed-srt--jump-to-subtitle-id-at-msecs 123450) :to-equal 
(point-min))
-        (expect (point) :to-equal (point-min))
-        (expect 'subed-srt--subtitle-id-at-msecs :to-have-been-called-with 
123450)
-        (expect 'subed-srt--subtitle-id-at-msecs :to-have-been-called-times 
1)))
-    (it "returns nil if point didn't change."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char 75)
-        (spy-on 'subed-srt--subtitle-id-at-msecs :and-return-value 75)
-        (expect (subed-srt--jump-to-subtitle-id-at-msecs 123450) :to-equal nil)
-        (expect (point) :to-equal 75)
-        (expect 'subed-srt--subtitle-id-at-msecs :to-have-been-called-with 
123450)
-        (expect 'subed-srt--subtitle-id-at-msecs :to-have-been-called-times 
1)))
-    )
-  (describe "to subtitle start time"
-    (it "returns start time's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-srt--jump-to-subtitle-time-start) :to-equal 3)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:01:01,000")
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-time-start) :to-equal 41)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:02:02,234")
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-time-start) :to-equal 79)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:03:03,45")))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-srt--jump-to-subtitle-time-start) :to-equal nil)))
-    )
-  (describe "to subtitle stop time"
-    (it "returns stop time's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-srt--jump-to-subtitle-time-stop) :to-equal 20)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:01:05,123")
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-time-stop) :to-equal 58)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:02:10,345")
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-time-stop) :to-equal 95)
-        (expect (looking-at subed-srt--regexp-timestamp) :to-be t)
-        (expect (match-string 0) :to-equal "00:03:15,5")))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-srt--jump-to-subtitle-time-stop) :to-equal nil)))
-    )
-  (describe "to subtitle text"
-    (it "returns subtitle text's point if movement was successful."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-srt--jump-to-subtitle-text) :to-equal 33)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Foo.")))
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-text) :to-equal 71)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Bar.")))
-        (re-search-forward "\n\n")
-        (expect (subed-srt--jump-to-subtitle-text) :to-equal 106)
-        (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Baz.")))))
-    (it "returns nil if movement failed."
-      (with-temp-srt-buffer
-        (expect (subed-srt--jump-to-subtitle-time-stop) :to-equal nil)))
-    )
-  (describe "to end of subtitle text"
-    (it "returns point if subtitle end can be found."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 37)
-        (expect (looking-back "^Foo.$") :to-be t)
-        (forward-char 2)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 75)
-        (expect (looking-back "^Bar.$") :to-be t)
-        (forward-char 2)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 110)
-        (expect (looking-back "^Baz.$") :to-be t)
-        (goto-char (point-max))
-        (backward-char 2)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 110)
-        (expect (looking-back "^Baz.$") :to-be t)))
-    (it "returns nil if subtitle end cannot be found."
-      (with-temp-srt-buffer
-        (expect (subed-srt--jump-to-subtitle-end) :to-be nil)))
-    (it "returns nil if point did not move."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (kill-line)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be nil)))
-    (it "works if text is empty with trailing newline."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (kill-line)
-        (backward-char)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 33)
-        (expect (looking-at "^$") :to-be t)
-        (subed-srt--jump-to-subtitle-text 2)
-        (kill-line)
-        (backward-char)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 67)
-        (expect (looking-at "^$") :to-be t)
-        (subed-srt--jump-to-subtitle-text 3)
-        (kill-line)
-        (backward-char)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 98)
-        (expect (looking-at "^$") :to-be t)))
-    (it "works if text is empty without trailing newline."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (kill-whole-line)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (goto-char (point-min))
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 33)
-        (expect (looking-at "^$") :to-be t)
-        (subed-srt--jump-to-subtitle-text 2)
-        (kill-whole-line)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (backward-char)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 66)
-        (expect (looking-at "^$") :to-be t)
-        (subed-srt--jump-to-subtitle-text 3)
-        (kill-whole-line)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be nil)
-        (expect (looking-at "^$") :to-be t)
-        (backward-char)
-        (expect (subed-srt--jump-to-subtitle-end) :to-be 96)
-        (expect (looking-at "^$") :to-be t)))
-    )
-  (describe "to next subtitle ID"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--forward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (subed-srt--jump-to-subtitle-time-start 2)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-srt--forward-subtitle-id) :to-be 77)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (expect (thing-at-point 'word) :to-equal nil)
-        (expect (subed-srt--forward-subtitle-id) :to-be nil))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-srt--forward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (subed-srt--jump-to-subtitle-time-stop 2)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-srt--forward-subtitle-id) :to-be 77)
-        (expect (thing-at-point 'word) :to-equal "3"))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 3)
-        (expect (thing-at-point 'word) :to-equal "Baz")
-        (expect (subed-srt--forward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "Baz"))
-      (with-temp-srt-buffer
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-srt--jump-to-subtitle-time-stop 3)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-srt--forward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    )
-  (describe "to previous subtitle ID"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 2)
-        (expect (thing-at-point 'word) :to-equal "Bar")
-        (expect (subed-srt--backward-subtitle-id) :to-be 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (subed-srt--jump-to-subtitle-time-stop 3)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-srt--backward-subtitle-id) :to-be 39)
-        (expect (thing-at-point 'word) :to-equal "2")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (expect (subed-srt--backward-subtitle-id) :to-be nil))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1"))
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-srt--backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "Foo"))
-      (with-temp-srt-buffer
-        (insert (concat "\n\n\n" mock-srt-data))
-        (subed-srt--jump-to-subtitle-time-stop 1)
-        (expect (thing-at-point 'word) :to-equal "00")
-        (expect (subed-srt--backward-subtitle-id) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    )
-  (describe "to next subtitle text"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--forward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (goto-char (point-max))
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--forward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle text"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--backward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--backward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle end"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 2)
-        (expect (thing-at-point 'word) :to-equal "Bar")
-        (expect (subed-srt--forward-subtitle-end) :to-be 110)
-        (expect (thing-at-point 'word) :to-equal nil)))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert (concat mock-srt-data "\n\n"))
-        (subed-srt--jump-to-subtitle-text 3)
-        (end-of-line)
-        (expect (thing-at-point 'word) :to-equal nil)
-        (expect (subed-srt--forward-subtitle-end) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal nil)))
-    )
-  (describe "to previous subtitle end"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--backward-subtitle-text) :to-be 71)
-        (expect (thing-at-point 'word) :to-equal "Bar")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--backward-subtitle-text) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle start time"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-srt--forward-subtitle-time-start) :to-be 41)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--forward-subtitle-time-start) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle start time"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 2)
-        (expect (thing-at-point 'word) :to-equal "2")
-        (expect (subed-srt--backward-subtitle-time-start) :to-be 3)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--backward-subtitle-time-start) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  (describe "to next subtitle stop time"
-    (it "returns point when there is a next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-text 1)
-        (expect (thing-at-point 'word) :to-equal "Foo")
-        (expect (subed-srt--forward-subtitle-time-stop) :to-be 58)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no next subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--forward-subtitle-time-stop) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "3")))
-    )
-  (describe "to previous subtitle stop time"
-    (it "returns point when there is a previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 3)
-        (expect (thing-at-point 'word) :to-equal "3")
-        (expect (subed-srt--backward-subtitle-time-stop) :to-be 58)
-        (expect (thing-at-point 'word) :to-equal "00")))
-    (it "returns nil and doesn't move when there is no previous subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-srt--jump-to-subtitle-id 1)
-        (expect (thing-at-point 'word) :to-equal "1")
-        (expect (subed-srt--backward-subtitle-time-stop) :to-be nil)
-        (expect (thing-at-point 'word) :to-equal "1")))
-    )
-  )
-
-(describe "Setting start/stop time"
-  (it "of current subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-end 2)
-      (subed-srt--set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 
3 1000) 400))
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "01:02:03,400 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-srt--set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 
7 1000) 800))
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "01:02:03,400 --> 
05:06:07,800\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "of specific subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-time-stop 3)
-      (subed-srt--set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) (* 
6 1000) 800) 1)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "02:04:06,800 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-srt--jump-to-subtitle-text 1)
-      (subed-srt--set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 
7 1000) 900) 3)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "02:04:06,800 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 
03:05:07,900\n"
-                                                "Baz.\n"))))
-  (it "when milliseconds lack digits."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-jump-to-subtitle-id 3)
-      (subed-srt--set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 
3 1000) 4) 3)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 00:03:15,5\n")
-      (subed-srt--set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 
4 1000) 60) 3)
-      (expect (save-excursion (subed-jump-to-subtitle-time-start)
-                              (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 02:03:04,060\n")))
-  )
-
-(describe "Inserting a subtitle"
-  (describe "in an empty buffer"
-    (describe "before"
-      (it "passing nothing."
-        (with-temp-srt-buffer
-          (expect (subed-srt--prepend-subtitle) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "0\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID."
-        (with-temp-srt-buffer
-          (expect (subed-srt--prepend-subtitle 2) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "2\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID and start time."
-        (with-temp-srt-buffer
-          (expect (subed-srt--prepend-subtitle 3 60000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "3\n"
-                                                    "00:01:00,000 --> 
00:01:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time and stop time."
-        (with-temp-srt-buffer
-          (expect (subed-srt--prepend-subtitle 4 60000 65000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "4\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time, stop time and text."
-        (with-temp-srt-buffer
-          (expect (subed-srt--prepend-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
-          (expect (buffer-string) :to-equal (concat "5\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n"
-                                                    "Foo, bar\nbaz.\n"))
-          (expect (point) :to-equal 33)))
+    (describe "the subtitle ID at playback time"
+      (it "returns subtitle ID if time is equal to start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (subed-subtitle-msecs-start target-id)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns subtitle ID if time is equal to stop time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (subed-subtitle-msecs-stop target-id)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns subtitle ID if time is between start and stop time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 3 do
+                  (let ((msecs (+ 1 (subed-subtitle-msecs-start target-id))))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal target-id)))))))
+      (it "returns nil if time is before the first subtitle's start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (let ((msecs (- (save-excursion
+                           (goto-char (point-min))
+                           (subed-subtitle-msecs-start)) 1)))
+           (cl-loop for outset-id from 1 to 3 do
+                    (progn
+                      (subed-jump-to-subtitle-id outset-id)
+                      (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
+      (it "returns nil if time is after the last subtitle's start time."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (let ((msecs (+ (save-excursion
+                           (goto-char (point-max))
+                           (subed-subtitle-msecs-stop)) 1)))
+           (cl-loop for outset-id from 1 to 3 do
+                    (progn
+                      (subed-jump-to-subtitle-id outset-id)
+                      (expect (subed-subtitle-id-at-msecs msecs) :to-equal 
nil))))))
+      (it "returns nil if time is between subtitles."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (cl-loop for target-id from 1 to 2 do
+                  (let ((msecs (+ (subed-subtitle-msecs-stop target-id) 1)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil))))
+                  (let ((msecs (- (subed-subtitle-msecs-start (+ target-id 1)) 
1)))
+                    (cl-loop for outset-id from 1 to 3 do
+                             (progn
+                               (subed-jump-to-subtitle-id outset-id)
+                               (expect (subed-subtitle-id-at-msecs msecs) 
:to-equal nil)))))))
+      (it "doesn't fail if start time is invalid."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (let ((msecs (- (subed-subtitle-msecs-start) 1)))
+           (subed-jump-to-subtitle-time-start)
+           (forward-char 8) (delete-char 1)
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal 2))))
       )
-    (describe "after"
-      (it "passing nothing."
-        (with-temp-srt-buffer
-          (expect (subed-srt--append-subtitle) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "0\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID."
-        (with-temp-srt-buffer
-          (expect (subed-srt--append-subtitle 2) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "2\n"
-                                                    "00:00:00,000 --> 
00:00:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID and start time."
-        (with-temp-srt-buffer
-          (expect (subed-srt--append-subtitle 3 60000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "3\n"
-                                                    "00:01:00,000 --> 
00:01:01,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time and stop time."
-        (with-temp-srt-buffer
-          (expect (subed-srt--append-subtitle 4 60000 65000) :to-equal 33)
-          (expect (buffer-string) :to-equal (concat "4\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n\n"))
-          (expect (point) :to-equal 33)))
-      (it "passing ID, start time, stop time and text."
-        (with-temp-srt-buffer
-          (expect (subed-srt--append-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
-          (expect (buffer-string) :to-equal (concat "5\n"
-                                                    "00:01:00,000 --> 
00:01:05,000\n"
-                                                    "Foo, bar\nbaz.\n"))
-          (expect (point) :to-equal 33)))
+    (describe "the subtitle start/stop time"
+      (it "returns the time in milliseconds."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 2 
1000) 234))
+         (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 10 
1000) 345))))
+      (it "handles lack of digits in milliseconds gracefully."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                                 (thing-at-point 'line)) :to-equal 
"00:03:03,45 --> 00:03:15,5\n")
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 3 60 1000) (*  3 
1000) 450))
+         (expect (subed-subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) (* 15 
1000) 500))))
+      (it "returns nil if time can't be found."
+        (with-temp-srt-buffer
+         (expect (subed-subtitle-msecs-start) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be nil)))
       )
-    )
-  (describe "in a non-empty buffer"
-    (describe "before the current subtitle"
-      (describe "with point on the first subtitle"
-        (it "passing nothing."
+    (describe "the subtitle text"
+      (describe "when text is empty"
+        (it "and at the beginning with a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-time-stop)
-            (expect (subed-srt--prepend-subtitle) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 1)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the beginning without a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-time-stop)
-            (expect (subed-srt--prepend-subtitle 7) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "7\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID and start time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 1)
+           (kill-whole-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and in the middle."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-time-stop)
-            (expect (subed-srt--prepend-subtitle 6 1500) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "6\n"
-                                                      "00:00:01,500 --> 
00:00:02,500\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID, start time and stop time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the end with a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-time-stop)
-            (expect (subed-srt--prepend-subtitle 5 1500 2000) :to-equal 33)
-            (expect (buffer-string) :to-equal (concat "5\n"
-                                                      "00:00:01,500 --> 
00:00:02,000\n"
-                                                      "\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
-        (it "passing ID, start time, stop time and text."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 3)
+           (kill-line)
+           (expect (subed-subtitle-text) :to-equal "")))
+        (it "and at the end without a trailing newline."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-time-stop)
-            (expect (subed-srt--prepend-subtitle 4 1500 3000 "Bar.") :to-equal 
33)
-            (expect (buffer-string) :to-equal (concat "4\n"
-                                                      "00:00:01,500 --> 
00:00:03,000\n"
-                                                      "Bar.\n\n"
-                                                      "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n"))
-            (expect (point) :to-equal 33)))
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 3)
+           (kill-whole-line)
+           (expect (subed-subtitle-text) :to-equal "")))
         )
-      (describe "with point on a non-first subtitle"
-        (it "passing nothing."
+      (describe "when text is not empty"
+        (it "and has no linebreaks."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-text 2)
-            (expect (subed-srt--prepend-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-text 2)
-            (expect (subed-srt--prepend-subtitle 9) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID and start time."
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (expect (subed-subtitle-text) :to-equal "Bar.")))
+        (it "and has linebreaks."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-text 2)
-            (expect (subed-srt--prepend-subtitle 9 7000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:08,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID, start time and stop time."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-text 2)
-            (expect (subed-srt--prepend-subtitle 9 7000 7123) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:07,123\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
-        (it "passing ID, start time, stop time and text."
-          (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:10,000 --> 00:00:12,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-text 2)
-            (expect (subed-srt--prepend-subtitle 9 7000 7123 "Baz.") :to-equal 
71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "9\n"
-                                                      "00:00:07,000 --> 
00:00:07,123\n"
-                                                      "Baz.\n\n"
-                                                      "2\n"
-                                                      "00:00:10,000 --> 
00:00:12,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (insert mock-srt-data)
+           (subed-jump-to-subtitle-text 2)
+           (insert "Bar.\n")
+           (expect (subed-subtitle-text) :to-equal "Bar.\nBar.")))
         )
       )
-    (describe "after the current subtitle"
-      (describe "with point on the last subtitle"
+    (describe "the point within the subtitle"
+      (it "returns the relative point if we can find an ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (expect (subed-subtitle-relative-point) :to-equal 0)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 2)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 32)
+         (forward-char)
+         (expect (subed-subtitle-relative-point) :to-equal 33)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 37)
+         (forward-line)
+         (expect (subed-subtitle-relative-point) :to-equal 0)))
+      (it "returns nil if we can't find an ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (insert "foo")
+         (expect (subed-subtitle-relative-point) :to-equal nil)))
+      )
+    )
+
+  (describe "Jumping"
+    (describe "to current subtitle ID"
+      (it "returns ID's point when point is already on the ID."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-jump-to-subtitle-id) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      (it "returns ID's point when point is on the duration."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (search-backward ",234")
+         (expect (thing-at-point 'word) :to-equal "02")
+         (expect (subed-jump-to-subtitle-id) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns ID's point when point is on the text."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (search-backward "Baz.")
+         (expect (thing-at-point 'word) :to-equal "Baz")
+         (expect (subed-jump-to-subtitle-id) :to-equal 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns ID's point when point is between subtitles."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Bar.\n")
+         (expect (thing-at-point 'line) :to-equal "\n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns nil if buffer is empty."
+        (with-temp-srt-buffer
+         (expect (buffer-string) :to-equal "")
+         (expect (subed-jump-to-subtitle-id) :to-equal nil)))
+      (it "returns ID's point when buffer starts with blank lines."
+        (with-temp-srt-buffer
+         (insert (concat " \n \t \n" mock-srt-data))
+         (search-backward "Foo.")
+         (expect (thing-at-point 'line) :to-equal "Foo.\n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 7)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      (it "returns ID's point when subtitles are separated with blank lines."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Foo.\n")
+         (insert " \n \t \n")
+         (expect (subed-jump-to-subtitle-id) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to specific subtitle ID"
+      (it "returns ID's point if wanted ID exists."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-max))
+         (expect (subed-jump-to-subtitle-id 2) :to-equal 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (expect (subed-jump-to-subtitle-id 1) :to-equal 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-jump-to-subtitle-id 3) :to-equal 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns nil and does not move if wanted ID does not exists."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (search-forward "Foo")
+         (let ((stored-point (point)))
+           (expect (subed-jump-to-subtitle-id 4) :to-equal nil)
+           (expect stored-point :to-equal (point)))))
+      )
+    (describe "to subtitle ID at specific time"
+      (it "returns ID's point if point changed."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-max))
+         (spy-on 'subed-subtitle-id-at-msecs :and-return-value (point-min))
+         (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal 
(point-min))
+         (expect (point) :to-equal (point-min))
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
+      (it "returns nil if point didn't change."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char 75)
+         (spy-on 'subed-subtitle-id-at-msecs :and-return-value 75)
+         (expect (subed-jump-to-subtitle-id-at-msecs 123450) :to-equal nil)
+         (expect (point) :to-equal 75)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-with 123450)
+         (expect 'subed-subtitle-id-at-msecs :to-have-been-called-times 1)))
+      )
+    (describe "to subtitle start time"
+      (it "returns start time's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 3)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:01:01,000")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 41)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:02:02,234")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 79)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:03:03,45")))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil)))
+      )
+    (describe "to subtitle stop time"
+      (it "returns stop time's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 20)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:01:05,123")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 58)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:02:10,345")
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 95)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
+         (expect (match-string 0) :to-equal "00:03:15,5")))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
+      )
+    (describe "to subtitle text"
+      (it "returns subtitle text's point if movement was successful."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-text) :to-equal 33)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Foo.")))
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-text) :to-equal 71)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Bar.")))
+         (re-search-forward "\n\n")
+         (expect (subed-jump-to-subtitle-text) :to-equal 106)
+         (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Baz.")))))
+      (it "returns nil if movement failed."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
+      )
+    (describe "to end of subtitle text"
+      (it "returns point if subtitle end can be found."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-end) :to-be 37)
+         (expect (looking-back "^Foo.$") :to-be t)
+         (forward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 75)
+         (expect (looking-back "^Bar.$") :to-be t)
+         (forward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 110)
+         (expect (looking-back "^Baz.$") :to-be t)
+         (goto-char (point-max))
+         (backward-char 2)
+         (expect (subed-jump-to-subtitle-end) :to-be 110)
+         (expect (looking-back "^Baz.$") :to-be t)))
+      (it "returns nil if subtitle end cannot be found."
+        (with-temp-srt-buffer
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
+      (it "returns nil if point did not move."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
+      (it "works if text is empty with trailing newline."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 33)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 2)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 67)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 3)
+         (kill-line)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 98)
+         (expect (looking-at "^$") :to-be t)))
+      (it "works if text is empty without trailing newline."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (goto-char (point-min))
+         (expect (subed-jump-to-subtitle-end) :to-be 33)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 2)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 66)
+         (expect (looking-at "^$") :to-be t)
+         (subed-jump-to-subtitle-text 3)
+         (kill-whole-line)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
+         (expect (looking-at "^$") :to-be t)
+         (backward-char)
+         (expect (subed-jump-to-subtitle-end) :to-be 96)
+         (expect (looking-at "^$") :to-be t)))
+      )
+    (describe "to next subtitle ID"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-forward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (subed-jump-to-subtitle-time-start 2)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be 77)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (expect (thing-at-point 'word) :to-equal nil)
+         (expect (subed-forward-subtitle-id) :to-be nil))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (subed-jump-to-subtitle-time-stop 2)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be 77)
+         (expect (thing-at-point 'word) :to-equal "3"))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 3)
+         (expect (thing-at-point 'word) :to-equal "Baz")
+         (expect (subed-forward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "Baz"))
+        (with-temp-srt-buffer
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-time-stop 3)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-forward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      )
+    (describe "to previous subtitle ID"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (thing-at-point 'word) :to-equal "Bar")
+         (expect (subed-backward-subtitle-id) :to-be 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (subed-jump-to-subtitle-time-stop 3)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-backward-subtitle-id) :to-be 39)
+         (expect (thing-at-point 'word) :to-equal "2")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (expect (subed-backward-subtitle-id) :to-be nil))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1"))
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "Foo"))
+        (with-temp-srt-buffer
+         (insert (concat "\n\n\n" mock-srt-data))
+         (subed-jump-to-subtitle-time-stop 1)
+         (expect (thing-at-point 'word) :to-equal "00")
+         (expect (subed-backward-subtitle-id) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      )
+    (describe "to next subtitle text"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-forward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (goto-char (point-max))
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle text"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle end"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 2)
+         (expect (thing-at-point 'word) :to-equal "Bar")
+         (expect (subed-forward-subtitle-end) :to-be 110)
+         (expect (thing-at-point 'word) :to-equal nil)))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert (concat mock-srt-data "\n\n"))
+         (subed-jump-to-subtitle-text 3)
+         (end-of-line)
+         (expect (thing-at-point 'word) :to-equal nil)
+         (expect (subed-forward-subtitle-end) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal nil)))
+      )
+    (describe "to previous subtitle end"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-text) :to-be 71)
+         (expect (thing-at-point 'word) :to-equal "Bar")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-text) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle start time"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-time-start) :to-be 41)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-time-start) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle start time"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (expect (thing-at-point 'word) :to-equal "2")
+         (expect (subed-backward-subtitle-time-start) :to-be 3)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-time-start) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    (describe "to next subtitle stop time"
+      (it "returns point when there is a next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-text 1)
+         (expect (thing-at-point 'word) :to-equal "Foo")
+         (expect (subed-forward-subtitle-time-stop) :to-be 58)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no next subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-forward-subtitle-time-stop) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "3")))
+      )
+    (describe "to previous subtitle stop time"
+      (it "returns point when there is a previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (expect (thing-at-point 'word) :to-equal "3")
+         (expect (subed-backward-subtitle-time-stop) :to-be 58)
+         (expect (thing-at-point 'word) :to-equal "00")))
+      (it "returns nil and doesn't move when there is no previous subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 1)
+         (expect (thing-at-point 'word) :to-equal "1")
+         (expect (subed-backward-subtitle-time-stop) :to-be nil)
+         (expect (thing-at-point 'word) :to-equal "1")))
+      )
+    )
+
+  (describe "Setting start/stop time"
+    (it "of current subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-end 2)
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 400))
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "01:02:03,400 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 7 
1000) 800))
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "01:02:03,400 --> 
05:06:07,800\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "of specific subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 3)
+       (subed-set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) (* 6 
1000) 800) 1)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "02:04:06,800 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-jump-to-subtitle-text 1)
+       (subed-set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 7 
1000) 900) 3)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "02:04:06,800 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 
03:05:07,900\n"
+                                                 "Baz.\n"))))
+    (it "when milliseconds lack digits."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 3)
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 4) 3)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 00:03:15,5\n")
+       (subed-set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 4 
1000) 60) 3)
+       (expect (save-excursion (subed-jump-to-subtitle-time-start)
+                               (thing-at-point 'line)) :to-equal "01:02:03,004 
--> 02:03:04,060\n")))
+    )
+
+  (describe "Inserting a subtitle"
+    (describe "in an empty buffer"
+      (describe "before"
         (it "passing nothing."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-text)
-            (expect (subed-srt--append-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "0\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-text)
-            (expect (subed-srt--append-subtitle 5) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 2) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "2\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID and start time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-text)
-            (expect (subed-srt--append-subtitle 5 12345) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:13,345\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 3 60000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "3\n"
+                                                     "00:01:00,000 --> 
00:01:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time and stop time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-text)
-            (expect (subed-srt--append-subtitle 5 12345 15000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:15,000\n"
-                                                      "\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 4 60000 65000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "4\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time, stop time and text."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Foo.\n"))
-            (subed-srt--jump-to-subtitle-text)
-            (expect (subed-srt--append-subtitle 5 12345 15000 "Bar.") 
:to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Foo.\n\n"
-                                                      "5\n"
-                                                      "00:00:12,345 --> 
00:00:15,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-prepend-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
+           (expect (buffer-string) :to-equal (concat "5\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n"
+                                                     "Foo, bar\nbaz.\n"))
+           (expect (point) :to-equal 33)))
         )
-      (describe "with point on a non-last subtitle"
+      (describe "after"
         (it "passing nothing."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-time-start 1)
-            (expect (subed-srt--append-subtitle) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "0\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "0\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-time-start 1)
-            (expect (subed-srt--append-subtitle 7) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:00,000 --> 
00:00:01,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 2) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "2\n"
+                                                     "00:00:00,000 --> 
00:00:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID and start time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-time-start 1)
-            (expect (subed-srt--append-subtitle 7 2500) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:03,500\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 3 60000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "3\n"
+                                                     "00:01:00,000 --> 
00:01:01,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time and stop time."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-time-start 1)
-            (expect (subed-srt--append-subtitle 7 2500 4000) :to-equal 71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:04,000\n"
-                                                      "\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 4 60000 65000) :to-equal 33)
+           (expect (buffer-string) :to-equal (concat "4\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n\n"))
+           (expect (point) :to-equal 33)))
         (it "passing ID, start time, stop time and text."
           (with-temp-srt-buffer
-            (insert (concat "1\n"
-                            "00:00:01,000 --> 00:00:02,000\n"
-                            "Foo.\n\n"
-                            "2\n"
-                            "00:00:05,000 --> 00:00:06,000\n"
-                            "Bar.\n"))
-            (subed-srt--jump-to-subtitle-time-start 1)
-            (expect (subed-srt--append-subtitle 7 2500 4000 "Baz.") :to-equal 
71)
-            (expect (buffer-string) :to-equal (concat "1\n"
-                                                      "00:00:01,000 --> 
00:00:02,000\n"
-                                                      "Foo.\n\n"
-                                                      "7\n"
-                                                      "00:00:02,500 --> 
00:00:04,000\n"
-                                                      "Baz.\n\n"
-                                                      "2\n"
-                                                      "00:00:05,000 --> 
00:00:06,000\n"
-                                                      "Bar.\n"))
-            (expect (point) :to-equal 71)))
+           (expect (subed-append-subtitle 5 60000 65000 "Foo, bar\nbaz.") 
:to-equal 33)
+           (expect (buffer-string) :to-equal (concat "5\n"
+                                                     "00:01:00,000 --> 
00:01:05,000\n"
+                                                     "Foo, bar\nbaz.\n"))
+           (expect (point) :to-equal 33)))
         )
       )
-    (it "when point is on empty text."
-      (with-temp-srt-buffer
-        (insert (concat "1\n"
-                        "00:00:01,000 --> 00:00:02,000\n"
-                        "\n"))
-        (subed-jump-to-subtitle-text)
-        (expect (subed-srt--append-subtitle) :to-equal 67)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:00:01,000 --> 
00:00:02,000\n"
-                                                  "\n\n"
-                                                  "0\n"
-                                                  "00:00:00,000 --> 
00:00:01,000\n"
-                                                  "\n"))
-        (expect (point) :to-equal 67)))
+    (describe "in a non-empty buffer"
+      (describe "before the current subtitle"
+        (describe "with point on the first subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 7) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "7\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 6 1500) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "6\n"
+                                                       "00:00:01,500 --> 
00:00:02,500\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 5 1500 2000) :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "5\n"
+                                                       "00:00:01,500 --> 
00:00:02,000\n"
+                                                       "\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle 4 1500 3000 "Bar.") :to-equal 33)
+             (expect (buffer-string) :to-equal (concat "4\n"
+                                                       "00:00:01,500 --> 
00:00:03,000\n"
+                                                       "Bar.\n\n"
+                                                       "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n"))
+             (expect (point) :to-equal 33)))
+          )
+        (describe "with point on a non-first subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:08,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000 7123) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:07,123\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:10,000 --> 00:00:12,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-text 2)
+             (expect (subed-prepend-subtitle 9 7000 7123 "Baz.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "9\n"
+                                                       "00:00:07,000 --> 
00:00:07,123\n"
+                                                       "Baz.\n\n"
+                                                       "2\n"
+                                                       "00:00:10,000 --> 
00:00:12,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        )
+      (describe "after the current subtitle"
+        (describe "with point on the last subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:13,345\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345 15000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:15,000\n"
+                                                       "\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Foo.\n"))
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle 5 12345 15000 "Bar.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Foo.\n\n"
+                                                       "5\n"
+                                                       "00:00:12,345 --> 
00:00:15,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        (describe "with point on a non-last subtitle"
+          (it "passing nothing."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "0\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:00,000 --> 
00:00:01,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID and start time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:03,500\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time and stop time."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500 4000) :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:04,000\n"
+                                                       "\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          (it "passing ID, start time, stop time and text."
+            (with-temp-srt-buffer
+             (insert (concat "1\n"
+                             "00:00:01,000 --> 00:00:02,000\n"
+                             "Foo.\n\n"
+                             "2\n"
+                             "00:00:05,000 --> 00:00:06,000\n"
+                             "Bar.\n"))
+             (subed-jump-to-subtitle-time-start 1)
+             (expect (subed-append-subtitle 7 2500 4000 "Baz.") :to-equal 71)
+             (expect (buffer-string) :to-equal (concat "1\n"
+                                                       "00:00:01,000 --> 
00:00:02,000\n"
+                                                       "Foo.\n\n"
+                                                       "7\n"
+                                                       "00:00:02,500 --> 
00:00:04,000\n"
+                                                       "Baz.\n\n"
+                                                       "2\n"
+                                                       "00:00:05,000 --> 
00:00:06,000\n"
+                                                       "Bar.\n"))
+             (expect (point) :to-equal 71)))
+          )
+        )
+      (it "when point is on empty text."
+        (with-temp-srt-buffer
+         (insert (concat "1\n"
+                         "00:00:01,000 --> 00:00:02,000\n"
+                         "\n"))
+         (subed-jump-to-subtitle-text)
+         (expect (subed-append-subtitle) :to-equal 67)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:00:01,000 --> 
00:00:02,000\n"
+                                                   "\n\n"
+                                                   "0\n"
+                                                   "00:00:00,000 --> 
00:00:01,000\n"
+                                                   "\n"))
+         (expect (point) :to-equal 67)))
+      )
     )
-  )
 
-(describe "Killing a subtitle"
-  (it "removes the first subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 1)
-      (subed-srt--kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes it in between."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 2)
-      (subed-srt--kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes the last subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 3)
-      (subed-srt--kill-subtitle)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n"))))
-  (describe "removes the previous subtitle when point is right above the ID"
-    (it "of the last subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 3)
-        (backward-char)
-        (expect (looking-at "^\n3\n") :to-be t)
-        (subed-srt--kill-subtitle)
-        (expect (buffer-string) :to-equal (concat "1\n"
-                                                  "00:01:01,000 --> 
00:01:05,123\n"
-                                                  "Foo.\n\n"
-                                                  "3\n"
-                                                  "00:03:03,45 --> 
00:03:15,5\n"
-                                                  "Baz.\n"))))
-    (it "of a non-last subtitle."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (subed-jump-to-subtitle-id 2)
-        (backward-char)
-        (expect (looking-at "^\n2\n") :to-be t)
-        (subed-srt--kill-subtitle)
-        (expect (buffer-string) :to-equal (concat "2\n"
-                                                  "00:02:02,234 --> 
00:02:10,345\n"
-                                                  "Bar.\n\n"
-                                                  "3\n"
-                                                  "00:03:03,45 --> 
00:03:15,5\n"
-                                                  "Baz.\n"))))
+  (describe "Killing a subtitle"
+    (it "removes the first subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 1)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes it in between."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (subed-kill-subtitle)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n"))))
+    (describe "removes the previous subtitle when point is right above the ID"
+      (it "of the last subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 3)
+         (backward-char)
+         (expect (looking-at "^\n3\n") :to-be t)
+         (subed-kill-subtitle)
+         (expect (buffer-string) :to-equal (concat "1\n"
+                                                   "00:01:01,000 --> 
00:01:05,123\n"
+                                                   "Foo.\n\n"
+                                                   "3\n"
+                                                   "00:03:03,45 --> 
00:03:15,5\n"
+                                                   "Baz.\n"))))
+      (it "of a non-last subtitle."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (subed-jump-to-subtitle-id 2)
+         (backward-char)
+         (expect (looking-at "^\n2\n") :to-be t)
+         (subed-kill-subtitle)
+         (expect (buffer-string) :to-equal (concat "2\n"
+                                                   "00:02:02,234 --> 
00:02:10,345\n"
+                                                   "Bar.\n\n"
+                                                   "3\n"
+                                                   "00:03:03,45 --> 
00:03:15,5\n"
+                                                   "Baz.\n"))))
+      )
     )
-  )
 
-(describe "Validating"
-  (it "works in empty buffer."
-    (with-temp-srt-buffer
-     (subed-srt--validate)))
-  (it "works in buffer that contains only newlines."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (insert "\n")
-               (subed-srt--validate))))
-  (it "works in buffer that contains only spaces."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (insert " ")
-               (subed-srt--validate))))
-  (it "works in buffer that contains only spaces and newlines."
-    (with-temp-srt-buffer
-      (cl-loop for _ from 1 to 10 do
-               (if (eq (random 2) 0)
-                   (insert " ")
-                 (insert "\n"))
-               (subed-srt--validate))))
-  (it "reports invalid IDs."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-id 1)
-      (insert "x")
-      (expect (subed-srt--validate) :to-throw
-              'error '("Found invalid subtitle ID: \"x1\""))
-      (expect (point) :to-equal 1)))
-  (it "reports invalid start time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-time-start 1)
-      (forward-char 5)
-      (delete-char 1)
-      (expect (subed-srt--validate) :to-throw
-              'error '("Found invalid start time: \"00:0101,000 --> 
00:01:05,123\""))
-      (expect (point) :to-equal 3)))
-  (it "reports invalid stop time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-time-stop 1)
-      (forward-char 10)
-      (insert "3")
-      (expect (subed-srt--validate) :to-throw
-              'error '("Found invalid stop time: \"00:01:01,000 --> 
00:01:05,1323\""))
-      (expect (point) :to-equal 20)))
-  (it "reports invalid time separator."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-time-stop 1)
-      (delete-char -1)
-      (expect (subed-srt--validate) :to-throw
-              'error '("Found invalid separator between start and stop time: 
\"00:01:01,000 -->00:01:05,123\""))
-      (expect (point) :to-equal 15)))
-  (it "reports invalid start time in later entries."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-time-start 3)
-      (forward-char 3)
-      (insert "##")
-      (expect (subed-srt--validate) :to-throw
-              'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
-      (expect (point) :to-equal 79)))
-  (it "does not report error when last subtitle text is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 3)
-      (kill-whole-line)
-      (forward-char -2)
-      (subed-srt--validate)
-      (expect (point) :to-equal 104)))
-  (it "preserves point if there is no error."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 2)
-      (forward-char 2)
-      (subed-srt--validate)
-      (expect (point) :to-equal 73)))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-     (insert mock-srt-data)
-     (subed-srt--jump-to-subtitle-time-start 3)
-     (forward-char 3)
-     (insert "##")
-     (expect (subed-prepare-to-save) :to-throw
-             'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
-     (expect (point) :to-equal 79))))
+  (describe "Validating"
+    (it "works in empty buffer."
+      (with-temp-srt-buffer
+       (subed-validate)))
+    (it "works in buffer that contains only newlines."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (insert "\n")
+                (subed-validate))))
+    (it "works in buffer that contains only spaces."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (insert " ")
+                (subed-validate))))
+    (it "works in buffer that contains only spaces and newlines."
+      (with-temp-srt-buffer
+       (cl-loop for _ from 1 to 10 do
+                (if (eq (random 2) 0)
+                    (insert " ")
+                  (insert "\n"))
+                (subed-validate))))
+    (it "reports invalid IDs."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-id 1)
+       (insert "x")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid subtitle ID: \"x1\""))
+       (expect (point) :to-equal 1)))
+    (it "reports invalid start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 1)
+       (forward-char 5)
+       (delete-char 1)
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid start time: \"00:0101,000 --> 
00:01:05,123\""))
+       (expect (point) :to-equal 3)))
+    (it "reports invalid stop time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 1)
+       (forward-char 10)
+       (insert "3")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid stop time: \"00:01:01,000 --> 
00:01:05,1323\""))
+       (expect (point) :to-equal 20)))
+    (it "reports invalid time separator."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-stop 1)
+       (delete-char -1)
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid separator between start and stop time: 
\"00:01:01,000 -->00:01:05,123\""))
+       (expect (point) :to-equal 15)))
+    (it "reports invalid start time in later entries."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 3)
+       (forward-char 3)
+       (insert "##")
+       (expect (subed-validate) :to-throw
+               'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
+       (expect (point) :to-equal 79)))
+    (it "does not report error when last subtitle text is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (kill-whole-line)
+       (forward-char -2)
+       (subed-validate)
+       (expect (point) :to-equal 104)))
+    (it "preserves point if there is no error."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (forward-char 2)
+       (subed-validate)
+       (expect (point) :to-equal 73)))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-time-start 3)
+       (forward-char 3)
+       (insert "##")
+       (expect (subed-prepare-to-save) :to-throw
+               'error '("Found invalid start time: \"00:##03:03,45 --> 
00:03:15,5\""))
+       (expect (point) :to-equal 79))))
 
-(describe "Sanitizing"
-  (it "removes trailing tabs and spaces from all lines."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match " \n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data))
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\t\n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes leading tabs and spaces from all lines."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\n "))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data))
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n" nil t)
-        (replace-match "\n\t"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes excessive empty lines between subtitles."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (re-search-forward "\n\n" nil t)
-        (replace-match "\n \n  \t  \t\t  \n\n  \t\n"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures double newline between subtitles if text of previous subtitle 
is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 1)
-      (kill-whole-line)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "Baz.\n"))))
-  (it "removes empty lines from beginning of buffer."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (insert " \n\t\n")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "removes empty lines from end of buffer."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-max))
-      (insert " \n\t\n\n")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures a single newline after the last subtitle."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-max))
-      (while (eq (char-before (point-max)) ?\n)
-        (delete-backward-char 1))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "ensures single newline after last subtitle if text is empty."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (subed-srt--jump-to-subtitle-text 3)
-      (kill-whole-line)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                ""))
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal (concat "1\n"
-                                                "00:01:01,000 --> 
00:01:05,123\n"
-                                                "Foo.\n\n"
-                                                "2\n"
-                                                "00:02:02,234 --> 
00:02:10,345\n"
-                                                "Bar.\n\n"
-                                                "3\n"
-                                                "00:03:03,45 --> 00:03:15,5\n"
-                                                "\n"))))
-  (it "ensures single space before and after time separators."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (re-search-forward " --> ")
-      (replace-match "  --> ")
-      (re-search-forward " --> ")
-      (replace-match " -->  ")
-      (re-search-forward " --> ")
-      (replace-match "-->")
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "does not insert newline in empty buffer."
-    (with-temp-srt-buffer
-      (expect (buffer-string) :to-equal "")
-      (subed-srt--sanitize)
-      (expect (buffer-string) :to-equal "")))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-     (insert mock-srt-data)
-     (goto-char (point-min))
-     (re-search-forward " --> ")
-     (replace-match "  --> ")
-     (re-search-forward " --> ")
-     (replace-match " -->  ")
-     (re-search-forward " --> ")
-     (replace-match "-->")
-     (expect (buffer-string) :not :to-equal mock-srt-data)
-     (subed-prepare-to-save)
-     (expect (buffer-string) :to-equal mock-srt-data))))
+  (describe "Sanitizing"
+    (it "removes trailing tabs and spaces from all lines."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match " \n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data))
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\t\n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes leading tabs and spaces from all lines."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\n "))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data))
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n" nil t)
+         (replace-match "\n\t"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes excessive empty lines between subtitles."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (re-search-forward "\n\n" nil t)
+         (replace-match "\n \n  \t  \t\t  \n\n  \t\n"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures double newline between subtitles if text of previous subtitle 
is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 1)
+       (kill-whole-line)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "Baz.\n"))))
+    (it "removes empty lines from beginning of buffer."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (insert " \n\t\n")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "removes empty lines from end of buffer."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-max))
+       (insert " \n\t\n\n")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures a single newline after the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-max))
+       (while (eq (char-before (point-max)) ?\n)
+         (delete-backward-char 1))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "ensures single newline after last subtitle if text is empty."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (kill-whole-line)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 ""))
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal (concat "1\n"
+                                                 "00:01:01,000 --> 
00:01:05,123\n"
+                                                 "Foo.\n\n"
+                                                 "2\n"
+                                                 "00:02:02,234 --> 
00:02:10,345\n"
+                                                 "Bar.\n\n"
+                                                 "3\n"
+                                                 "00:03:03,45 --> 00:03:15,5\n"
+                                                 "\n"))))
+    (it "ensures single space before and after time separators."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward " --> ")
+       (replace-match "  --> ")
+       (re-search-forward " --> ")
+       (replace-match " -->  ")
+       (re-search-forward " --> ")
+       (replace-match "-->")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "does not insert newline in empty buffer."
+      (with-temp-srt-buffer
+       (expect (buffer-string) :to-equal "")
+       (subed-sanitize)
+       (expect (buffer-string) :to-equal "")))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward " --> ")
+       (replace-match "  --> ")
+       (re-search-forward " --> ")
+       (replace-match " -->  ")
+       (re-search-forward " --> ")
+       (replace-match "-->")
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-prepare-to-save)
+       (expect (buffer-string) :to-equal mock-srt-data))))
 
-(describe "Renumbering"
-  (it "ensures consecutive subtitle IDs."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (replace-match "123"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-srt--regenerate-ids)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "runs before saving."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (replace-match "123"))
-      (expect (buffer-string) :not :to-equal mock-srt-data)
-      (subed-prepare-to-save)
-      (expect (buffer-string) :to-equal mock-srt-data)))
-  (it "does not modify the kill-ring."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (kill-new "asdf")
-      (goto-char (point-min))
-      (while (looking-at "^[0-9]$")
-        (insert "555"))
-      (subed-srt--regenerate-ids)
-      (expect (car kill-ring) :to-equal "asdf")))
-  (it "does not modify empty buffer."
-    (with-temp-srt-buffer
-      (subed-srt--regenerate-ids)
-      (expect (buffer-string) :to-equal "")))
-  )
+  (describe "Renumbering"
+    (it "ensures consecutive subtitle IDs."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (replace-match "123"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-regenerate-ids)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "runs before saving."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (replace-match "123"))
+       (expect (buffer-string) :not :to-equal mock-srt-data)
+       (subed-prepare-to-save)
+       (expect (buffer-string) :to-equal mock-srt-data)))
+    (it "does not modify the kill-ring."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (kill-new "asdf")
+       (goto-char (point-min))
+       (while (looking-at "^[0-9]$")
+         (insert "555"))
+       (subed-regenerate-ids)
+       (expect (car kill-ring) :to-equal "asdf")))
+    (it "does not modify empty buffer."
+      (with-temp-srt-buffer
+       (subed-regenerate-ids)
+       (expect (buffer-string) :to-equal "")))
+    )
 
-(describe "Sorting"
-  (it "orders subtitles by start time."
-    (with-temp-srt-buffer
-      (insert mock-srt-data)
-      (goto-char (point-min))
-      (re-search-forward "01:01")
-      (replace-match "12:01")
-      (goto-char (point-min))
-      (re-search-forward "02:02")
-      (replace-match "10:02")
-      (goto-char (point-min))
-      (re-search-forward "03:03")
-      (replace-match "11:03")
-      (subed-srt--sort)
-      (expect (buffer-string) :to-equal
-              (concat
-               "1\n"
-               "00:10:02,234 --> 00:02:10,345\n"
-               "Bar.\n"
-               "\n"
-               "2\n"
-               "00:11:03,45 --> 00:03:15,5\n"
-               "Baz.\n"
-               "\n"
-               "3\n"
-               "00:12:01,000 --> 00:01:05,123\n"
-               "Foo.\n"))))
-  (describe "preserves point in the current subtitle"
-    (it "when subtitle text is non-empty."
-      (with-temp-srt-buffer
-        (insert mock-srt-data)
-        (goto-char (point-min))
-        (re-search-forward "01:01")
-        (replace-match "12:01")
-        (search-forward "\n")
-        (expect (current-word) :to-equal "Foo")
-        (subed-srt--sort)
-        (expect (current-word) :to-equal "Foo")))
-    (it "when subtitle text is empty."
-      (with-temp-srt-buffer
-        (insert "1\n00:12:01,000 --> 00:01:05,123\n")
-        (goto-char (point-max))
-        (subed-srt--sort)
-        (expect (point) :to-equal 33)))
+  (describe "Sorting"
+    (it "orders subtitles by start time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (goto-char (point-min))
+       (re-search-forward "01:01")
+       (replace-match "12:01")
+       (goto-char (point-min))
+       (re-search-forward "02:02")
+       (replace-match "10:02")
+       (goto-char (point-min))
+       (re-search-forward "03:03")
+       (replace-match "11:03")
+       (subed-sort)
+       (expect (buffer-string) :to-equal
+               (concat
+                "1\n"
+                "00:10:02,234 --> 00:02:10,345\n"
+                "Bar.\n"
+                "\n"
+                "2\n"
+                "00:11:03,45 --> 00:03:15,5\n"
+                "Baz.\n"
+                "\n"
+                "3\n"
+                "00:12:01,000 --> 00:01:05,123\n"
+                "Foo.\n"))))
+    (describe "preserves point in the current subtitle"
+      (it "when subtitle text is non-empty."
+        (with-temp-srt-buffer
+         (insert mock-srt-data)
+         (goto-char (point-min))
+         (re-search-forward "01:01")
+         (replace-match "12:01")
+         (search-forward "\n")
+         (expect (current-word) :to-equal "Foo")
+         (subed-sort)
+         (expect (current-word) :to-equal "Foo")))
+      (it "when subtitle text is empty."
+        (with-temp-srt-buffer
+         (insert "1\n00:12:01,000 --> 00:01:05,123\n")
+         (goto-char (point-max))
+         (subed-sort)
+         (expect (point) :to-equal 33)))
+      )
     )
-  )
-(describe "Converting msecs to timestamp"
-  (it "uses the right format"
-    (with-temp-srt-buffer
-     (expect (subed-msecs-to-timestamp 1401) :to-equal "00:00:01,401"))))
+  (describe "Converting msecs to timestamp"
+    (it "uses the right format"
+      (with-temp-srt-buffer
+       (expect (subed-msecs-to-timestamp 1401) :to-equal "00:00:01,401"))))
+
+  (describe "Merging with next subtitle"
+    (it "throws an error in an empty buffer."
+      (with-temp-srt-buffer
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "throws an error with the last subtitle."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 3)
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "combines the text and the time."
+      (with-temp-srt-buffer
+       (insert mock-srt-data)
+       (subed-jump-to-subtitle-text 2)
+       (subed-merge-with-next)
+       (expect (subed-subtitle-text) :to-equal "Bar.\nBaz.")
+       (expect (subed-subtitle-msecs-start) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop) :to-equal 195500)))))
diff --git a/tests/test-subed-vtt.el b/tests/test-subed-vtt.el
index a044b8dafa..7f27d9eb31 100644
--- a/tests/test-subed-vtt.el
+++ b/tests/test-subed-vtt.el
@@ -1,7 +1,8 @@
 ;; -*- eval: (buttercup-minor-mode) -*-
 
-(add-to-list 'load-path "./subed")
+(load-file "./tests/undercover-init.el")
 (require 'subed)
+(require 'subed-vtt)
 
 (defvar mock-vtt-data
   "WEBVTT
@@ -19,103 +20,148 @@ Baz.
 (defmacro with-temp-vtt-buffer (&rest body)
   "Call `subed-vtt--init' in temporary buffer before running BODY."
   `(with-temp-buffer
-    (subed-vtt--init)
+    (subed-vtt-mode)
     (progn ,@body)))
 
 (describe "VTT"
   (describe "Getting"
+    (describe "the subtitle ID"
+      (it "returns the subtitle ID if it can be found."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (subed-jump-to-subtitle-text "00:01:01.000")
+         (expect (subed-subtitle-id) :to-equal "00:01:01.000")))
+      (it "returns nil if no subtitle ID can be found."
+        (with-temp-vtt-buffer
+         (expect (subed-subtitle-id) :to-equal nil))))
+    (describe "the subtitle ID at playback time"
+      (it "returns subtitle ID if time is equal to start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:01:01.000"))
+                 :to-equal "00:01:01.000")))
+      (it "returns subtitle ID if time is equal to stop time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:02:10.345"))
+                 :to-equal "00:02:02.234")))
+      (it "returns subtitle ID if time is between start and stop time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:02:05.345"))
+                 :to-equal "00:02:02.234")))
+      (it "returns nil if time is before the first subtitle's start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (let ((msecs (- (save-excursion
+                           (goto-char (point-min))
+                           (subed-subtitle-msecs-start))
+                         1)))
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal nil))))
+      (it "returns nil if time is after the last subtitle's start time."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (let ((msecs (+ (save-excursion
+                           (goto-char (point-max))
+                           (subed-subtitle-msecs-stop)) 1)))
+           (expect (subed-subtitle-id-at-msecs msecs) :to-equal nil))))
+      (it "returns nil if time is between subtitles."
+        (with-temp-vtt-buffer
+         (insert mock-vtt-data)
+         (expect (subed-subtitle-id-at-msecs (subed-timestamp-to-msecs 
"00:01:06.123"))
+                 :to-equal nil))))
     (describe "the subtitle start/stop time"
       (it "returns the time in milliseconds."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:02:02.234")
-         (expect (subed-vtt--subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 
2 1000) 234))
-         (expect (subed-vtt--subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 
10 1000) 345))))
+         (subed-jump-to-subtitle-id "00:02:02.234")
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 2 60000) (* 2 
1000) 234))
+         (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 2 60000) (* 10 
1000) 345))))
       (it "handles lack of digits in milliseconds gracefully."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
-         (expect (save-excursion (subed-vtt--jump-to-subtitle-time-start)
+         (subed-jump-to-subtitle-id "00:03:03.45")
+         (expect (save-excursion (subed-jump-to-subtitle-time-start)
                                  (thing-at-point 'line)) :to-equal 
"00:03:03.45 --> 00:03:15.5\n")
-         (expect (subed-vtt--subtitle-msecs-start) :to-equal (+ (* 3 60 1000) 
(*  3 1000) 450))
-         (expect (subed-vtt--subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) 
(* 15 1000) 500))))
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 3 60 1000) (*  3 
1000) 450))
+         (expect (subed-subtitle-msecs-stop)  :to-equal (+ (* 3 60 1000) (* 15 
1000) 500))))
       (it "handles lack of hours in milliseconds gracefully."
         (with-temp-vtt-buffer
          (insert "WEBVTT\n\n01:02.000 --> 03:04.000\nHello\n")
-         (expect (subed-vtt--subtitle-msecs-start) :to-equal (+ (* 1 60 1000) 
(* 2 1000)))
-         (expect (subed-vtt--subtitle-msecs-stop) :to-equal (+ (* 3 60 1000) 
(* 4 1000)))))
+         (expect (subed-subtitle-msecs-start) :to-equal (+ (* 1 60 1000) (* 2 
1000)))
+         (expect (subed-subtitle-msecs-stop) :to-equal (+ (* 3 60 1000) (* 4 
1000)))))
       (it "returns nil if time can't be found."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--subtitle-msecs-start) :to-be nil)
-         (expect (subed-vtt--subtitle-msecs-stop) :to-be nil)))
+         (expect (subed-subtitle-msecs-start) :to-be nil)
+         (expect (subed-subtitle-msecs-stop) :to-be nil)))
       )
     (describe "the subtitle text"
       (describe "when text is empty"
         (it "and at the beginning with a trailing newline."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+           (subed-jump-to-subtitle-text "00:01:01.000")
            (kill-line)
-           (expect (subed-vtt--subtitle-text) :to-equal "")))
+           (expect (subed-subtitle-text) :to-equal "")))
         (it "and at the beginning without a trailing newline."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+           (subed-jump-to-subtitle-text "00:01:01.000")
            (kill-whole-line)
-           (expect (subed-vtt--subtitle-text) :to-equal "")))
+           (expect (subed-subtitle-text) :to-equal "")))
         (it "and in the middle."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+           (subed-jump-to-subtitle-text "00:02:02.234")
            (kill-line)
-           (expect (subed-vtt--subtitle-text) :to-equal "")))
+           (expect (subed-subtitle-text) :to-equal "")))
         (it "and at the end with a trailing newline."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+           (subed-jump-to-subtitle-text "00:03:03.45")
            (kill-line)
-           (expect (subed-vtt--subtitle-text) :to-equal "")))
+           (expect (subed-subtitle-text) :to-equal "")))
         (it "and at the end without a trailing newline."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+           (subed-jump-to-subtitle-text "00:03:03.45")
            (kill-whole-line)
-           (expect (subed-vtt--subtitle-text) :to-equal "")))
+           (expect (subed-subtitle-text) :to-equal "")))
         )
       (describe "when text is not empty"
         (it "and has no linebreaks."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:02:02.234")
-           (expect (subed-vtt--subtitle-text) :to-equal "Bar.")))
+           (subed-jump-to-subtitle-text "00:02:02.234")
+           (expect (subed-subtitle-text) :to-equal "Bar.")))
         (it "and has linebreaks."
           (with-temp-vtt-buffer
            (insert mock-vtt-data)
-           (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+           (subed-jump-to-subtitle-text "00:02:02.234")
            (insert "Bar.\n")
-           (expect (subed-vtt--subtitle-text) :to-equal "Bar.\nBar.")))
+           (expect (subed-subtitle-text) :to-equal "Bar.\nBar.")))
         )
       )
     (describe "the point within the subtitle"
       (it "returns the relative point if we can find an ID."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:02:02.234")
-         (expect (subed-vtt--subtitle-relative-point) :to-equal 0)
+         (subed-jump-to-subtitle-id "00:02:02.234")
+         (expect (subed-subtitle-relative-point) :to-equal 0)
          (forward-line)
-         (expect (subed-vtt--subtitle-relative-point) :to-equal 30)
+         (expect (subed-subtitle-relative-point) :to-equal 30)
          (forward-char)
-         (expect (subed-vtt--subtitle-relative-point) :to-equal 31)
+         (expect (subed-subtitle-relative-point) :to-equal 31)
          (forward-line)
-         (expect (subed-vtt--subtitle-relative-point) :to-equal 35)
+         (expect (subed-subtitle-relative-point) :to-equal 35)
          (forward-line)
-         (expect (subed-vtt--subtitle-relative-point) :to-equal 0)))
+         (expect (subed-subtitle-relative-point) :to-equal 0)))
       (it "returns nil if we can't find an ID."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (insert "foo")
-         (expect (subed-vtt--subtitle-relative-point) :to-equal nil)))
+         (expect (subed-subtitle-relative-point) :to-equal nil)))
       )
     )
 
@@ -125,17 +171,17 @@ Baz.
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal (point))
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (subed-jump-to-subtitle-id "00:01:01.000")
+         (expect (subed-jump-to-subtitle-time-start) :to-equal (point))
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:01:01.000")))
       (it "returns timestamp's point when point is on the text."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (search-backward "Baz.")
          (expect (thing-at-point 'word) :to-equal "Baz")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 81)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 81)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:03:03.45")))
       (it "returns timestamp's point when point is between subtitles."
         (with-temp-vtt-buffer
@@ -143,20 +189,20 @@ Baz.
          (goto-char (point-min))
          (search-forward "Bar.\n")
          (expect (thing-at-point 'line) :to-equal "\n")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 45)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 45)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:02:02.234")))
       (it "returns nil if buffer is empty."
         (with-temp-vtt-buffer
          (expect (buffer-string) :to-equal "")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal nil)))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil)))
       (it "returns timestamp's point when buffer starts with blank lines."
         (with-temp-vtt-buffer
          (insert (concat "WEBVTT \n \t \n" (replace-regexp-in-string "WEBVTT" 
"" mock-vtt-data)))
          (search-backward "Foo.")
          (expect (thing-at-point 'line) :to-equal "Foo.\n")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 15)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 15)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:01:01.000")))
       (it "returns timestamp's point when subtitles are separated with blank 
lines."
         (with-temp-vtt-buffer
@@ -164,8 +210,8 @@ Baz.
          (goto-char (point-min))
          (search-forward "Foo.\n")
          (insert " \n \t \n")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 9)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 9)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:01:01.000")))
       )
     (describe "to specific subtitle by timestamp"
@@ -173,9 +219,9 @@ Baz.
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-max))
-         (expect (subed-vtt--jump-to-subtitle-id "00:02:02.234") :to-equal 45)
+         (expect (subed-jump-to-subtitle-id "00:02:02.234") :to-equal 45)
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
-         (expect (subed-vtt--jump-to-subtitle-id "00:01:01.000") :to-equal 9)
+         (expect (subed-jump-to-subtitle-id "00:01:01.000") :to-equal 9)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       (it "returns nil and does not move if wanted ID does not exists."
         (with-temp-vtt-buffer
@@ -183,7 +229,7 @@ Baz.
          (goto-char (point-min))
          (search-forward "Foo")
          (let ((stored-point (point)))
-           (expect (subed-vtt--jump-to-subtitle-id "0:08:00") :to-equal nil)
+           (expect (subed-jump-to-subtitle-id "0:08:00") :to-equal nil)
            (expect stored-point :to-equal (point)))))
       )
     (describe "to subtitle start time"
@@ -191,74 +237,74 @@ Baz.
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 9)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 9)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:01:01.000")
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 45)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 45)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:02:02.234")
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal 81)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-start) :to-equal 81)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:03:03.45")))
       (it "returns nil if movement failed."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--jump-to-subtitle-time-start) :to-equal nil)))
+         (expect (subed-jump-to-subtitle-time-start) :to-equal nil)))
       )
     (describe "to subtitle stop time"
       (it "returns stop time's point if movement was successful."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-time-stop) :to-equal 26)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 26)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:01:05.123")
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-time-stop) :to-equal 62)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 62)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:02:10.345")
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-time-stop) :to-equal 97)
-         (expect (looking-at subed-vtt--regexp-timestamp) :to-be t)
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal 97)
+         (expect (looking-at subed--regexp-timestamp) :to-be t)
          (expect (match-string 0) :to-equal "00:03:15.5")))
       (it "returns nil if movement failed."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--jump-to-subtitle-time-stop) :to-equal nil)))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
       )
     (describe "to subtitle text"
       (it "returns subtitle text's point if movement was successful."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-text) :to-equal 39)
+         (expect (subed-jump-to-subtitle-text) :to-equal 39)
          (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Foo.")))
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-text) :to-equal 75)
+         (expect (subed-jump-to-subtitle-text) :to-equal 75)
          (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Bar.")))
          (re-search-forward "\n\n")
-         (expect (subed-vtt--jump-to-subtitle-text) :to-equal 108)
+         (expect (subed-jump-to-subtitle-text) :to-equal 108)
          (expect (point) :to-equal (save-excursion (goto-char (point-max)) 
(search-backward "Baz.")))))
       (it "returns nil if movement failed."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--jump-to-subtitle-time-stop) :to-equal nil)))
+         (expect (subed-jump-to-subtitle-time-stop) :to-equal nil)))
       )
     (describe "to end of subtitle text"
       (it "returns point if subtitle end can be found."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 43)
+         (expect (subed-jump-to-subtitle-end) :to-be 43)
          (expect (looking-back "^Foo.$") :to-be t)
          (forward-char 2)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 79)
+         (expect (subed-jump-to-subtitle-end) :to-be 79)
          (expect (looking-back "^Bar.$") :to-be t)
          (forward-char 2)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 112)
+         (expect (subed-jump-to-subtitle-end) :to-be 112)
          (expect (looking-back "^Baz.$") :to-be t)
          (goto-char (point-max))
          (backward-char 2)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 112)
+         (expect (subed-jump-to-subtitle-end) :to-be 112)
          (expect (looking-back "^Baz.$") :to-be t)))
       (it "handles spaces in between subtitles."
         (with-temp-vtt-buffer
@@ -267,263 +313,263 @@ Baz.
          (re-search-forward "Foo\\.\n")
          (replace-match "Foo.\n ")
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 43)
+         (expect (subed-jump-to-subtitle-end) :to-be 43)
          (expect (looking-back "^Foo.$") :to-be t)))
       (it "returns nil if subtitle end cannot be found."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be nil)))
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
       (it "returns nil if point did not move."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (kill-line)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be nil)))
+         (expect (subed-jump-to-subtitle-end) :to-be nil)))
       (it "works if text is empty with trailing newline."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (kill-line)
          (backward-char)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 39)
+         (expect (subed-jump-to-subtitle-end) :to-be 39)
          (expect (looking-at "^$") :to-be t)
-         (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+         (subed-jump-to-subtitle-text "00:02:02.234")
          (kill-line)
          (backward-char)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 71)
+         (expect (subed-jump-to-subtitle-end) :to-be 71)
          (expect (looking-at "^$") :to-be t)
-         (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+         (subed-jump-to-subtitle-text "00:03:03.45")
          (kill-line)
          (backward-char)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 100)
+         (expect (subed-jump-to-subtitle-end) :to-be 100)
          (expect (looking-at "^$") :to-be t)))
       (it "works if text is empty without trailing newline."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (kill-whole-line)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be nil)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
          (expect (looking-at "^$") :to-be t)
          (goto-char (point-min))
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 39)
+         (expect (subed-jump-to-subtitle-end) :to-be 39)
          (expect (looking-at "^$") :to-be t)
-         (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+         (subed-jump-to-subtitle-text "00:02:02.234")
          (kill-whole-line)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be nil)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
          (expect (looking-at "^$") :to-be t)
          (backward-char)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 70)
+         (expect (subed-jump-to-subtitle-end) :to-be 70)
          (expect (looking-at "^$") :to-be t)
-         (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+         (subed-jump-to-subtitle-text "00:03:03.45")
          (kill-whole-line)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be nil)
+         (expect (subed-jump-to-subtitle-end) :to-be nil)
          (expect (looking-at "^$") :to-be t)
          (backward-char)
-         (expect (subed-vtt--jump-to-subtitle-end) :to-be 98)
+         (expect (subed-jump-to-subtitle-end) :to-be 98)
          (expect (looking-at "^$") :to-be t)))
       )
     (describe "to next subtitle ID"
       (it "returns point when there is a next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-id) :to-be 45)
+         (expect (subed-forward-subtitle-id) :to-be 45)
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
-         (subed-vtt--jump-to-subtitle-time-start "00:02:02.234")
+         (subed-jump-to-subtitle-time-start "00:02:02.234")
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-id) :to-be 81)
+         (expect (subed-forward-subtitle-id) :to-be 81)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-vtt-buffer
          (expect (thing-at-point 'word) :to-equal nil)
-         (expect (subed-vtt--forward-subtitle-id) :to-be nil))
+         (expect (subed-forward-subtitle-id) :to-be nil))
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (expect (thing-at-point 'word) :to-equal "Foo")
-         (expect (subed-vtt--forward-subtitle-id) :to-be 45)
+         (expect (subed-forward-subtitle-id) :to-be 45)
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
-         (subed-vtt--jump-to-subtitle-time-stop "00:02:02.234")
+         (subed-jump-to-subtitle-time-stop "00:02:02.234")
          (expect (looking-at (regexp-quote "00:02:10.345")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-id) :to-be 81)
+         (expect (subed-forward-subtitle-id) :to-be 81)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t))
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+         (subed-jump-to-subtitle-text "00:03:03.45")
          (expect (thing-at-point 'word) :to-equal "Baz")
-         (expect (subed-vtt--forward-subtitle-id) :to-be nil)
+         (expect (subed-forward-subtitle-id) :to-be nil)
          (expect (thing-at-point 'word) :to-equal "Baz"))
         (with-temp-vtt-buffer
          (insert (concat mock-vtt-data "\n\n"))
-         (subed-vtt--jump-to-subtitle-time-stop "00:03:03.45")
+         (subed-jump-to-subtitle-time-stop "00:03:03.45")
          (expect (thing-at-point 'word) :to-equal "00")
-         (expect (subed-vtt--forward-subtitle-id) :to-be nil)
+         (expect (subed-forward-subtitle-id) :to-be nil)
          (expect (thing-at-point 'word) :to-equal "00")))
       )
     (describe "to previous subtitle ID"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+         (subed-jump-to-subtitle-text "00:02:02.234")
          (expect (thing-at-point 'word) :to-equal "Bar")
-         (expect (subed-vtt--backward-subtitle-id) :to-be 9)
+         (expect (subed-backward-subtitle-id) :to-be 9)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (subed-vtt--jump-to-subtitle-time-stop "00:03:03.45")
+         (subed-jump-to-subtitle-time-stop "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:15.5")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-id) :to-be 45)
+         (expect (subed-backward-subtitle-id) :to-be 45)
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-vtt-buffer
-         (expect (subed-vtt--backward-subtitle-id) :to-be nil))
+         (expect (subed-backward-subtitle-id) :to-be nil))
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-id) :to-be nil)
+         (expect (subed-backward-subtitle-id) :to-be nil)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t))
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (expect (thing-at-point 'word) :to-equal "Foo")
-         (expect (subed-vtt--backward-subtitle-id) :to-be nil)
+         (expect (subed-backward-subtitle-id) :to-be nil)
          (expect (thing-at-point 'word) :to-equal "Foo"))
         (with-temp-vtt-buffer
          (insert (concat "\n\n\n" mock-vtt-data))
-         (subed-vtt--jump-to-subtitle-time-stop "00:01:01.000")
+         (subed-jump-to-subtitle-time-stop "00:01:01.000")
          (expect (thing-at-point 'word) :to-equal "00")
-         (expect (subed-vtt--backward-subtitle-id) :to-be nil)
+         (expect (subed-backward-subtitle-id) :to-be nil)
          (expect (thing-at-point 'word) :to-equal "00")))
       )
     (describe "to next subtitle text"
       (it "returns point when there is a next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-text) :to-be 75)
+         (expect (subed-forward-subtitle-text) :to-be 75)
          (expect (thing-at-point 'word) :to-equal "Bar")))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-vtt-buffer
          (goto-char (point-max))
          (insert (concat mock-vtt-data "\n\n"))
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-text) :to-be nil)
+         (expect (subed-forward-subtitle-text) :to-be nil)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
       )
     (describe "to previous subtitle text"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-text) :to-be 75)
+         (expect (subed-backward-subtitle-text) :to-be 75)
          (expect (thing-at-point 'word) :to-equal "Bar")))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (subed-vtt--forward-subtitle-time-start)
+         (subed-forward-subtitle-time-start)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-text) :to-be nil)
+         (expect (subed-backward-subtitle-text) :to-be nil)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       )
     (describe "to next subtitle end"
       (it "returns point when there is a next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+         (subed-jump-to-subtitle-text "00:02:02.234")
          (expect (thing-at-point 'word) :to-equal "Bar")
-         (expect (subed-vtt--forward-subtitle-end) :to-be 112)
+         (expect (subed-forward-subtitle-end) :to-be 112)
          (expect (thing-at-point 'word) :to-equal nil)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-vtt-buffer
          (insert (concat mock-vtt-data "\n\n"))
-         (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+         (subed-jump-to-subtitle-text "00:03:03.45")
          (end-of-line)
          (expect (thing-at-point 'word) :to-equal nil)
-         (expect (subed-vtt--forward-subtitle-end) :to-be nil)
+         (expect (subed-forward-subtitle-end) :to-be nil)
          (expect (thing-at-point 'word) :to-equal nil)))
       )
     (describe "to previous subtitle end"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-text) :to-be 75)
+         (expect (subed-backward-subtitle-text) :to-be 75)
          (expect (thing-at-point 'word) :to-equal "Bar")))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
          (goto-char (point-min))
-         (subed-vtt--forward-subtitle-id)
+         (subed-forward-subtitle-id)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-text) :to-be nil)
+         (expect (subed-backward-subtitle-text) :to-be nil)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       )
     (describe "to next subtitle start time"
       (it "returns point when there is a next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (expect (thing-at-point 'word) :to-equal "Foo")
-         (expect (subed-vtt--forward-subtitle-time-start) :to-be 45)
+         (expect (subed-forward-subtitle-time-start) :to-be 45)
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-time-start) :to-be nil)
+         (expect (subed-forward-subtitle-time-start) :to-be nil)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
       )
     (describe "to previous subtitle start time"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:02:02.234")
+         (subed-jump-to-subtitle-id "00:02:02.234")
          (expect (looking-at (regexp-quote "00:02:02.234")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-time-start) :to-be 9)
+         (expect (subed-backward-subtitle-time-start) :to-be 9)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-time-start) :to-be nil)
+         (expect (subed-backward-subtitle-time-start) :to-be nil)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       )
     (describe "to next subtitle stop time"
       (it "returns point when there is a next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+         (subed-jump-to-subtitle-text "00:01:01.000")
          (expect (thing-at-point 'word) :to-equal "Foo")
-         (expect (subed-vtt--forward-subtitle-time-stop) :to-be 62)
+         (expect (subed-forward-subtitle-time-stop) :to-be 62)
          (expect (looking-at (regexp-quote "00:02:10.345")) :to-be t)))
       (it "returns nil and doesn't move when there is no next subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--forward-subtitle-time-stop) :to-be nil)
+         (expect (subed-forward-subtitle-time-stop) :to-be nil)
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)))
       )
     (describe "to previous subtitle stop time"
       (it "returns point when there is a previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:03:03.45")
+         (subed-jump-to-subtitle-id "00:03:03.45")
          (expect (looking-at (regexp-quote "00:03:03.45")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-time-stop) :to-be 62)
+         (expect (subed-backward-subtitle-time-stop) :to-be 62)
          (expect (looking-at (regexp-quote "00:02:10.345")) :to-be t)))
       (it "returns nil and doesn't move when there is no previous subtitle."
         (with-temp-vtt-buffer
          (insert mock-vtt-data)
-         (subed-vtt--jump-to-subtitle-id "00:01:01.000")
+         (subed-jump-to-subtitle-id "00:01:01.000")
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)
-         (expect (subed-vtt--backward-subtitle-time-stop) :to-be nil)
+         (expect (subed-backward-subtitle-time-stop) :to-be nil)
          (expect (looking-at (regexp-quote "00:01:01.000")) :to-be t)))
       )
     )
@@ -532,8 +578,8 @@ Baz.
     (it "of current subtitle."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-end "00:02:02.234")
-       (subed-vtt--set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) 
(* 3 1000) 400))
+       (subed-jump-to-subtitle-end "00:02:02.234")
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 400))
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -541,7 +587,7 @@ Baz.
                                                  "Bar.\n\n"
                                                  "00:03:03.45 --> 00:03:15.5\n"
                                                  "Baz.\n"))
-       (subed-vtt--set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 
7 1000) 800))
+       (subed-set-subtitle-time-stop (+ (* 5 60 60 1000) (* 6 60 1000) (* 7 
1000) 800))
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -552,8 +598,8 @@ Baz.
     (it "of specific subtitle."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-time-stop "00:01:01.000")
-       (subed-vtt--set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) 
(* 6 1000) 800) 1)
+       (subed-jump-to-subtitle-time-stop "00:01:01.000")
+       (subed-set-subtitle-time-start (+ (* 2 60 60 1000) (* 4 60 1000) (* 6 
1000) 800) 1)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "02:04:06.800 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -561,8 +607,8 @@ Baz.
                                                  "Bar.\n\n"
                                                  "00:03:03.45 --> 00:03:15.5\n"
                                                  "Baz.\n"))
-       (subed-vtt--jump-to-subtitle-text "00:03:03.45")
-       (subed-vtt--set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 
7 1000) 900) 3)
+       (subed-jump-to-subtitle-text "00:03:03.45")
+       (subed-set-subtitle-time-stop (+ (* 3 60 60 1000) (* 5 60 1000) (* 7 
1000) 900) 3)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "02:04:06.800 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -574,10 +620,10 @@ Baz.
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
        (subed-jump-to-subtitle-id "00:03:03.45")
-       (subed-vtt--set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) 
(* 3 1000) 4) 3)
+       (subed-set-subtitle-time-start (+ (* 1 60 60 1000) (* 2 60 1000) (* 3 
1000) 4) 3)
        (expect (save-excursion (subed-jump-to-subtitle-time-start)
                                (thing-at-point 'line)) :to-equal "01:02:03.004 
--> 00:03:15.5\n")
-       (subed-vtt--set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 
4 1000) 60) 3)
+       (subed-set-subtitle-time-stop (+ (* 2 60 60 1000) (* 3 60 1000) (* 4 
1000) 60) 3)
        (expect (save-excursion (subed-jump-to-subtitle-time-start)
                                (thing-at-point 'line)) :to-equal "01:02:03.004 
--> 02:03:04.060\n")))
     )
@@ -587,22 +633,22 @@ Baz.
       (describe "before"
         (it "passing nothing."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--prepend-subtitle) :to-equal 31)
+           (expect (subed-prepend-subtitle) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:00:00.000 --> 
00:00:01.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--prepend-subtitle nil 60000) :to-equal 31)
+           (expect (subed-prepend-subtitle nil 60000) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:01.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time and stop time."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--prepend-subtitle nil 60000 65000) :to-equal 31)
+           (expect (subed-prepend-subtitle nil 60000 65000) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:05.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time, stop time and text."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--prepend-subtitle nil 60000 65000 "Foo. 
bar\nbaz.") :to-equal 31)
+           (expect (subed-prepend-subtitle nil 60000 65000 "Foo. bar\nbaz.") 
:to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:05.000\n"
                                                      "Foo. bar\nbaz.\n"))
            (expect (point) :to-equal 31)))
@@ -610,22 +656,22 @@ Baz.
       (describe "after"
         (it "passing nothing."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--append-subtitle) :to-equal 31)
+           (expect (subed-append-subtitle) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:00:00.000 --> 
00:00:01.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--append-subtitle nil 60000) :to-equal 31)
+           (expect (subed-append-subtitle nil 60000) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:01.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time and stop time."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--append-subtitle nil 60000 65000) :to-equal 31)
+           (expect (subed-append-subtitle nil 60000 65000) :to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:05.000\n\n"))
            (expect (point) :to-equal 31)))
         (it "passing start time, stop time and text."
           (with-temp-vtt-buffer
-           (expect (subed-vtt--append-subtitle nil 60000 65000 "Foo, 
bar\nbaz.") :to-equal 31)
+           (expect (subed-append-subtitle nil 60000 65000 "Foo, bar\nbaz.") 
:to-equal 31)
            (expect (buffer-string) :to-equal (concat "00:01:00.000 --> 
00:01:05.000\n"
                                                      "Foo, bar\nbaz.\n"))
            (expect (point) :to-equal 31)))
@@ -638,8 +684,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-time-stop)
-             (expect (subed-vtt--prepend-subtitle) :to-equal 31)
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle) :to-equal 31)
              (expect (buffer-string) :to-equal (concat "00:00:00.000 --> 
00:00:01.000\n"
                                                        "\n\n"
                                                        "00:00:05.000 --> 
00:00:06.000\n"
@@ -649,8 +695,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-time-stop)
-             (expect (subed-vtt--prepend-subtitle nil 1500) :to-equal 31)
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle nil 1500) :to-equal 31)
              (expect (buffer-string) :to-equal (concat "00:00:01.500 --> 
00:00:02.500\n"
                                                        "\n\n"
                                                        "00:00:05.000 --> 
00:00:06.000\n"
@@ -660,8 +706,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-time-stop)
-             (expect (subed-vtt--prepend-subtitle nil 1500 2000) :to-equal 31)
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle nil 1500 2000) :to-equal 31)
              (expect (buffer-string) :to-equal (concat "00:00:01.500 --> 
00:00:02.000\n"
                                                        "\n\n"
                                                        "00:00:05.000 --> 
00:00:06.000\n"
@@ -671,8 +717,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-time-stop)
-             (expect (subed-vtt--prepend-subtitle nil 1500 3000 "Bar.") 
:to-equal 31)
+             (subed-jump-to-subtitle-time-stop)
+             (expect (subed-prepend-subtitle nil 1500 3000 "Bar.") :to-equal 
31)
              (expect (buffer-string) :to-equal (concat "00:00:01.500 --> 
00:00:03.000\n"
                                                        "Bar.\n\n"
                                                        "00:00:05.000 --> 
00:00:06.000\n"
@@ -686,8 +732,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:10.000 --> 00:00:12.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-text "00:00:10.000")
-             (expect (subed-vtt--prepend-subtitle) :to-equal 67)
+             (subed-jump-to-subtitle-text "00:00:10.000")
+             (expect (subed-prepend-subtitle) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:00.000 --> 
00:00:01.000\n"
@@ -701,8 +747,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:10.000 --> 00:00:12.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-text "00:00:10.000")
-             (expect (subed-vtt--prepend-subtitle nil 7000) :to-equal 67)
+             (subed-jump-to-subtitle-text "00:00:10.000")
+             (expect (subed-prepend-subtitle nil 7000) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:07.000 --> 
00:00:08.000\n"
@@ -716,8 +762,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:10.000 --> 00:00:12.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-text "00:00:10.000")
-             (expect (subed-vtt--prepend-subtitle nil 7000 7123) :to-equal 67)
+             (subed-jump-to-subtitle-text "00:00:10.000")
+             (expect (subed-prepend-subtitle nil 7000 7123) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:07.000 --> 
00:00:07.123\n"
@@ -731,8 +777,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:10.000 --> 00:00:12.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-text "00:00:10.000")
-             (expect (subed-vtt--prepend-subtitle nil 7000 7123 "Baz.") 
:to-equal 67)
+             (subed-jump-to-subtitle-text "00:00:10.000")
+             (expect (subed-prepend-subtitle nil 7000 7123 "Baz.") :to-equal 
67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:07.000 --> 
00:00:07.123\n"
@@ -748,8 +794,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-text)
-             (expect (subed-vtt--append-subtitle) :to-equal 67)
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:00.000 --> 
00:00:01.000\n"
@@ -759,8 +805,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-text)
-             (expect (subed-vtt--append-subtitle nil 12345) :to-equal 67)
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle nil 12345) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:12.345 --> 
00:00:13.345\n"
@@ -770,8 +816,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-text)
-             (expect (subed-vtt--append-subtitle nil 12345 15000) :to-equal 67)
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle nil 12345 15000) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:12.345 --> 
00:00:15.000\n"
@@ -781,8 +827,8 @@ Baz.
             (with-temp-vtt-buffer
              (insert (concat "00:00:05.000 --> 00:00:06.000\n"
                              "Foo.\n"))
-             (subed-vtt--jump-to-subtitle-text)
-             (expect (subed-vtt--append-subtitle nil 12345 15000 "Bar.") 
:to-equal 67)
+             (subed-jump-to-subtitle-text)
+             (expect (subed-append-subtitle nil 12345 15000 "Bar.") :to-equal 
67)
              (expect (buffer-string) :to-equal (concat "00:00:05.000 --> 
00:00:06.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:12.345 --> 
00:00:15.000\n"
@@ -796,8 +842,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:05.000 --> 00:00:06.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-time-start "00:00:01.000")
-             (expect (subed-vtt--append-subtitle) :to-equal 67)
+             (subed-jump-to-subtitle-time-start "00:00:01.000")
+             (expect (subed-append-subtitle) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:00.000 --> 
00:00:01.000\n"
@@ -811,8 +857,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:05.000 --> 00:00:06.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-time-start "00:00:01.000")
-             (expect (subed-vtt--append-subtitle nil 2500) :to-equal 67)
+             (subed-jump-to-subtitle-time-start "00:00:01.000")
+             (expect (subed-append-subtitle nil 2500) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:02.500 --> 
00:00:03.500\n"
@@ -826,8 +872,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:05.000 --> 00:00:06.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-time-start "00:00:01.000")
-             (expect (subed-vtt--append-subtitle nil 2500 4000) :to-equal 67)
+             (subed-jump-to-subtitle-time-start "00:00:01.000")
+             (expect (subed-append-subtitle nil 2500 4000) :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:02.500 --> 
00:00:04.000\n"
@@ -841,8 +887,8 @@ Baz.
                              "Foo.\n\n"
                              "00:00:05.000 --> 00:00:06.000\n"
                              "Bar.\n"))
-             (subed-vtt--jump-to-subtitle-time-start "00:00:01.000")
-             (expect (subed-vtt--append-subtitle nil 2500 4000 "Baz.") 
:to-equal 67)
+             (subed-jump-to-subtitle-time-start "00:00:01.000")
+             (expect (subed-append-subtitle nil 2500 4000 "Baz.") :to-equal 67)
              (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
                                                        "Foo.\n\n"
                                                        "00:00:02.500 --> 
00:00:04.000\n"
@@ -857,7 +903,7 @@ Baz.
          (insert (concat "00:00:01.000 --> 00:00:02.000\n"
                          "\n"))
          (subed-jump-to-subtitle-text)
-         (expect (subed-vtt--append-subtitle) :to-equal 63)
+         (expect (subed-append-subtitle) :to-equal 63)
          (expect (buffer-string) :to-equal (concat "00:00:01.000 --> 
00:00:02.000\n"
                                                    "\n\n"
                                                    "00:00:00.000 --> 
00:00:01.000\n"
@@ -870,8 +916,8 @@ Baz.
     (it "removes the first subtitle."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:01:01.000")
-       (subed-vtt--kill-subtitle)
+       (subed-jump-to-subtitle-text "00:01:01.000")
+       (subed-kill-subtitle)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:02:02.234 --> 
00:02:10.345\n"
                                                  "Bar.\n\n"
@@ -880,8 +926,8 @@ Baz.
     (it "removes it in between."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:02:02.234")
-       (subed-vtt--kill-subtitle)
+       (subed-jump-to-subtitle-text "00:02:02.234")
+       (subed-kill-subtitle)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -890,8 +936,8 @@ Baz.
     (it "removes the last subtitle."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:03:03.45")
-       (subed-vtt--kill-subtitle)
+       (subed-jump-to-subtitle-text "00:03:03.45")
+       (subed-kill-subtitle)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -904,7 +950,7 @@ Baz.
          (subed-jump-to-subtitle-id "00:03:03.45")
          (backward-char)
          (expect (looking-at "^\n00:03:03.45") :to-be t)
-         (subed-vtt--kill-subtitle)
+         (subed-kill-subtitle)
          (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                    "00:01:01.000 --> 
00:01:05.123\n"
                                                    "Foo.\n\n"
@@ -916,7 +962,7 @@ Baz.
          (subed-jump-to-subtitle-id "00:02:02.234")
          (backward-char)
          (expect (looking-at "^\n00:02:02.234") :to-be t)
-         (subed-vtt--kill-subtitle)
+         (subed-kill-subtitle)
          (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                    "00:02:02.234 --> 
00:02:10.345\n"
                                                    "Bar.\n\n"
@@ -928,37 +974,37 @@ Baz.
   (describe "Validating"
     (it "works in empty buffer."
       (with-temp-vtt-buffer
-       (subed-vtt--validate)))
+       (subed-validate)))
     (it "works in buffer that contains only newlines."
       (with-temp-vtt-buffer
        (cl-loop for _ from 1 to 10 do
                 (insert "\n")
-                (subed-vtt--validate))))
+                (subed-validate))))
     (it "works in buffer that contains only spaces."
       (with-temp-vtt-buffer
        (cl-loop for _ from 1 to 10 do
                 (insert " ")
-                (subed-vtt--validate))))
+                (subed-validate))))
     (it "works in buffer that contains only spaces and newlines."
       (with-temp-vtt-buffer
        (cl-loop for _ from 1 to 10 do
                 (if (eq (random 2) 0)
                     (insert " ")
                   (insert "\n"))
-                (subed-vtt--validate))))
+                (subed-validate))))
     (it "reports invalid stop time."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-time-stop "00:01:01.000")
+       (subed-jump-to-subtitle-time-stop "00:01:01.000")
        (forward-char 10)
        (insert "3")
-       (expect (subed-vtt--validate) :to-throw
+       (expect (subed-validate) :to-throw
                'error '("Found invalid stop time: \"00:01:01.000 --> 
00:01:05.1323\""))
        (expect (point) :to-equal 26)))
     (it "runs before saving."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-time-stop "00:01:01.000")
+       (subed-jump-to-subtitle-time-stop "00:01:01.000")
        (forward-char 10)
        (insert "3")
        (expect (subed-prepare-to-save) :to-throw
@@ -967,25 +1013,25 @@ Baz.
     (it "reports invalid time separator."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-time-stop "00:01:01.000")
+       (subed-jump-to-subtitle-time-stop "00:01:01.000")
        (delete-char -1)
-       (expect (subed-vtt--validate) :to-throw
+       (expect (subed-validate) :to-throw
                'error '("Found invalid separator between start and stop time: 
\"00:01:01.000 -->00:01:05.123\""))
        (expect (point) :to-equal 21)))
     (it "does not report error when last subtitle text is empty."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+       (subed-jump-to-subtitle-text "00:03:03.45")
        (kill-whole-line)
        (forward-char -2)
-       (subed-vtt--validate)
+       (subed-validate)
        (expect (point) :to-equal 106)))
     (it "preserves point if there is no error."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:02:02.234")
+       (subed-jump-to-subtitle-text "00:02:02.234")
        (forward-char 2)
-       (subed-vtt--validate)
+       (subed-validate)
        (expect (point) :to-equal 77)))
     )
 
@@ -997,7 +1043,7 @@ Baz.
        (while (re-search-forward "\n" nil t)
          (replace-match " \n"))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data))
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
@@ -1005,7 +1051,7 @@ Baz.
        (while (re-search-forward "\n" nil t)
          (replace-match "\t\n"))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "removes leading tabs and spaces from all lines."
       (with-temp-vtt-buffer
@@ -1014,7 +1060,7 @@ Baz.
        (while (re-search-forward "\n" nil t)
          (replace-match "\n "))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data))
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
@@ -1022,7 +1068,7 @@ Baz.
        (while (re-search-forward "\n" nil t)
          (replace-match "\n\t"))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "removes excessive empty lines between subtitles."
       (with-temp-vtt-buffer
@@ -1032,12 +1078,12 @@ Baz.
        (while (re-search-forward "\n\n" nil t)
          (replace-match "\n \n  \t  \t\t  \n\n  \t\n"))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "ensures double newline between subtitles if text of previous subtitle 
is empty."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:01:01.000")
+       (subed-jump-to-subtitle-text "00:01:01.000")
        (kill-whole-line)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
@@ -1046,7 +1092,7 @@ Baz.
                                                  "Bar.\n\n"
                                                  "00:03:03.45 --> 00:03:15.5\n"
                                                  "Baz.\n"))
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "\n\n"
@@ -1060,7 +1106,7 @@ Baz.
        (goto-char (point-max))
        (insert " \n\t\n\n")
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "ensures a single newline after the last subtitle."
       (with-temp-vtt-buffer
@@ -1069,12 +1115,12 @@ Baz.
        (while (eq (char-before (point-max)) ?\n)
          (delete-backward-char 1))
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "ensures single newline after last subtitle if text is empty."
       (with-temp-vtt-buffer
        (insert mock-vtt-data)
-       (subed-vtt--jump-to-subtitle-text "00:03:03.45")
+       (subed-jump-to-subtitle-text "00:03:03.45")
        (kill-whole-line)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
@@ -1083,7 +1129,7 @@ Baz.
                                                  "Bar.\n\n"
                                                  "00:03:03.45 --> 00:03:15.5\n"
                                                  ""))
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal (concat "WEBVTT\n\n"
                                                  "00:01:01.000 --> 
00:01:05.123\n"
                                                  "Foo.\n\n"
@@ -1102,7 +1148,7 @@ Baz.
        (re-search-forward " --> ")
        (replace-match "-->")
        (expect (buffer-string) :not :to-equal mock-vtt-data)
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal mock-vtt-data)))
     (it "runs before saving."
       (with-temp-vtt-buffer
@@ -1120,7 +1166,7 @@ Baz.
     (it "does not insert newline in empty buffer."
       (with-temp-vtt-buffer
        (expect (buffer-string) :to-equal "")
-       (subed-vtt--sanitize)
+       (subed-sanitize)
        (expect (buffer-string) :to-equal "")))
     )
 
@@ -1138,7 +1184,7 @@ Baz.
        (goto-char (point-min))
        (re-search-forward "03:03")
        (replace-match "11:03")
-       (subed-vtt--sort)
+       (subed-sort)
        (expect (buffer-string) :to-equal
                (concat
                 "WEBVTT\n"
@@ -1185,13 +1231,13 @@ Baz.
          (replace-match "12:01")
          (search-forward "\n")
          (expect (current-word) :to-equal "Foo")
-         (subed-vtt--sort)
+         (subed-sort)
          (expect (current-word) :to-equal "Foo")))
       (it "when subtitle text is empty."
         (with-temp-vtt-buffer
          (insert "WEBVTT\n\n00:12:01.000 --> 00:01:05.123\n")
          (goto-char (point-max))
-         (subed-vtt--sort)
+         (subed-sort)
          (expect (point) :to-equal (1- (point-max)))))
       )
     )
@@ -1217,4 +1263,22 @@ This is another test here.
        (subed-forward-subtitle-end)
        (expect (current-word) :to-equal "test")
        (subed-forward-subtitle-end)
-       (expect (current-word) :to-equal "here")))))
+       (expect (current-word) :to-equal "here"))))
+
+  (describe "Merging with next subtitle"
+    (it "throws an error in an empty buffer."
+      (with-temp-vtt-buffer
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "throws an error with the last subtitle."
+      (with-temp-vtt-buffer
+       (insert mock-vtt-data)
+       (subed-jump-to-subtitle-text 3)
+       (expect (subed-merge-with-next) :to-throw 'error)))
+    (it "combines the text and the time."
+      (with-temp-vtt-buffer
+       (insert mock-vtt-data)
+       (subed-jump-to-subtitle-text "00:02:02.234")
+       (subed-merge-with-next)
+       (expect (subed-subtitle-text) :to-equal "Bar.\nBaz.")
+       (expect (subed-subtitle-msecs-start) :to-equal 122234)
+       (expect (subed-subtitle-msecs-stop) :to-equal 195500)))))
diff --git a/tests/undercover-init.el b/tests/undercover-init.el
new file mode 100644
index 0000000000..0ffc2aed1a
--- /dev/null
+++ b/tests/undercover-init.el
@@ -0,0 +1,4 @@
+(add-to-list 'load-path (expand-file-name "./subed"))
+(when (require 'undercover nil t)
+  (undercover "./subed/*.el" (:report-format 'simplecov) (:send-report nil)))
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]