Merge pull request #10 from Kinneyzhang/copilot/fix-issue-9
fix: enforce kinsoku rules for CJK opening punctuation (Fixes #9)
This commit is contained in:
commit
11437cb029
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ archive
|
|||||||
*.dylib
|
*.dylib
|
||||||
*.dll
|
*.dll
|
||||||
*.o
|
*.o
|
||||||
|
*.elc
|
||||||
|
|||||||
48
ekp-utils.el
48
ekp-utils.el
@ -115,6 +115,14 @@
|
|||||||
(and (>= char #x3000) (<= char #x303F))
|
(and (>= char #x3000) (<= char #x303F))
|
||||||
(and (>= char #xFF00) (<= char #xFF60)))))
|
(and (>= char #xFF00) (<= char #xFF60)))))
|
||||||
|
|
||||||
|
(defun ekp-cjk-opening-punct-p (str)
|
||||||
|
"Return non-nil if STR ends with a CJK opening punctuation.
|
||||||
|
These characters must not appear at the end of a line (kinsoku rule).
|
||||||
|
When STR is held as cjk-char, this checks if it still needs attachment."
|
||||||
|
(let ((char (aref str (1- (length str)))))
|
||||||
|
(memq (get-char-code-property char 'general-category)
|
||||||
|
'(Ps Pi))))
|
||||||
|
|
||||||
(defun ekp--flush-latin-word (word boxes)
|
(defun ekp--flush-latin-word (word boxes)
|
||||||
"Push latin WORD to BOXES if non-nil. Return updated boxes."
|
"Push latin WORD to BOXES if non-nil. Return updated boxes."
|
||||||
(if word (cons word boxes) boxes))
|
(if word (cons word boxes) boxes))
|
||||||
@ -161,20 +169,41 @@ Return (new-state new-latin-word new-cjk-char new-boxes)."
|
|||||||
;; Already in latin mode: accumulate
|
;; Already in latin mode: accumulate
|
||||||
(list 1 (concat latin-word str) nil boxes)
|
(list 1 (concat latin-word str) nil boxes)
|
||||||
;; Was in CJK mode: flush CJK char, switch to latin
|
;; Was in CJK mode: flush CJK char, switch to latin
|
||||||
(list 1 str nil (ekp--flush-cjk-char cjk-char boxes))))
|
;; If held cjk-char is opening punct, prepend it to the latin word
|
||||||
|
(if (and cjk-char (ekp-cjk-opening-punct-p cjk-char))
|
||||||
|
(list 1 (concat cjk-char str) nil boxes)
|
||||||
|
(list 1 str nil (ekp--flush-cjk-char cjk-char boxes)))))
|
||||||
|
|
||||||
(defun ekp--handle-cjk-char (str state latin-word cjk-char boxes)
|
(defun ekp--handle-cjk-char (str state latin-word cjk-char boxes)
|
||||||
"Handle a CJK (width=2) character.
|
"Handle a CJK (width=2) character.
|
||||||
Return (new-state new-latin-word new-cjk-char new-boxes)."
|
Return (new-state new-latin-word new-cjk-char new-boxes)."
|
||||||
(if (= state 1)
|
(if (= state 1)
|
||||||
;; Was in latin mode: flush latin word, push CJK directly
|
;; Was in latin mode: flush latin word, push CJK directly
|
||||||
(list 2 nil nil (cons str (ekp--flush-latin-word latin-word boxes)))
|
(let ((new-boxes (ekp--flush-latin-word latin-word boxes)))
|
||||||
|
(if (ekp-cjk-opening-punct-p str)
|
||||||
|
;; Opening punct: hold as cjk-char (will attach to next char)
|
||||||
|
(list 2 nil str new-boxes)
|
||||||
|
(list 2 nil nil (cons str new-boxes))))
|
||||||
;; Already in CJK mode
|
;; Already in CJK mode
|
||||||
(if (ekp-cjk-fw-punct-p str)
|
(cond
|
||||||
;; Punctuation attaches to previous CJK char
|
((ekp-cjk-opening-punct-p str)
|
||||||
(list 2 nil nil (cons (concat cjk-char str) boxes))
|
;; Opening punct: cannot end a line (kinsoku rule).
|
||||||
;; Regular CJK char: flush previous, hold current
|
;; If previous held char is also opening punct, concatenate them.
|
||||||
(list 2 nil str (ekp--flush-cjk-char cjk-char boxes)))))
|
;; Otherwise flush previous and hold this opening punct.
|
||||||
|
(if (and cjk-char (ekp-cjk-opening-punct-p cjk-char))
|
||||||
|
(list 2 nil (concat cjk-char str) boxes)
|
||||||
|
(list 2 nil str (ekp--flush-cjk-char cjk-char boxes))))
|
||||||
|
((ekp-cjk-fw-punct-p str)
|
||||||
|
;; Closing/other punct: attaches to previous CJK char
|
||||||
|
(list 2 nil nil (cons (concat cjk-char str) boxes)))
|
||||||
|
(t
|
||||||
|
;; Regular CJK char: prepend any held opening punct
|
||||||
|
(if (and cjk-char (ekp-cjk-opening-punct-p cjk-char))
|
||||||
|
;; Previous was opening punct: combine with current char and hold.
|
||||||
|
;; Now last char is regular, so this won't be detected as opening.
|
||||||
|
(list 2 nil (concat cjk-char str) boxes)
|
||||||
|
;; Normal case: flush previous, hold current
|
||||||
|
(list 2 nil str (ekp--flush-cjk-char cjk-char boxes)))))))
|
||||||
|
|
||||||
(defun ekp-split-to-boxes (string)
|
(defun ekp-split-to-boxes (string)
|
||||||
"Split STRING into typographic boxes.
|
"Split STRING into typographic boxes.
|
||||||
@ -197,9 +226,12 @@ Whitespace runs are preserved as separate boxes; CJK punctuation attaches to pre
|
|||||||
(cond
|
(cond
|
||||||
;; Whitespace or zero-width: flush content, accumulate spaces
|
;; Whitespace or zero-width: flush content, accumulate spaces
|
||||||
((or (string-blank-p str) (= 0 width))
|
((or (string-blank-p str) (= 0 width))
|
||||||
|
;; Don't flush opening punct - keep it held for attachment to next char
|
||||||
|
(if (and cjk-char (ekp-cjk-opening-punct-p cjk-char))
|
||||||
|
nil ; keep cjk-char as-is
|
||||||
(setq boxes (ekp--flush-cjk-char cjk-char boxes))
|
(setq boxes (ekp--flush-cjk-char cjk-char boxes))
|
||||||
(when cjk-char (setq prev-state 2))
|
(when cjk-char (setq prev-state 2))
|
||||||
(setq cjk-char nil)
|
(setq cjk-char nil))
|
||||||
(setq boxes (ekp--flush-latin-word latin-word boxes))
|
(setq boxes (ekp--flush-latin-word latin-word boxes))
|
||||||
(when latin-word (setq prev-state 1))
|
(when latin-word (setq prev-state 1))
|
||||||
(setq latin-word nil)
|
(setq latin-word nil)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user