aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/doc-view.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/doc-view.el')
-rw-r--r--lisp/doc-view.el225
1 files changed, 172 insertions, 53 deletions
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 24434d294c6..0658a11c30a 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -145,7 +145,7 @@
145;;;; Customization Options 145;;;; Customization Options
146 146
147(defgroup doc-view nil 147(defgroup doc-view nil
148 "In-buffer viewer for PDF, PostScript and DVI files." 148 "In-buffer viewer for PDF, PostScript, DVI, and DJVU files."
149 :link '(function-link doc-view) 149 :link '(function-link doc-view)
150 :version "22.2" 150 :version "22.2"
151 :group 'applications 151 :group 'applications
@@ -158,6 +158,39 @@
158 :type 'file 158 :type 'file
159 :group 'doc-view) 159 :group 'doc-view)
160 160
161(defcustom doc-view-pdfdraw-program "mudraw"
162 "Program to convert PDF files to PNG."
163 :type 'file
164 :version "24.4")
165
166(defcustom doc-view-pdf->png-converter-function
167 'doc-view-pdf->png-converter-ghostscript
168 "Function to call to convert a PDF file into a PNG file."
169 :type '(radio
170 (function-item doc-view-pdf->png-converter-ghostscript
171 :doc "Use ghostscript")
172 (function-item doc-view-pdf->png-converter-mupdf
173 :doc "Use mupdf")
174 function)
175 :version "24.4")
176
177;; FIXME: Get rid of it: there's no choice.
178(defcustom doc-view-djvu->png-converter-function
179 'doc-view-djvu->png-converter-ddjvu
180 "Function to call to convert a DJVU file into a PNG file"
181 :type '(radio (function-item doc-view-djvu->png-converter-ddjvu
182 :doc "Use ddjvu")
183 function))
184
185;; FIXME: Get rid of it: there's no choice.
186(defcustom doc-view-ps->png-converter-function
187 'doc-view-ps->png-converter-ghostscript
188 "Function to call to convert a PS file into a PNG file."
189 :type '(radio (function-item doc-view-ps->png-converter-ghostscript
190 :doc "Use ghostscript")
191 function)
192 :version "24.4")
193
161(defcustom doc-view-ghostscript-options 194(defcustom doc-view-ghostscript-options
162 '("-dSAFER" ;; Avoid security problems when rendering files from untrusted 195 '("-dSAFER" ;; Avoid security problems when rendering files from untrusted
163 ;; sources. 196 ;; sources.
@@ -320,6 +353,20 @@ the (uncompressed, extracted) file residing in
320 "The type of document in the current buffer. 353 "The type of document in the current buffer.
321Can be `dvi', `pdf', or `ps'.") 354Can be `dvi', `pdf', or `ps'.")
322 355
356(defvar doc-view-single-page-converter-function nil
357 "Function to call to convert a single page of the document to a bitmap file.
358May operate on the source document or on some intermediate (typically PDF)
359conversion of it.")
360
361(defvar doc-view--image-type nil
362 "The type of image in the current buffer.
363Can be `png' or `tiff'.")
364
365(defvar doc-view--image-file-extension nil
366 ;; FIXME: Replace it with a `format' string, like "page-%d.png".
367 "The file extension of the image type in the current buffer.
368Can be `png' or `tif'.")
369
323;;;; DocView Keymaps 370;;;; DocView Keymaps
324 371
325(defvar doc-view-mode-map 372(defvar doc-view-mode-map
@@ -458,24 +505,26 @@ Can be `dvi', `pdf', or `ps'.")
458 ;; We used to find the file name from doc-view-current-files but 505 ;; We used to find the file name from doc-view-current-files but
459 ;; that's not right if the pages are not generated sequentially 506 ;; that's not right if the pages are not generated sequentially
460 ;; or if the page isn't in doc-view-current-files yet. 507 ;; or if the page isn't in doc-view-current-files yet.
461 (let ((file (expand-file-name (format "page-%d.png" page) 508 (let ((file (expand-file-name
462 (doc-view-current-cache-dir)))) 509 (format "page-%d.%s" page doc-view--image-file-extension)
510 (doc-view-current-cache-dir))))
463 (doc-view-insert-image file :pointer 'arrow) 511 (doc-view-insert-image file :pointer 'arrow)
464 (set-window-hscroll (selected-window) hscroll) 512 (set-window-hscroll (selected-window) hscroll)
465 (when (and (not (file-exists-p file)) 513 (when (and (not (file-exists-p file))
466 doc-view-current-converter-processes) 514 doc-view-current-converter-processes)
467 ;; The PNG file hasn't been generated yet. 515 ;; The PNG file hasn't been generated yet.
468 (doc-view-pdf->png-1 doc-view-buffer-file-name file page 516 (funcall doc-view-single-page-converter-function
469 (let ((win (selected-window))) 517 doc-view-buffer-file-name file page
470 (lambda () 518 (let ((win (selected-window)))
471 (and (eq (current-buffer) (window-buffer win)) 519 (lambda ()
472 ;; If we changed page in the mean 520 (and (eq (current-buffer) (window-buffer win))
473 ;; time, don't mess things up. 521 ;; If we changed page in the mean
474 (eq (doc-view-current-page win) page) 522 ;; time, don't mess things up.
475 ;; Make sure we don't infloop. 523 (eq (doc-view-current-page win) page)
476 (file-readable-p file) 524 ;; Make sure we don't infloop.
477 (with-selected-window win 525 (file-readable-p file)
478 (doc-view-goto-page page)))))))) 526 (with-selected-window win
527 (doc-view-goto-page page))))))))
479 (overlay-put (doc-view-current-overlay) 528 (overlay-put (doc-view-current-overlay)
480 'help-echo (doc-view-current-info)))) 529 'help-echo (doc-view-current-info))))
481 530
@@ -661,12 +710,15 @@ OpenDocument format)."
661 (executable-find doc-view-dvipdfm-program))))) 710 (executable-find doc-view-dvipdfm-program)))))
662 ((or (eq type 'postscript) (eq type 'ps) (eq type 'eps) 711 ((or (eq type 'postscript) (eq type 'ps) (eq type 'eps)
663 (eq type 'pdf)) 712 (eq type 'pdf))
713 ;; FIXME: allow mupdf here
664 (and doc-view-ghostscript-program 714 (and doc-view-ghostscript-program
665 (executable-find doc-view-ghostscript-program))) 715 (executable-find doc-view-ghostscript-program)))
666 ((eq type 'odf) 716 ((eq type 'odf)
667 (and doc-view-unoconv-program 717 (and doc-view-unoconv-program
668 (executable-find doc-view-unoconv-program) 718 (executable-find doc-view-unoconv-program)
669 (doc-view-mode-p 'pdf))) 719 (doc-view-mode-p 'pdf)))
720 ((eq type 'djvu)
721 (executable-find "ddjvu"))
670 (t ;; unknown image type 722 (t ;; unknown image type
671 nil)))) 723 nil))))
672 724
@@ -826,6 +878,36 @@ Should be invoked when the cached images aren't up-to-date."
826 (list "-o" pdf dvi) 878 (list "-o" pdf dvi)
827 callback))) 879 callback)))
828 880
881(defun doc-view-pdf->png-converter-ghostscript (resolution pdf png &optional page)
882 `((command . ,doc-view-ghostscript-program)
883 (arguments . (,@doc-view-ghostscript-options
884 ,(format "-r%d" resolution)
885 ,@(if page `(,(format "-dFirstPage=%d" page)))
886 ,@(if page `(,(format "-dLastPage=%d" page)))
887 ,(concat "-sOutputFile=" png)
888 ,pdf))))
889
890(defalias 'doc-view-ps->png-converter-ghostscript
891 'doc-view-pdf->png-converter-ghostscript)
892
893(defun doc-view-djvu->png-converter-ddjvu (resolution djvu png &optional page)
894 `((command . "ddjvu")
895 (arguments . ("-format=tiff"
896 ;; ddjvu only accepts the range 1-999.
897 ,(format "-scale=%d" resolution)
898 ;; -eachpage was only added after djvulibre-3.5.25.3!
899 ,@(unless page '("-eachpage"))
900 ,@(if page `(,(format "-page=%d" page)))
901 ,djvu
902 ,png))))
903
904(defun doc-view-pdf->png-converter-mupdf (resolution pdf png &optional page)
905 `((command . ,doc-view-pdfdraw-program)
906 (arguments . (,(concat "-o" png)
907 ,(format "-r%d" resolution)
908 ,pdf
909 ,@(if page `(,(format "%d" page)))))))
910
829(defun doc-view-odf->pdf (odf callback) 911(defun doc-view-odf->pdf (odf callback)
830 "Convert ODF to PDF asynchronously and call CALLBACK when finished. 912 "Convert ODF to PDF asynchronously and call CALLBACK when finished.
831The converted PDF is put into the current cache directory, and it 913The converted PDF is put into the current cache directory, and it
@@ -835,13 +917,18 @@ is named like ODF with the extension turned to pdf."
835 callback)) 917 callback))
836 918
837(defun doc-view-pdf/ps->png (pdf-ps png) 919(defun doc-view-pdf/ps->png (pdf-ps png)
920 ;; FIXME: Fix name and docstring to account for djvu&tiff.
838 "Convert PDF-PS to PNG asynchronously." 921 "Convert PDF-PS to PNG asynchronously."
839 (doc-view-start-process 922 (let ((invocation
840 "pdf/ps->png" doc-view-ghostscript-program 923 (funcall (pcase doc-view-doc-type
841 (append doc-view-ghostscript-options 924 (`pdf doc-view-pdf->png-converter-function)
842 (list (format "-r%d" (round doc-view-resolution)) 925 (`djvu doc-view-djvu->png-converter-function)
843 (concat "-sOutputFile=" png) 926 (_ doc-view-ps->png-converter-function))
844 pdf-ps)) 927 (round doc-view-resolution) pdf-ps png)))
928
929 (doc-view-start-process
930 "pdf/ps->png" (cdr (assoc 'command invocation))
931 (cdr (assoc 'arguments invocation))
845 (let ((resolution doc-view-resolution)) 932 (let ((resolution doc-view-resolution))
846 (lambda () 933 (lambda ()
847 ;; Only create the resolution file when it's all done, so it also 934 ;; Only create the resolution file when it's all done, so it also
@@ -853,7 +940,7 @@ is named like ODF with the extension turned to pdf."
853 (when doc-view-current-timer 940 (when doc-view-current-timer
854 (cancel-timer doc-view-current-timer) 941 (cancel-timer doc-view-current-timer)
855 (setq doc-view-current-timer nil)) 942 (setq doc-view-current-timer nil))
856 (doc-view-display (current-buffer) 'force)))) 943 (doc-view-display (current-buffer) 'force)))))
857 ;; Update the displayed pages as soon as they're done generating. 944 ;; Update the displayed pages as soon as they're done generating.
858 (when doc-view-conversion-refresh-interval 945 (when doc-view-conversion-refresh-interval
859 (setq doc-view-current-timer 946 (setq doc-view-current-timer
@@ -864,21 +951,27 @@ is named like ODF with the extension turned to pdf."
864(defun doc-view-pdf->png-1 (pdf png page callback) 951(defun doc-view-pdf->png-1 (pdf png page callback)
865 "Convert a PAGE of a PDF file to PNG asynchronously. 952 "Convert a PAGE of a PDF file to PNG asynchronously.
866Call CALLBACK with no arguments when done." 953Call CALLBACK with no arguments when done."
867 (doc-view-start-process 954 (let ((invocation (funcall doc-view-pdf->png-converter-function
868 "pdf->png-1" doc-view-ghostscript-program 955 (round doc-view-resolution) pdf png page)))
869 (append doc-view-ghostscript-options 956 (doc-view-start-process
870 (list (format "-r%d" (round doc-view-resolution)) 957 "pdf/ps->png" (cdr (assoc 'command invocation))
871 ;; Sadly, `gs' only supports the page-range 958 (cdr (assoc 'arguments invocation))
872 ;; for PDF files. 959 callback)))
873 (format "-dFirstPage=%d" page) 960
874 (format "-dLastPage=%d" page) 961(defun doc-view-djvu->png-1 (djvu png page callback)
875 (concat "-sOutputFile=" png) 962 "Convert a PAGE of a DJVU file to bitmap asynchronously.
876 pdf)) 963Call CALLBACK with no arguments when done."
877 callback)) 964 (let ((invocation (funcall doc-view-djvu->png-converter-function
965 (round doc-view-resolution) djvu png page)))
966 (doc-view-start-process
967 "djvu->png" (cdr (assoc 'command invocation))
968 (cdr (assoc 'arguments invocation))
969 callback)))
878 970
879(declare-function clear-image-cache "image.c" (&optional filter)) 971(declare-function clear-image-cache "image.c" (&optional filter))
880 972
881(defun doc-view-pdf->png (pdf png pages) 973(defun doc-view-document->png (pdf png pages single-page-converter)
974 ;; FIXME: Fix docstring.
882 "Convert a PDF file to PNG asynchronously. 975 "Convert a PDF file to PNG asynchronously.
883Start by converting PAGES, and then the rest." 976Start by converting PAGES, and then the rest."
884 (if (null pages) 977 (if (null pages)
@@ -888,11 +981,11 @@ Start by converting PAGES, and then the rest."
888 ;; a single page anyway, and of the remaining 1%, few cases will have 981 ;; a single page anyway, and of the remaining 1%, few cases will have
889 ;; consecutive pages, it's not worth the trouble. 982 ;; consecutive pages, it's not worth the trouble.
890 (let ((rest (cdr pages))) 983 (let ((rest (cdr pages)))
891 (doc-view-pdf->png-1 984 (funcall single-page-converter
892 pdf (format png (car pages)) (car pages) 985 pdf (format png (car pages)) (car pages)
893 (lambda () 986 (lambda ()
894 (if rest 987 (if rest
895 (doc-view-pdf->png pdf png rest) 988 (doc-view-document->png pdf png rest)
896 ;; Yippie, the important pages are done, update the display. 989 ;; Yippie, the important pages are done, update the display.
897 (clear-image-cache) 990 (clear-image-cache)
898 ;; For the windows that have a message (like "Welcome to 991 ;; For the windows that have a message (like "Welcome to
@@ -900,8 +993,8 @@ Start by converting PAGES, and then the rest."
900 ;; not sufficient. 993 ;; not sufficient.
901 (dolist (win (get-buffer-window-list (current-buffer) nil 'visible)) 994 (dolist (win (get-buffer-window-list (current-buffer) nil 'visible))
902 (with-selected-window win 995 (with-selected-window win
903 (when (stringp (get-char-property (point-min) 'display)) 996 (when (stringp (get-char-property (point-min) 'display))
904 (doc-view-goto-page (doc-view-current-page))))) 997 (doc-view-goto-page (doc-view-current-page)))))
905 ;; Convert the rest of the pages. 998 ;; Convert the rest of the pages.
906 (doc-view-pdf/ps->png pdf png))))))) 999 (doc-view-pdf/ps->png pdf png)))))))
907 1000
@@ -971,8 +1064,9 @@ Those files are saved in the directory given by the function
971 ;; preserves the horizontal/vertical scroll settings (which are otherwise 1064 ;; preserves the horizontal/vertical scroll settings (which are otherwise
972 ;; resets during the redisplay). 1065 ;; resets during the redisplay).
973 (setq doc-view-pending-cache-flush t) 1066 (setq doc-view-pending-cache-flush t)
974 (let ((png-file (expand-file-name "page-%d.png" 1067 (let ((png-file (expand-file-name
975 (doc-view-current-cache-dir)))) 1068 (concat "page-%d." doc-view--image-file-extension)
1069 (doc-view-current-cache-dir))))
976 (make-directory (doc-view-current-cache-dir) t) 1070 (make-directory (doc-view-current-cache-dir) t)
977 (pcase doc-view-doc-type 1071 (pcase doc-view-doc-type
978 (`dvi 1072 (`dvi
@@ -985,11 +1079,12 @@ Those files are saved in the directory given by the function
985 ;; ODF files have to be converted to PDF before Ghostscript can 1079 ;; ODF files have to be converted to PDF before Ghostscript can
986 ;; process it. 1080 ;; process it.
987 (let ((pdf (doc-view-current-cache-doc-pdf)) 1081 (let ((pdf (doc-view-current-cache-doc-pdf))
988 (opdf (expand-file-name (concat (file-name-base doc-view-buffer-file-name) 1082 (opdf (expand-file-name
989 ".pdf") 1083 (concat (file-name-base doc-view-buffer-file-name)
990 doc-view-current-cache-dir)) 1084 ".pdf")
1085 doc-view-current-cache-dir))
991 (png-file png-file)) 1086 (png-file png-file))
992 ;; The unoconv tool only supports a output directory, but no 1087 ;; The unoconv tool only supports an output directory, but no
993 ;; file name. It's named like the input file with the 1088 ;; file name. It's named like the input file with the
994 ;; extension replaced by pdf. 1089 ;; extension replaced by pdf.
995 (doc-view-odf->pdf doc-view-buffer-file-name 1090 (doc-view-odf->pdf doc-view-buffer-file-name
@@ -1000,7 +1095,12 @@ Those files are saved in the directory given by the function
1000 (`pdf 1095 (`pdf
1001 (let ((pages (doc-view-active-pages))) 1096 (let ((pages (doc-view-active-pages)))
1002 ;; Convert PDF to PNG images starting with the active pages. 1097 ;; Convert PDF to PNG images starting with the active pages.
1003 (doc-view-pdf->png doc-view-buffer-file-name png-file pages))) 1098 (doc-view-document->png doc-view-buffer-file-name png-file pages
1099 'doc-view-pdf->png-1)))
1100 (`djvu
1101 (let ((pages (doc-view-active-pages)))
1102 (doc-view-document->png doc-view-buffer-file-name png-file pages
1103 'doc-view-djvu->png-1)))
1004 (_ 1104 (_
1005 ;; Convert to PNG images. 1105 ;; Convert to PNG images.
1006 (doc-view-pdf/ps->png doc-view-buffer-file-name png-file))))) 1106 (doc-view-pdf/ps->png doc-view-buffer-file-name png-file)))))
@@ -1144,7 +1244,7 @@ ARGS is a list of image descriptors."
1144 (image (if (and file (file-readable-p file)) 1244 (image (if (and file (file-readable-p file))
1145 (if (not (and doc-view-scale-internally 1245 (if (not (and doc-view-scale-internally
1146 (fboundp 'imagemagick-types))) 1246 (fboundp 'imagemagick-types)))
1147 (apply 'create-image file 'png nil args) 1247 (apply 'create-image file doc-view--image-type nil args)
1148 (unless (member :width args) 1248 (unless (member :width args)
1149 (setq args `(,@args :width ,doc-view-image-width))) 1249 (setq args `(,@args :width ,doc-view-image-width)))
1150 (apply 'create-image file 'imagemagick nil args)))) 1250 (apply 'create-image file 'imagemagick nil args))))
@@ -1194,13 +1294,17 @@ have the page we want to view."
1194 (let ((prev-pages doc-view-current-files)) 1294 (let ((prev-pages doc-view-current-files))
1195 (setq doc-view-current-files 1295 (setq doc-view-current-files
1196 (sort (directory-files (doc-view-current-cache-dir) t 1296 (sort (directory-files (doc-view-current-cache-dir) t
1197 "page-[0-9]+\\.png" t) 1297 (concat "page-[0-9]+\\."
1298 doc-view--image-file-extension)
1299 t)
1198 'doc-view-sort)) 1300 'doc-view-sort))
1199 (dolist (win (or (get-buffer-window-list buffer nil t) 1301 (dolist (win (or (get-buffer-window-list buffer nil t)
1200 (list t))) 1302 (list t)))
1201 (let* ((page (doc-view-current-page win)) 1303 (let* ((page (doc-view-current-page win))
1202 (pagefile (expand-file-name (format "page-%d.png" page) 1304 (pagefile (expand-file-name
1203 (doc-view-current-cache-dir)))) 1305 (format "page-%d.%s"
1306 page doc-view--image-file-extension)
1307 (doc-view-current-cache-dir))))
1204 (when (or force 1308 (when (or force
1205 (and (not (member pagefile prev-pages)) 1309 (and (not (member pagefile prev-pages))
1206 (member pagefile doc-view-current-files))) 1310 (member pagefile doc-view-current-files)))
@@ -1393,12 +1497,13 @@ If BACKWARD is non-nil, jump to the previous match."
1393 ;; the conversion is incomplete. 1497 ;; the conversion is incomplete.
1394 (file-readable-p (expand-file-name "resolution.el" 1498 (file-readable-p (expand-file-name "resolution.el"
1395 (doc-view-current-cache-dir))) 1499 (doc-view-current-cache-dir)))
1396 (> (length (directory-files (doc-view-current-cache-dir) 1500 (> (length (directory-files
1397 nil "\\.png\\'")) 1501 (doc-view-current-cache-dir)
1502 nil (concat "\\." doc-view--image-file-extension "\\'")))
1398 0))) 1503 0)))
1399 1504
1400(defun doc-view-initiate-display () 1505(defun doc-view-initiate-display ()
1401 ;; Switch to image display if possible 1506 ;; Switch to image display if possible.
1402 (if (doc-view-mode-p doc-view-doc-type) 1507 (if (doc-view-mode-p doc-view-doc-type)
1403 (progn 1508 (progn
1404 (doc-view-buffer-message) 1509 (doc-view-buffer-message)
@@ -1467,6 +1572,8 @@ If BACKWARD is non-nil, jump to the previous match."
1467 ("pdf" pdf) ("epdf" pdf) 1572 ("pdf" pdf) ("epdf" pdf)
1468 ;; PostScript 1573 ;; PostScript
1469 ("ps" ps) ("eps" ps) 1574 ("ps" ps) ("eps" ps)
1575 ;; DjVu
1576 ("djvu" djvu)
1470 ;; OpenDocument formats 1577 ;; OpenDocument formats
1471 ("odt" odf) ("ods" odf) ("odp" odf) ("odg" odf) 1578 ("odt" odf) ("ods" odf) ("odp" odf) ("odg" odf)
1472 ("odc" odf) ("odi" odf) ("odm" odf) ("ott" odf) 1579 ("odc" odf) ("odi" odf) ("odm" odf) ("ott" odf)
@@ -1481,7 +1588,8 @@ If BACKWARD is non-nil, jump to the previous match."
1481 (cond 1588 (cond
1482 ((looking-at "%!") '(ps)) 1589 ((looking-at "%!") '(ps))
1483 ((looking-at "%PDF") '(pdf)) 1590 ((looking-at "%PDF") '(pdf))
1484 ((looking-at "\367\002") '(dvi)))))) 1591 ((looking-at "\367\002") '(dvi))
1592 ((looking-at "AT&TFORM") '(djvu))))))
1485 (set (make-local-variable 'doc-view-doc-type) 1593 (set (make-local-variable 'doc-view-doc-type)
1486 (car (or (doc-view-intersection name-types content-types) 1594 (car (or (doc-view-intersection name-types content-types)
1487 (when (and name-types content-types) 1595 (when (and name-types content-types)
@@ -1490,6 +1598,16 @@ If BACKWARD is non-nil, jump to the previous match."
1490 name-types content-types 1598 name-types content-types
1491 (error "Cannot determine the document type")))))) 1599 (error "Cannot determine the document type"))))))
1492 1600
1601(defun doc-view-set-up-single-converter ()
1602 "Find the right single-page converter for the current document type"
1603 (pcase-let ((`(,conv-function ,type ,extension)
1604 (pcase doc-view-doc-type
1605 (`djvu (list #'doc-view-djvu->png-1 'tiff "tif"))
1606 (_ (list #'doc-view-pdf->png-1 'png "png")))))
1607 (setq-local doc-view-single-page-converter-function conv-function)
1608 (setq-local doc-view--image-type type)
1609 (setq-local doc-view--image-file-extension extension)))
1610
1493;;;###autoload 1611;;;###autoload
1494(defun doc-view-mode () 1612(defun doc-view-mode ()
1495 "Major mode in DocView buffers. 1613 "Major mode in DocView buffers.
@@ -1522,6 +1640,7 @@ toggle between displaying the document or editing it as text.
1522 ;; Figure out the document type. 1640 ;; Figure out the document type.
1523 (unless doc-view-doc-type 1641 (unless doc-view-doc-type
1524 (doc-view-set-doc-type)) 1642 (doc-view-set-doc-type))
1643 (doc-view-set-up-single-converter)
1525 1644
1526 (doc-view-make-safe-dir doc-view-cache-directory) 1645 (doc-view-make-safe-dir doc-view-cache-directory)
1527 ;; Handle compressed files, remote files, files inside archives 1646 ;; Handle compressed files, remote files, files inside archives