1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-24 07:20:37 +00:00

(search-unencodable-char): New

function.
(select-safe-coding-system): Show unencodable characters.
(unencodable-char-position): Deleted, and implemented by C in
coding.c.
This commit is contained in:
Kenichi Handa 2002-08-11 01:04:41 +00:00
parent 8030369ccb
commit 738746ba63

View File

@ -548,6 +548,27 @@ For invalid characters, CHARs are actually strings."
(setq chars (cons (list charset 1 char) chars))))))))
(nreverse chars)))
(defun search-unencodable-char (coding-system)
"Search forward from point for a character that is not encodable.
It asks which coding system to check.
If such a character is found, set point after that character.
Otherwise, don't move point.
When called from a program, the value is a position of the found character,
or nil if all characters are encodable."
(interactive
(list (let ((default (or buffer-file-coding-system 'us-ascii)))
(read-coding-system
(format "Coding-system (default, %s): " default)
default))))
(let ((pos (unencodable-char-position (point) (point-max) coding-system)))
(if pos
(goto-char (1+ pos))
(message "All following characters are encodable by %s" coding-system))
pos))
(defvar last-coding-system-specified nil
"Most recent coding system explicitly specified by the user when asked.
This variable is set whenever Emacs asks the user which coding system
@ -655,7 +676,30 @@ and TO is ignored."
;; If all the defaults failed, ask a user.
(when (or (not coding-system) (consp coding-system))
;; At first, change each coding system to the corresponding
;; At first, record at most 11 problematic characters and their
;; positions for each default.
(if (stringp from)
(mapc #'(lambda (coding)
(setcdr coding
(mapcar #'(lambda (pos)
(cons pos (aref from pos)))
(unencodable-char-position
0 (length from) (car coding) 11 from))))
default-coding-system)
(mapc #'(lambda (coding)
(setcdr coding
(mapcar #'(lambda (pos)
(cons pos (char-after pos)))
(unencodable-char-position
from to (car coding) 11))))
default-coding-system))
;; If 11 unencodable characters were found, mark the last one as nil.
(mapc #'(lambda (coding)
(if (> (length coding) 11)
(setcdr (car (last coding)) nil)))
default-coding-system)
;; Change each safe coding system to the corresponding
;; mime-charset name if it is also a coding system. Such a name
;; is more friendly to users.
(let ((l codings)
@ -676,75 +720,112 @@ and TO is ignored."
(coding-system-category elt)))
(push elt l))))
(unwind-protect
(save-window-excursion
(let ((window-configuration (current-window-configuration)))
(save-excursion
;; Make sure the offending buffer is displayed.
(when (and default-coding-system (not (stringp from)))
(pop-to-buffer bufname)
(goto-char (apply 'min (mapcar #'(lambda (x) (car (cadr x)))
default-coding-system))))
;; Then ask users to select one from CODINGS.
(with-output-to-temp-buffer "*Warning*"
(save-excursion
;; Make sure the offending buffer is displayed.
(unless (stringp from)
(pop-to-buffer bufname)
(goto-char (unencodable-char-position
from to (mapcar #'car default-coding-system))))
;; Then ask users to select one from CODINGS.
(with-output-to-temp-buffer "*Warning*"
(save-excursion
(set-buffer standard-output)
(if (not default-coding-system)
(insert "No default coding systems to try for "
(if (stringp from)
(format "string \"%s\"." from)
(format "buffer `%s'." bufname)))
(insert
"These default coding systems were tried to encode"
(if (stringp from)
(concat " \"" (if (> (length from) 10)
(concat (substring from 0 10) "...\"")
(concat from "\"")))
(format " text\nin the buffer `%s'" bufname))
":\n")
(let ((pos (point))
(fill-prefix " "))
(mapcar (function (lambda (x)
(princ " ") (princ (car x))))
default-coding-system)
(insert "\n")
(fill-region-as-paragraph pos (point)))
(if (consp coding-system)
(insert (format "%s safely encodes the target text,\n"
(car coding-system))
"\
(set-buffer standard-output)
(if (not default-coding-system)
(insert "No default coding systems to try for "
(if (stringp from)
(format "string \"%s\"." from)
(format "buffer `%s'." bufname)))
(insert
"These default coding systems were tried to encode"
(if (stringp from)
(concat " \"" (if (> (length from) 10)
(concat (substring from 0 10) "...\"")
(concat from "\"")))
(format " text\nin the buffer `%s'" bufname))
":\n")
(let ((pos (point))
(fill-prefix " "))
(mapcar (function (lambda (x)
(princ " ") (princ (car x))))
default-coding-system)
(insert "\n")
(fill-region-as-paragraph pos (point)))
(if (consp coding-system)
(insert (format "%s safely encodes the target text,\n"
(car coding-system))
"\
but it is not recommended for encoding text in this context,
e.g., for sending an email message.\n")
(insert "\
However, none of them safely encodes the target text.
(insert "\
However, each of them encountered these problematic characters:\n")
(mapc
#'(lambda (coding)
(insert (format " %s:" (car coding)))
(dolist (elt (cdr coding))
(insert " ")
(if (stringp from)
(insert (or (cdr elt) "..."))
(if (cdr elt)
(insert-text-button
(cdr elt)
:type 'help-xref
'help-echo
"mouse-2, RET: jump to this character"
'help-function
#'(lambda (bufname pos)
(when (buffer-live-p (get-buffer bufname))
(pop-to-buffer bufname)
(goto-char pos)))
'help-args (list bufname (car elt)))
(insert-text-button
"..."
:type 'help-xref
'help-echo
"mouse-2, RET: next unencodable character"
'help-function
#'(lambda (bufname pos coding)
(when (buffer-live-p (get-buffer bufname))
(pop-to-buffer bufname)
(if (< (point) pos)
(goto-char pos)
(forward-char 1)
(search-unencodable-char coding)
(forward-char -1))))
'help-args (list bufname (car elt)
(car coding))))))
(insert "\n"))
default-coding-system)
(insert "\
The first problematic character is at point in the displayed buffer,\n"
(substitute-command-keys "\
(substitute-command-keys "\
and \\[universal-argument] \\[what-cursor-position] will give information about it.\n"))))
(insert (if (consp coding-system)
"\nSelect the above, or "
"\nSelect ")
"\
(insert (if (consp coding-system)
"\nSelect the above, or "
"\nSelect ")
"\
one of the following safe coding systems, or edit the buffer:\n")
(let ((pos (point))
(fill-prefix " "))
(mapcar (function (lambda (x) (princ " ") (princ x)))
codings)
(insert "\n")
(fill-region-as-paragraph pos (point)))))
(let ((pos (point))
(fill-prefix " "))
(mapcar (function (lambda (x) (princ " ") (princ x)))
codings)
(insert "\n")
(fill-region-as-paragraph pos (point)))))
;; Read a coding system.
(if (consp coding-system)
(setq codings (cons (car coding-system) codings)))
(let* ((safe-names (mapcar (lambda (x) (list (symbol-name x)))
codings))
(name (completing-read
(format "Select coding system (default %s): "
(car codings))
safe-names nil t nil nil
(car (car safe-names)))))
(setq last-coding-system-specified (intern name)
coding-system last-coding-system-specified)))
(kill-buffer "*Warning*"))))
;; Read a coding system.
(if (consp coding-system)
(setq codings (cons (car coding-system) codings)))
(let* ((safe-names (mapcar (lambda (x) (list (symbol-name x)))
codings))
(name (completing-read
(format "Select coding system (default %s): "
(car codings))
safe-names nil t nil nil
(car (car safe-names)))))
(setq last-coding-system-specified (intern name)
coding-system last-coding-system-specified)))
(kill-buffer "*Warning*")
(set-window-configuration window-configuration)))
(if (vectorp (coding-system-eol-type coding-system))
(let ((eol (coding-system-eol-type buffer-file-coding-system)))
@ -780,46 +861,6 @@ and try again)? " coding-system auto-cs))
(error "Save aborted")))))
coding-system))
(defun unencodable-char-position (start end coding-system)
"Return position of first un-encodable character in a region.
START and END specfiy the region and CODING-SYSTEM specifies the
encoding to check. Return nil if CODING-SYSTEM does encode the region.
CODING-SYSTEM may also be a list of coding systems, in which case return
the first position not encodable by any of them.
This function is fairly slow."
;; Use recursive calls in the binary chop below, since we're
;; O(logN), and the call overhead shouldn't be a bottleneck.
(unless enable-multibyte-characters
(error "Unibyte buffer"))
;; Recurse if list of coding systems.
(if (consp coding-system)
(let ((end end) res)
(dolist (elt coding-system (and res (>= res 0) res))
(let ((pos (unencodable-char-position start end elt)))
(if pos
(setq end pos
res pos)))))
;; Skip ASCII initially.
(save-excursion
(goto-char start)
(skip-chars-forward "\000-\177" end)
(setq start (point))
(unless (= start end)
(setq coding-system (coding-system-base coding-system)) ; canonicalize
(let ((codings (find-coding-systems-region start end)))
(unless (or (equal codings '(undecided))
(memq coding-system
(find-coding-systems-region start end)))
;; Binary chop.
(if (= start (1- end))
start
(or (unencodable-char-position start (/ (+ start end) 2)
coding-system)
(unencodable-char-position (/ (+ start end) 2) end
coding-system)))))))))
(setq select-safe-coding-system-function 'select-safe-coding-system)
(defun select-message-coding-system ()