[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/scanner f76603c 03/17: ask for confirmation before over
From: |
Stefan Monnier |
Subject: |
[elpa] externals/scanner f76603c 03/17: ask for confirmation before overwriting existing files |
Date: |
Mon, 14 Dec 2020 18:34:42 -0500 (EST) |
branch: externals/scanner
commit f76603cfc86021cf9b4d2b6f0cd127368ee85fff
Author: Raffael Stocker <r.stocker@mnet-mail.de>
Commit: Raffael Stocker <r.stocker@mnet-mail.de>
ask for confirmation before overwriting existing files
* scanner.el (scanner-scan-image): ask before overwriting files
(scanner-scan-document): ask before overwriting files
---
scanner.el | 380 +++++++++++++++++++++++++++++++------------------------------
1 file changed, 193 insertions(+), 187 deletions(-)
diff --git a/scanner.el b/scanner.el
index 587e5b0..27568eb 100644
--- a/scanner.el
+++ b/scanner.el
@@ -10,8 +10,6 @@
;; Keywords: hardware, multimedia
;; URL: https://gitlab.com/rstocker/scanner.git
-;; This file is NOT part of GNU Emacs
-
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or (at
@@ -107,7 +105,7 @@ the second is the height in mm."
"Document paper size.
The value must be one of the keys in the paper sizes list."
:type '(restricted-sexp :match-alternatives
- ((lambda (k) (plist-member scanner-paper-sizes k)))))
+ ((lambda (k) (plist-member
scanner-paper-sizes k)))))
(defcustom scanner-image-size
'(200 250)
@@ -141,8 +139,8 @@ widget's values and the elements of SET."
(let ((values (widget-value widget)))
(unless (cl-subsetp values set :test #'string=)
(widget-put widget :error (format error-msg
- (mapconcat #'identity values ", ")
- (mapconcat #'identity set ", ")))
+
(mapconcat #'identity values ", ")
+
(mapconcat #'identity set ", ")))
widget)))
(defun scanner--validate-languages (widget)
@@ -150,7 +148,7 @@ widget's values and the elements of SET."
(scanner--widget-validate-subset
"Unknown language(s): %s; available are: %s" widget
(cdr (process-lines scanner-tesseract-program
- "--list-langs"))))
+ "--list-langs"))))
(defcustom scanner-tesseract-languages
'("eng")
@@ -200,7 +198,7 @@ If nil, attempt auto-detection. Note that some devices,
like USB
scanners, may receive a different name every time they are
plugged in. For these, auto-detection will always be done."
:type '(restricted-sexp :match-alternatives
- (stringp 'nil)))
+ (stringp 'nil)))
(defcustom scanner-scan-delay
3
@@ -214,42 +212,42 @@ plugged in. For these, auto-detection will always be
done."
(let ((map (make-sparse-keymap)))
(define-key map [languages]
'(menu-item "Select languages" scanner-select-languages
- :key-sequence nil
- :help "Select languages for OCR."))
+ :key-sequence nil
+ :help "Select languages for OCR."))
(define-key map [outputs]
'(menu-item "Select document outputs" scanner-select-outputs
- :key-sequence nil
- :help "Select document output formats."))
+ :key-sequence nil
+ :help "Select document output formats."))
(define-key map [papersize]
'(menu-item "Select paper size" scanner-select-papersize
- :key-sequence nil
- :help "Select a paper size for document scanning."))
+ :key-sequence nil
+ :help "Select a paper size for document
scanning."))
(define-key map [img-res]
'(menu-item "Set image resolution" scanner-set-image-resolution
- :key-sequence nil
- :help "Set the resolution for image scanning."))
+ :key-sequence nil
+ :help "Set the resolution for image
scanning."))
(define-key map [doc-res]
'(menu-item "Set document resolution" scanner-set-document-resolution
- :key-sequence nil
- :help "Set the resolution for document scanning."))
+ :key-sequence nil
+ :help "Set the resolution for document
scanning."))
(define-key map [select-dev]
'(menu-item "Select scanning device" scanner-select-device
- :key-sequence nil
- :help "Select a scanning device."))
+ :key-sequence nil
+ :help "Select a scanning device."))
(define-key map [seperator]
'(menu-item "--"))
(define-key map [image-multi]
'(menu-item "Scan multiple images" scanner-scan-multi-images
- :key-sequence nil))
+ :key-sequence nil))
(define-key map [image]
'(menu-item "Scan an image" scanner-scan-image
- :key-sequence nil))
+ :key-sequence nil))
(define-key map [document-multi]
'(menu-item "Scan a multi-page document" scanner-scan-multi-doc
- :key-sequence nil))
+ :key-sequence nil))
(define-key map [document]
'(menu-item "Scan a document" scanner-scan-document
- :key-sequence nil))
+ :key-sequence nil))
map)
"The scanner menu map.")
@@ -285,8 +283,8 @@ name, the device type, and the vendor and model names."
;; attempt to filter out any spurious error output or other non-relevant
;; stuff
(setq scanner--detected-devices
- (--filter (= 3 (length it))
- (mapcar (lambda (x) (split-string x "|")) scanners)))))
+ (--filter (= 3 (length it))
+ (mapcar (lambda (x) (split-string x
"|")) scanners)))))
(defun scanner--scanimage-args (outfile scan-type switches img-fmt)
"Construct the argument list for scanimage(1).
@@ -300,27 +298,27 @@ the document format. If any of the required options from
‘scanner--device-specific-switches’ are unavailable, they are
simply dropped."
(let ((size (cond ((eq :doc scan-type)
- (plist-get scanner-paper-sizes scanner-doc-papersize))
- ((eq :image scan-type) scanner-image-size)
- (t nil))))
+ (plist-get scanner-paper-sizes
scanner-doc-papersize))
+ ((eq :image scan-type)
scanner-image-size)
+ (t nil))))
(-flatten (list (and scanner-device-name
- (list "-d" scanner-device-name))
- (concat "--format=" img-fmt)
- "-o" outfile
- (--map (pcase it
- ("--mode" (concat "--mode="
- (plist-get scanner-scan-mode
- scan-type)))
- ("--resolution" (concat "--resolution="
- (number-to-string
- (plist-get
scanner-resolution
- scan-type))))
- ((and "-x" (guard size))
- (list "-x" (number-to-string (car size))))
- ((and "-y" (guard size))
- (list "-y" (number-to-string (cadr size)))))
- switches)
- scanner-scanimage-switches))))
+ (list "-d"
scanner-device-name))
+ (concat "--format=" img-fmt)
+ "-o" outfile
+ (--map (pcase it
+ ("--mode" (concat
"--mode="
+
(plist-get scanner-scan-mode
+
scan-type)))
+ ("--resolution"
(concat "--resolution="
+
(number-to-string
+
(plist-get scanner-resolution
+
scan-type))))
+ ((and "-x" (guard
size))
+ (list "-x"
(number-to-string (car size))))
+ ((and "-y" (guard
size))
+ (list "-y"
(number-to-string (cadr size)))))
+ switches)
+ scanner-scanimage-switches))))
(defun scanner--tesseract-args (input output-base)
"Construct the argument list for ‘tesseract(1)’.
@@ -329,10 +327,10 @@ output files. Note that tesseract automatically adds
file name
extensions depending on the selected output options, see
‘scanner-tesseract-outputs’."
(-flatten (list input output-base
- "-l" (mapconcat #'identity scanner-tesseract-languages "+")
- "--dpi" (number-to-string (plist-get scanner-resolution :doc))
- scanner-tesseract-switches
- scanner-tesseract-outputs)))
+ "-l" (mapconcat #'identity
scanner-tesseract-languages "+")
+ "--dpi" (number-to-string (plist-get
scanner-resolution :doc))
+ scanner-tesseract-switches
+ scanner-tesseract-outputs)))
(defun scanner--ensure-init ()
"Ensure that scanning device is initialized.
@@ -344,29 +342,29 @@ This function checks the SANE backend of the selected
device
against the required options. The return value is a list of the
available options."
(let ((-compare-fn #'string=)
- (switches-re (eval-when-compile
- (regexp-opt scanner--device-specific-switches t)))
- opts)
+ (switches-re (eval-when-compile
+ (regexp-opt
scanner--device-specific-switches t)))
+ opts)
(unless (and scanner-device-name
- (eql 0 (call-process scanner-scanimage-program
- nil nil nil "-n"
- "-d" scanner-device-name)))
+ (eql 0 (call-process scanner-scanimage-program
+ nil
nil nil "-n"
+ "-d"
scanner-device-name)))
(let ((num-devices (length (scanner--detect-devices))))
- (cond ((= 0 num-devices)
- (user-error "No scanning device was found"))
- ((= 1 num-devices)
- (setq scanner-device-name (caar scanner--detected-devices)))
- (t (call-interactively #'scanner-select-device)))))
+ (cond ((= 0 num-devices)
+ (user-error "No scanning device was found"))
+ ((= 1 num-devices)
+ (setq scanner-device-name (caar
scanner--detected-devices)))
+ (t (call-interactively #'scanner-select-device)))))
(with-temp-buffer
(apply #'call-process scanner-scanimage-program nil t nil "-A"
- (and scanner-device-name (list "-d" scanner-device-name)))
+ (and scanner-device-name (list "-d"
scanner-device-name)))
(goto-char (point-min))
(while (re-search-forward switches-re nil t)
- (push (match-string 1) opts)))
+ (push (match-string 1) opts)))
(-when-let (missing (-difference scanner--device-specific-switches
- opts))
+ opts))
(scanner--log "Some required options are not supported by the device: %S"
- missing))
+ missing))
(nreverse opts)))
(defun scanner--log (msg &rest args)
@@ -388,10 +386,10 @@ MSG is a format string, with ARGS passed to ‘format’."
"Select the papersize SIZE for document scanning."
(interactive
(let ((choices (delq nil (mapcar (lambda (x) (and (keywordp x)
- (substring (symbol-name x) 1)))
- scanner-paper-sizes))))
+
(substring (symbol-name x) 1)))
+
scanner-paper-sizes))))
(list (intern (concat ":"
- (completing-read "Papersize: " choices nil t))))))
+ (completing-read "Papersize:
" choices nil t))))))
(setq scanner-doc-papersize size))
;;;###autoload
@@ -399,7 +397,7 @@ MSG is a format string, with ARGS passed to ‘format’."
"Select LANGUAGES for optical character recognition."
(interactive
(let ((langs (cdr (process-lines scanner-tesseract-program
- "--list-langs"))))
+
"--list-langs"))))
(list (completing-read-multiple "Languages: " langs nil t))))
(setq scanner-tesseract-languages languages))
@@ -434,15 +432,15 @@ The selected device will be used for any future scan
until a new
selection is made."
(interactive
(let* ((devices (if current-prefix-arg
- (scanner--detect-devices)
- (or scanner--detected-devices
- (scanner--detect-devices))))
- (choices (mapcar (lambda (dev)
- (concat (caddr dev) " (" (car dev) ")"))
- devices)))
+ (scanner--detect-devices)
+ (or scanner--detected-devices
+ (scanner--detect-devices))))
+ (choices (mapcar (lambda (dev)
+ (concat (caddr dev) "
(" (car dev) ")"))
+ devices)))
(list (cadr (split-string
- (completing-read "Select scanning device: " choices nil t)
- "(" t ")")))))
+ (completing-read "Select scanning device: "
choices nil t)
+ "(" t ")")))))
(setq scanner-device-name device))
;;;###autoload
@@ -461,71 +459,75 @@ attempt auto-detection. If more than one scanning device
is
available, ask for a selection interactively."
(interactive "P\nFDocument file name: ")
(let ((doc-file (file-name-sans-extension filename))
- (num-pages (prefix-numeric-value npages))
- (fmt (plist-get scanner-image-format :doc))
- (switches (scanner--ensure-init))
- (file-list '())
- (fl-file nil))
+ (num-pages (prefix-numeric-value npages))
+ (fmt (plist-get scanner-image-format :doc))
+ (switches (scanner--ensure-init))
+ (file-list '())
+ (fl-file nil))
(cl-labels ((scanimage
- ()
- (let* ((img-file (make-temp-file "scanner" nil (concat "."
fmt)))
- (scanimage-args (scanner--scanimage-args img-file
- :doc
- switches
- fmt)))
- (push img-file file-list)
- (make-process :name "Scanner (scanimage)"
- :command `(,scanner-scanimage-program
- ,@scanimage-args)
- :sentinel #'scan-or-process
- :stderr (scanner--log-buffer))))
- (scan-or-process
- (process event)
- (condition-case err
- (let ((ev (string-trim event)))
- (unless (string= "finished" ev)
- (error "%s: %s" process ev))
- (cond ((consp npages) (if (y-or-n-p "Scan another page?
")
- (scanimage)
- (tesseract)))
- ((> num-pages 1)
- (cl-decf num-pages)
- (run-at-time scanner-scan-delay nil #'scanimage))
- (t (tesseract))))
- (error
- (cleanup)
- (signal (car err) (cdr err)))))
- (tesseract
- ()
- (unless scanner-reverse-pages
- (setq file-list (nreverse file-list)))
- (setq fl-file (make-temp-file "scanlist" nil ".txt"
- (mapconcat #'identity
- file-list
- "\n")))
- (let ((tesseract-args (scanner--tesseract-args fl-file
- doc-file)))
- (scanner--log "") ; make sure logs are properly sequenced
- (make-process :name "Scanner (tesseract)"
- :command `(,scanner-tesseract-program
- ,@tesseract-args)
- :sentinel #'finish
- :stderr (scanner--log-buffer))))
- (finish
- (process event)
- (unwind-protect
- (let ((ev (string-trim event)))
- (unless (string= "finished" ev)
- (error "%s: %s" process ev)))
- (cleanup)))
- (cleanup
- ()
- (and file-list (dolist (file file-list)
- (delete-file file)))
- (and fl-file (delete-file fl-file))))
- (scanner--log "Scanning document to file(s) \"%s.*\""
- (concat doc-file))
- (scanimage))))
+ ()
+ (let* ((img-file (make-temp-file "scanner" nil
(concat "." fmt)))
+ (scanimage-args
(scanner--scanimage-args img-file
+
:doc
+
switches
+
fmt)))
+ (push img-file file-list)
+ (make-process :name "Scanner (scanimage)"
+ :command
`(,scanner-scanimage-program
+
,@scanimage-args)
+ :sentinel
#'scan-or-process
+ :stderr
(scanner--log-buffer))))
+ (scan-or-process
+ (process event)
+ (condition-case err
+ (let ((ev (string-trim event)))
+ (unless (string= "finished" ev)
+ (error "%s: %s" process ev))
+ (cond ((consp npages) (if (y-or-n-p
"Scan another page? ")
+
(scanimage)
+
(tesseract)))
+ ((> num-pages 1)
+ (cl-decf num-pages)
+ (run-at-time
scanner-scan-delay nil #'scanimage))
+ (t (tesseract))))
+ (error
+ (cleanup)
+ (signal (car err) (cdr err)))))
+ (tesseract
+ ()
+ (unless scanner-reverse-pages
+ (setq file-list (nreverse file-list)))
+ (setq fl-file (make-temp-file "scanlist" nil
".txt"
+
(mapconcat #'identity
+
file-list
+
"\n")))
+ (let ((tesseract-args (scanner--tesseract-args
fl-file
+
doc-file)))
+ (scanner--log "") ; make sure logs are
properly sequenced
+ (make-process :name "Scanner (tesseract)"
+ :command
`(,scanner-tesseract-program
+
,@tesseract-args)
+ :sentinel
#'finish
+ :stderr
(scanner--log-buffer))))
+ (finish
+ (process event)
+ (unwind-protect
+ (let ((ev (string-trim event)))
+ (unless (string= "finished" ev)
+ (error "%s: %s" process ev)))
+ (cleanup)))
+ (cleanup
+ ()
+ (and file-list (dolist (file file-list)
+ (delete-file
file)))
+ (and fl-file (delete-file fl-file))))
+ (if (and (file-exists-p filename)
+ (not (y-or-n-p (format "File ‘%s’ exists; overwrite?"
+
filename))))
+ nil
+ (scanner--log "Scanning document to file(s) \"%s.*\""
+ (concat doc-file))
+ (scanimage)))))
;;;###autoload
(defun scanner-scan-multi-doc (filename)
@@ -550,54 +552,58 @@ attempt auto-detection. If more than one scanning device
is
available, ask for a selection interactively."
(interactive "P\nFImage file name: ")
(let ((derived-fmt (cdr (assoc (downcase (file-name-extension filename t))
- '((".jpeg" . "jpeg")
- (".jpg" . "jpeg")
- (".png" . "png")
- (".pnm" . "pnm")
- (".tiff" . "tiff")
- (".tif" . "tiff")))))
- (num-scans (prefix-numeric-value nscans))
- (switches (scanner--ensure-init))
- (page-count 1))
+ '((".jpeg" .
"jpeg")
+ (".jpg" .
"jpeg")
+ (".png" .
"png")
+ (".pnm" .
"pnm")
+ (".tiff" .
"tiff")
+ (".tif" .
"tiff")))))
+ (num-scans (prefix-numeric-value nscans))
+ (switches (scanner--ensure-init))
+ (page-count 1))
(cl-labels ((scanimage
- (multi-scan)
- (let* ((img-fmt (or derived-fmt
- (plist-get scanner-image-format :image)))
- (img-ext (if derived-fmt
- (file-name-extension filename t)
- (concat "."
- (plist-get scanner-image-format
- :image))))
- (img-base (if derived-fmt
- (file-name-sans-extension filename)
- filename))
- (img-file (if multi-scan
- (prog1
- (concat img-base "-"
- (number-to-string page-count)
- img-ext)
- (cl-incf page-count))
- (concat img-base img-ext)))
- (scanimage-args (scanner--scanimage-args img-file
- :image
- switches
- img-fmt)))
- (scanner--log "Scanning image to file \"%s\"" img-file)
- (make-process :name "Scanner (scanimage)"
- :command `(,scanner-scanimage-program
- ,@scanimage-args)
- :sentinel #'scan-or-finish
- :stderr (scanner--log-buffer))))
- (scan-or-finish
- (process event)
- (let ((ev (string-trim event)))
- (unless (string= "finished" ev)
- (error "%s: %s" process ev))
- (cond ((consp nscans) (when (y-or-n-p "Scan another page? ")
- (scanimage t)))
- ((> num-scans 1)
- (cl-decf num-scans)
- (run-at-time scanner-scan-delay nil #'scanimage
t))))))
+ (multi-scan)
+ (let* ((img-fmt (or derived-fmt
+
(plist-get scanner-image-format :image)))
+ (img-ext (if derived-fmt
+
(file-name-extension filename t)
+ (concat "."
+
(plist-get scanner-image-format
+
:image))))
+ (img-base (if derived-fmt
+
(file-name-sans-extension filename)
+
filename))
+ (img-file (if multi-scan
+ (prog1
+
(concat img-base "-"
+
(number-to-string page-count)
+
img-ext)
+
(cl-incf page-count))
+ (concat
img-base img-ext)))
+ (scanimage-args
(scanner--scanimage-args img-file
+
:image
+
switches
+
img-fmt)))
+ (if (and (file-exists-p img-file)
+ (not (y-or-n-p (format
"File ‘%s’ exists; overwrite?"
+
img-file))))
+ nil
+ (scanner--log "Scanning image to file
\"%s\"" img-file)
+ (make-process :name "Scanner
(scanimage)"
+ :command
`(,scanner-scanimage-program
+
,@scanimage-args)
+ :sentinel
#'scan-or-finish
+ :stderr
(scanner--log-buffer)))))
+ (scan-or-finish
+ (process event)
+ (let ((ev (string-trim event)))
+ (unless (string= "finished" ev)
+ (error "%s: %s" process ev))
+ (cond ((consp nscans) (when (y-or-n-p "Scan
another page? ")
+
(scanimage t)))
+ ((> num-scans 1)
+ (cl-decf num-scans)
+ (run-at-time
scanner-scan-delay nil #'scanimage t))))))
(scanimage (or (> num-scans 1) (consp nscans))))))
;;;###autoload
- [elpa] externals/scanner updated (cbfd2bb -> b96d3d1), Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 1495d30 04/17: add time stamps when logging and log program arguments, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner f76603c 03/17: ask for confirmation before overwriting existing files,
Stefan Monnier <=
- [elpa] externals/scanner b683e19 05/17: correct handling of existing files, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner a43ce69 01/17: Update scanner.el, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 072222a 06/17: improve doc-string in scanner--confirm-filenames, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner e199957 07/17: add file-local variables for tab configuration, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 7d5cd5c 02/17: correct Readme.org markup (=...= instead of ~...~), Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 2101ca0 08/17: handle undefined options and tesseract config directory gracefully, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 22ead30 15/17: correct handling of empty TESSDATA_PREFIX env variable, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 5c8f04b 09/17: add --tessdata-dir option to scanner--tesseract-args, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner 52bb719 14/17: fix handling of tessdata directory, Stefan Monnier, 2020/12/14
- [elpa] externals/scanner ff513b0 10/17: add image size selection function and order menu more logically, Stefan Monnier, 2020/12/14