New commands to convert ASCII to fullwidth characters and back

* lisp/textmodes/text-mode.el (text-mode--fullwidth-table): New
variable.
(text-mode--get-fullwidth-table): New internal function.
(fullwidth-region, halfwidth-region, fullwidth-word)
(halfwidth-word): New commands.  (Bug#71822)

* etc/NEWS: Announce new commands.
This commit is contained in:
Eli Zaretskii 2025-03-02 15:25:53 +02:00
parent e34d7a7c4e
commit 8937dee9e4
2 changed files with 90 additions and 0 deletions

View file

@ -444,6 +444,17 @@ modal editing packages.
* Changes in Specialized Modes and Packages in Emacs 31.1
---
** Text mode
*** New commands to convert between ASCII and full-width characters.
New commands 'fullwidth-region' and 'fullwidth-word' convert ASCII
characters in region or in the word at point to the corresponding
full-width characters, which are customarily used instead of ASCII
characters in CJK texts. For example, 'A' is converted to '', '1' is
converted to '', etc. Companion commands 'halfwidth-region' and
'halfwidth-word' perform the opposite conversion.
---
** ASM mode

View file

@ -271,6 +271,85 @@ The argument NLINES says how many lines to center."
(define-obsolete-function-alias 'indented-text-mode #'text-mode "29.1")
(defvar text-mode--fullwidth-table nil)
(defun text-mode--get-fullwidth-table ()
"Return translation table for converting half-width characters to fullwidth."
(or (and (char-table-p text-mode--fullwidth-table)
text-mode--fullwidth-table)
;; Create the translation table.
(let ((tbl (make-char-table 'translation-table))
(rev-tbl (make-char-table 'translation-table))
(ch ?!))
(while (<= ch ?~)
;; ! -> , 0 -> , A -> , etc.
(aset tbl ch (+ ch #xFEE0))
(aset rev-tbl (+ ch #xFEE0) ch)
(setq ch (1+ ch)))
(set-char-table-extra-slot tbl 0 rev-tbl)
(set-char-table-extra-slot tbl 1 1)
(set-char-table-extra-slot rev-tbl 1 1)
(put 'text-mode--fullwidth-table 'translation-table tbl)
(setq text-mode--fullwidth-table tbl)
tbl)))
(defun fullwidth-region (from to)
"Convert ASCII characters in the region to their fullwidth variants.
This converts 1 to , A to , etc.
When called from Lisp, FROM and TO are character positions that define
the region in which to convert characters."
(interactive "r")
(translate-region from to
(text-mode--get-fullwidth-table)))
(defun halfwidth-region (from to)
"Convert fullwidth characters in the region to their ASCII variants.
This converts to 1, to A, etc.
When called from Lisp, FROM and TO are character positions that define
the region in which to convert characters."
(interactive "r")
(translate-region from to
(char-table-extra-slot (text-mode--get-fullwidth-table)
0)))
(defun fullwidth-word (arg)
"Convert fullwidth characters in word at point, moving over the word.
This converts fullwidth characters to their ASCII variants:
to 1, to A, etc.
With numerical argument ARG, convert that many words starting from point.
With negative argument, convert previous words, but do not move point.
If point is in the middle of a word, the part of that word before point
is ignored when converting forward, and the part of that word after
point is ignored when converting backward."
(interactive "p")
(let* ((pt (point-marker))
(beg pt)
(end (progn
(forward-word arg)
(point))))
(fullwidth-region beg end)
(or (> arg 0) (goto-char pt))))
(defun halfwidth-word (arg)
"Convert characters in word at point to fullwidth, moving over the word.
This converts ASCII characters to their fullwidth variants:
1 to , A to , etc.
With numerical argument ARG, convert that many words starting from point.
With negative argument, convert previous words, but do not move point.
If point is in the middle of a word, the part of that word before point
is ignored when converting forward, and the part of that word after
point is ignored when converting backward."
(interactive "p")
(let* ((pt (point-marker))
(beg pt)
(end (progn
(forward-word arg)
(point))))
(halfwidth-region beg end)
(or (> arg 0) (goto-char pt))))
(provide 'text-mode)
;;; text-mode.el ends here