commit 9cfd13ff44e8d6f56a1025207c833ab45a7d51ba (HEAD, refs/remotes/origin/master) Author: Jim Porter Date: Sun Nov 3 20:21:12 2024 -0800 ; * test/lisp/eshell/esh-cmd-tests.el: Fix last change. diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index 64ac3a8c2f6..3b1fbafe4d1 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -354,7 +354,7 @@ processes correctly." ;; doesn't count. (let ((eshell-test-value "1..5")) (eshell-match-command-output "for i in $eshell-test-value { echo $i }" - "1..5\n"))))) + "1..5\n")))) (ert-deftest esh-cmd-test/for-loop-mixed-args () "Test invocation of a for loop iterating over multiple arguments." commit ee87af4f1603d2042afa641e74df0403a49af1c5 Author: Jim Porter Date: Sun Nov 3 11:56:15 2024 -0800 Add support for range objects in Eshell "for" loops * lisp/eshell/esh-cmd.el (eshell-for-iterate): Add support for 'eshell-range' objects. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-range): New test. * doc/misc/eshell.texi (Control Flow): Update documentation. * etc/NEWS: Announce this change. diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index ee4d0ca09c8..fda1632f1ac 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1761,11 +1761,15 @@ satisfied. Repeatedly evaluate @var{subcommand} until @var{conditional} is satisfied. -@item for @var{var} in @var{list}@dots{} @var{subcommand} -Iterate over each element of @var{list}, storing the element in -@var{var} and evaluating @var{subcommand}. If @var{list} is not a list, -treat it as a list of one element. If you specify multiple @var{lists}, -this will iterate over each of them in turn. +@item for @var{var} in @var{sequence}@dots{} @var{subcommand} +Iterate over each element of @var{sequence}, storing the element in +@var{var} and evaluating @var{subcommand}. If @var{sequence} is a +range of the form @code{@var{begin}..@var{end}}, iterate over each +integer between @var{begin} and @var{end}, not including @var{end}. If +@var{sequence} is not a sequence, treat it as a list of one element. + +If you specify multiple @var{sequences}, this will iterate over each of +them in turn. @end table diff --git a/etc/NEWS b/etc/NEWS index 41a76d1cd95..1df8b1b794d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -280,6 +280,12 @@ These functions now take an optional ERROR-TARGET argument to control where to send the standard error output. See the "(eshell) Entry Points" node in the Eshell manual for more details. ++++ +*** You can now loop over ranges of integers with the Eshell 'for' command. +When passing a range like 'BEGIN..END' to the Eshell 'for' command, +Eshell will now iterate over each integer between BEGIN and END, not +including END. + +++ *** Conditional statements in Eshell now use an 'else' keyword. Eshell now prefers the following form when writing conditionals: diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 11fa9fc6122..c0015745ad5 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -530,7 +530,19 @@ the second is ignored." "Iterate over the elements of each sequence in ARGS. If ARGS is not a sequence, treat it as a list of one element." (dolist (arg args) + (when (eshell--range-string-p arg) + (setq arg (eshell--string-to-range arg))) (cond + ((eshell-range-p arg) + (let ((i (eshell-range-begin arg)) + (end (eshell-range-end arg))) + ;; NOTE: We could support unbounded ranges here, but those + ;; aren't very easy to use in Eshell yet. (We'd need something + ;; like the "break" statement for "for" loops.) + (cl-assert (and i end)) + (while (< i end) + (iter-yield i) + (cl-incf i)))) ((stringp arg) (iter-yield arg)) ((listp arg) diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index ae1aed59b45..64ac3a8c2f6 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -341,6 +341,21 @@ processes correctly." (eshell-match-command-output "for i in `[1 2 3] { echo $i }" "1\n2\n3\n"))) +(ert-deftest esh-cmd-test/for-loop-range () + "Test invocation of a for loop iterating over a range." + (with-temp-eshell + (eshell-match-command-output "for i in 1..5 { echo $i }" + "1\n2\n3\n4\n") + (let ((eshell-test-value 2)) + (eshell-match-command-output "for i in $eshell-test-value..5 { echo $i }" + "2\n3\n4\n")) + ;; Make sure range syntax only work when it's part of the literal + ;; syntax; a variable expanding to something that looks like a range + ;; doesn't count. + (let ((eshell-test-value "1..5")) + (eshell-match-command-output "for i in $eshell-test-value { echo $i }" + "1..5\n"))))) + (ert-deftest esh-cmd-test/for-loop-mixed-args () "Test invocation of a for loop iterating over multiple arguments." (with-temp-eshell commit ed9ea57e57a915e743100591d7a71d44a4b4c0e9 Author: Jim Porter Date: Sun Oct 20 18:01:10 2024 -0700 Move more of Eshell range handling to the parser phase * lisp/eshell/esh-util.el (eshell-range): New struct. (eshell--range-string-p, eshell--string-to-range): New functions. * lisp/eshell/esh-arg.el (eshell-parse-integer) (eshell-parse-range-token): New functions... (eshell-parse-argument-hook): ... add them. (eshell--after-range-token-regexp): New defsubst. (eshell-concat-1): Don't remove the 'number' property; we use that when handling range arguments. (eshell--range-token): New constant. (eshell-unmark-range-token): New function. * lisp/eshell/esh-var.el (eshell-parse-index): Update implementation to use parsed range argument. * test/lisp/eshell/esh-var-tests.el (esh-var-test/interp-var-indices): Test range index using variables. diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index 55a40f0af3d..8a23bfe20b4 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -92,6 +92,11 @@ If POS is nil, the location of point is checked." eshell-parse-special-reference ;; Numbers convert to numbers if they stand alone. eshell-parse-number + ;; Integers convert to numbers if they stand alone or are part of a + ;; range expression. + eshell-parse-integer + ;; Range tokens go between integers and denote a half-open range. + eshell-parse-range-token ;; Parse any non-special characters, based on the current context. eshell-parse-non-special ;; Whitespace is an argument delimiter. @@ -193,6 +198,15 @@ Eshell will expand special refs like \"#\" into (rx-to-string `(+ (not (any ,@eshell-special-chars-outside-quoting))) t)))) +(defvar eshell--after-range-token-regexp nil) +(defsubst eshell--after-range-token-regexp () + (or eshell--after-range-token-regexp + (setq-local eshell--after-range-token-regexp + (rx-to-string + `(or (any ,@eshell-special-chars-outside-quoting) + (regexp ,eshell-integer-regexp)) + t)))) + (defsubst eshell-escape-arg (string) "Return STRING with the `escaped' property on it." (if (stringp string) @@ -245,7 +259,6 @@ If QUOTED is nil and either FIRST or SECOND are numberlike, try to mark the result as a number as well." (let ((result (concat (eshell-stringify first quoted) (eshell-stringify second quoted)))) - (remove-text-properties 0 (length result) '(number) result) (when (and (not quoted) (or (numberp first) (eshell--numeric-string-p first) (numberp second) (eshell--numeric-string-p second))) @@ -412,6 +425,8 @@ Point is left at the end of the arguments." "A stub function that generates an error if a floating splice is found." (error "Splice operator is not permitted in this context")) +(defconst eshell--range-token (propertize ".." 'eshell-range t)) + (defun eshell-parse-number () "Parse a numeric argument. Eshell can treat unquoted arguments matching `eshell-number-regexp' as @@ -422,10 +437,50 @@ their numeric values." (eshell-arg-delimiter (match-end 0))) (goto-char (match-end 0)) (let ((str (match-string 0))) - (when (> (length str) 0) - (add-text-properties 0 (length str) '(number t) str)) + (add-text-properties 0 (length str) '(number t) str) str))) +(defun eshell-parse-integer () + "Parse an integer argument." + (unless eshell-current-quoted + (let ((prev-token (if eshell-arg-listified + (car (last eshell-current-argument)) + eshell-current-argument))) + (when (and (memq prev-token `(nil ,eshell--range-token)) + (looking-at eshell-integer-regexp) + (or (eshell-arg-delimiter (match-end 0)) + (save-excursion + (goto-char (match-end 0)) + (looking-at-p (rx ".."))))) + (goto-char (match-end 0)) + (let ((str (match-string 0))) + (add-text-properties 0 (length str) '(number t) str) + str))))) + +(defun eshell-unmark-range-token (string) + (remove-text-properties 0 (length string) '(eshell-range) string)) + +(defun eshell-parse-range-token () + "Parse a range token. +This separates two integers (possibly as dollar expansions) and denotes +a half-open range." + (when (and (not eshell-current-quoted) + (looking-at (rx "..")) + (or (eshell-arg-delimiter (match-end 0)) + (save-excursion + (goto-char (match-end 0)) + (looking-at (eshell--after-range-token-regexp))))) + ;; If we parse multiple range tokens for a single argument, then + ;; they can't actually be range tokens. Unmark the result to + ;; indicate this. + (when (memq eshell--range-token + (if eshell-arg-listified + eshell-current-argument + (list eshell-current-argument))) + (add-hook 'eshell-current-modifiers #'eshell-unmark-range-token)) + (forward-char 2) + eshell--range-token)) + (defun eshell-parse-non-special () "Parse any non-special characters, depending on the current context." (when (looking-at (if eshell-current-quoted diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index de3f86ccae4..57dd1353aab 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -369,6 +369,35 @@ unchanged." (string-to-number string) string)) +(cl-defstruct (eshell-range + (:constructor nil) + (:constructor eshell-range-create (begin end))) + "A half-open range from BEGIN to END." + begin end) + +(defsubst eshell--range-string-p (string) + "Return non-nil if STRING has been marked as a range." + (and (stringp string) + (text-property-any 0 (length string) 'eshell-range t string))) + +(defun eshell--string-to-range (string) + "Convert STRING to an `eshell-range' object." + (let* ((startpos (text-property-any 0 (length string) 'eshell-range t string)) + (endpos (next-single-property-change startpos 'eshell-range + string (length string))) + range-begin range-end) + (unless (= startpos 0) + (setq range-begin (substring string 0 startpos)) + (unless (eshell--numeric-string-p range-begin) + (user-error "range begin `%s' is not a number" range-begin)) + (setq range-begin (string-to-number range-begin))) + (unless (= endpos (length string)) + (setq range-end (substring string endpos)) + (unless (eshell--numeric-string-p range-end) + (user-error "range end `%s' is not a number" range-end)) + (setq range-end (string-to-number range-end))) + (eshell-range-create range-begin range-end))) + (defun eshell-convert (string &optional to-string) "Convert STRING into a more-native Lisp object. If TO-STRING is non-nil, always return a single string with diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 35f7ab9492d..f46f5ef839c 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -641,24 +641,13 @@ in the cons is nil. Otherwise (including if INDEX is not a string), return the original value of INDEX." - (save-match-data - (cond - ((and (stringp index) (get-text-property 0 'number index)) - (string-to-number index)) - ((and (stringp index) - (not (text-property-any 0 (length index) 'escaped t index)) - (string-match (rx string-start - (group-n 1 (? (regexp eshell-integer-regexp))) - ".." - (group-n 2 (? (regexp eshell-integer-regexp))) - string-end) - index)) - (let ((begin (match-string 1 index)) - (end (match-string 2 index))) - (cons (unless (string-empty-p begin) (string-to-number begin)) - (unless (string-empty-p end) (string-to-number end))))) - (t - index)))) + (cond + ((eshell--numeric-string-p index) + (string-to-number index)) + ((eshell--range-string-p index) + (eshell--string-to-range index)) + (t + index))) (defun eshell-eval-indices (indices) "Evaluate INDICES, a list of index-lists generated by `eshell-parse-indices'." @@ -795,14 +784,6 @@ For example, to retrieve the second element of a user's record in (push (eshell-index-value value ref) new-value)) (setq value (nreverse new-value))))))) -(pcase-defmacro eshell-index-range (start end) - "A pattern that matches an Eshell index range. -EXPVAL should be a cons cell, with each slot containing either an -integer or nil. If this matches, bind the values of the sltos to -START and END." - (list '\` (cons (list '\, `(and (or (pred integerp) (pred null)) ,start)) - (list '\, `(and (or (pred integerp) (pred null)) ,end))))) - (defun eshell-index-value (value index) "Reference VALUE using the given INDEX." (let ((parsed-index (eshell-parse-index index))) @@ -810,15 +791,17 @@ START and END." (pcase parsed-index ((pred integerp) (ring-ref value parsed-index)) - ((eshell-index-range start end) + ((pred eshell-range-p) (let* ((len (ring-length value)) - (real-start (mod (or start 0) len)) + (begin (eshell-range-begin parsed-index)) + (end (eshell-range-end parsed-index)) + (real-begin (mod (or begin 0) len)) (real-end (mod (or end len) len))) (when (and (eq real-end 0) (not (eq end 0))) (setq real-end len)) (ring-convert-sequence-to-ring - (seq-subseq (ring-elements value) real-start real-end)))) + (seq-subseq (ring-elements value) real-begin real-end)))) (_ (error "Invalid index for ring: %s" index))) (pcase parsed-index @@ -826,8 +809,9 @@ START and END." (when (< parsed-index 0) (setq parsed-index (+ parsed-index (length value)))) (seq-elt value parsed-index)) - ((eshell-index-range start end) - (seq-subseq value (or start 0) end)) + ((pred eshell-range-p) + (seq-subseq value (or (eshell-range-begin parsed-index) 0) + (eshell-range-end parsed-index))) (_ ;; INDEX is some non-integer value, so treat VALUE as an alist. (cdr (assoc parsed-index value))))))) diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 38f90e615a8..2f8ac32b0b5 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -35,6 +35,8 @@ default-directory)))) (defvar eshell-test-value nil) +(defvar eshell-test-begin nil) +(defvar eshell-test-end nil) ;;; Tests: @@ -111,7 +113,11 @@ nil, use FUNCTION instead." (eshell-command-result-equal "echo $eshell-test-value[1..4 -2..]" (list (funcall range-function '("one" "two" "three")) - (funcall range-function '("three" "four")))))) + (funcall range-function '("three" "four")))) + (let ((eshell-test-begin 1) (eshell-test-end 4)) + (eshell-command-result-equal + "echo $eshell-test-value[$eshell-test-begin..$eshell-test-end]" + (funcall range-function '("one" "two" "three")))))) (ert-deftest esh-var-test/interp-var-indices/list () "Interpolate list variable with indices." commit 4d69d3778a51427654965cbcc5bb03611034b656 Author: Jim Porter Date: Sun Oct 20 15:30:19 2024 -0700 Add QUOTED argument to 'eshell-stringify' This will make it easier to reconstitute numbers that we converted to strings. * lisp/eshell/esh-util.el (eshell--numeric-string-p): New function. (eshell-stringify, eshell-stringify-list): Add QUOTED argument. (eshell-convert, eshell-list-to-string): Stringify as quoted. * lisp/eshell/esh-arg.el (eshell--numberlike-p): Remove. (eshell-concat-1): Pass along QUOTED. * lisp/eshell/esh-cmd.el (eshell-lisp-command): Use 'eshell--numeric-string-p'. * lisp/eshell/esh-var.el (eshell-parse-variable): * lisp/eshell/em-cmpl.el (eshell-complete-parse-arguments): Stringify as quoted. diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index 4c79f7b187a..ef931db62b2 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -444,7 +444,7 @@ to writing a completion function." ('nil (propertize "" 'pcomplete-arg-value arg)) (_ - (propertize (eshell-stringify arg) + (propertize (eshell-stringify arg t) 'pcomplete-arg-value arg)))) args) posns))) diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index ebecb279753..55a40f0af3d 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -239,19 +239,16 @@ would produce (\"abc\" \"d\")." (t (setq result (eshell-concat-1 quoted result i)))))))) -(defsubst eshell--numberlike-p (object) - (or (numberp object) - (and (stringp object) (get-text-property 0 'number object)))) - (defun eshell-concat-1 (quoted first second) "Concatenate FIRST and SECOND. If QUOTED is nil and either FIRST or SECOND are numberlike, try to mark the result as a number as well." - (let ((result (concat (eshell-stringify first) (eshell-stringify second)))) + (let ((result (concat (eshell-stringify first quoted) + (eshell-stringify second quoted)))) (remove-text-properties 0 (length result) '(number) result) (when (and (not quoted) - (or (eshell--numberlike-p first) - (eshell--numberlike-p second))) + (or (numberp first) (eshell--numeric-string-p first) + (numberp second) (eshell--numeric-string-p second))) (eshell-mark-numeric-string result)) result)) diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 4156d208930..11fa9fc6122 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -1577,9 +1577,7 @@ a string naming a Lisp function." (while args (let ((arg (car args))) (cond - ((and numeric (stringp arg) (> (length arg) 0) - (text-property-any 0 (length arg) - 'number t arg)) + ((and numeric (eshell--numeric-string-p arg)) ;; If any of the arguments are flagged as ;; numbers waiting for conversion, convert ;; them now. diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 65e19228e0e..de3f86ccae4 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -353,6 +353,12 @@ See `eshell-convertible-to-number-p'." (eshell--do-mark-numeric-string string)) string) +(defsubst eshell--numeric-string-p (string) + "Return non-nil if STRING has been marked as numeric." + (and (stringp string) + (length> string 0) + (not (text-property-not-all 0 (length string) 'number t string)))) + (defun eshell-convert-to-number (string) "Try to convert STRING to a number. If STRING doesn't look like a number (or @@ -377,7 +383,7 @@ trailing newlines removed. Otherwise, this behaves as follows: (cond ((not (stringp string)) (if to-string - (eshell-stringify string) + (eshell-stringify string t) string)) (to-string (string-trim-right string "\n+")) (t (let ((len (length string))) @@ -499,25 +505,27 @@ Prepend remote identification of `default-directory', if any." (define-obsolete-function-alias 'eshell-flatten-list #'flatten-tree "27.1") -(defun eshell-stringify (object) +(defun eshell-stringify (object &optional quoted) "Convert OBJECT into a string value." (cond ((stringp object) object) ((numberp object) - (number-to-string object)) + (if quoted + (number-to-string object) + (propertize (number-to-string object) 'number t))) ((and (eq object t) (not eshell-stringify-t)) nil) (t (string-trim-right (pp-to-string object))))) -(defsubst eshell-stringify-list (args) +(defsubst eshell-stringify-list (args &optional quoted) "Convert each element of ARGS into a string value." - (mapcar #'eshell-stringify args)) + (mapcar (lambda (i) (eshell-stringify i quoted)) args)) (defsubst eshell-list-to-string (list) "Convert LIST into a single string separated by spaces." - (mapconcat #'eshell-stringify list " ")) + (mapconcat (lambda (i) (eshell-stringify i t)) list " ")) (defsubst eshell-flatten-and-stringify (&rest args) "Flatten and stringify all of the ARGS into a single string." diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index dc0bc4532de..35f7ab9492d 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -495,7 +495,7 @@ process any indices that come after the variable reference." (if splice (setq value `(eshell-list-to-string ,value) splice nil) - (setq value `(eshell-stringify ,value)))) + (setq value `(eshell-stringify ,value t)))) (setq value `(eshell-escape-arg ,value)) (when splice (setq value `(eshell-splice-args ,value))) commit 08d5994b435c119bde8b8ac8f7152810d1814d1e Author: Jim Porter Date: Sun Nov 3 11:22:27 2024 -0800 Improve handling of Eshell "for" loops This fixes some errors with more-complex string forms, and also allows iterating over sequences other than just lists. * lisp/eshell/esh-cmd.el (eshell-for-iterate): New function... (eshell-rewrite-for-command): ... use it. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop): Test multiple values. (esh-cmd-test/for-loop-string, esh-cmd-test/for-loop-vector): New tests. (esh-cmd-test/for-loop-mixed-args): Rename. * test/lisp/eshell/esh-proc-tests.el (esh-proc-test/sentinel/change-buffer): Make sure all the processes get cleaned up. diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 2b1666a7293..4156d208930 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -526,6 +526,20 @@ the second is ignored." (defvar eshell--local-vars nil "List of locally bound vars that should take precedence over env-vars.") +(iter-defun eshell-for-iterate (&rest args) + "Iterate over the elements of each sequence in ARGS. +If ARGS is not a sequence, treat it as a list of one element." + (dolist (arg args) + (cond + ((stringp arg) + (iter-yield arg)) + ((listp arg) + (dolist (i arg) (iter-yield i))) + ((arrayp arg) + (dotimes (i (length arg)) (iter-yield (aref arg i)))) + (t + (iter-yield arg))))) + (defun eshell-rewrite-for-command (terms) "Rewrite a `for' command into its equivalent Eshell command form. Because the implementation of `for' relies upon conditional evaluation @@ -533,23 +547,14 @@ of its argument (i.e., use of a Lisp special form), it must be implemented via rewriting, rather than as a function." (if (and (equal (car terms) "for") (equal (nth 2 terms) "in")) - (let ((for-items (make-symbol "for-items")) + (let ((iter-symbol (intern (nth 1 terms))) (body (car (last terms)))) (setcdr (last terms 2) nil) - `(let ((,for-items - (append - ,@(mapcar - (lambda (elem) - (if (listp elem) - (eshell-term-as-value elem) - `(list ,elem))) - (nthcdr 3 terms))))) - (while ,for-items - (let ((,(intern (cadr terms)) (car ,for-items)) - (eshell--local-vars (cons ',(intern (cadr terms)) - eshell--local-vars))) - ,body) - (setq ,for-items (cdr ,for-items))))))) + `(let ((eshell--local-vars (cons ',iter-symbol eshell--local-vars))) + (iter-do (,iter-symbol (eshell-for-iterate + ,@(mapcar #'eshell-term-as-value + (nthcdr 3 terms)))) + ,body))))) (defun eshell-structure-basic-command (func names keyword test &rest body) "With TERMS, KEYWORD, and two NAMES, structure a basic command. diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index 8b68013c60d..ae1aed59b45 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -319,8 +319,15 @@ processes correctly." (ert-deftest esh-cmd-test/for-loop () "Test invocation of a for loop." (with-temp-eshell - (eshell-match-command-output "for i in 5 { echo $i }" - "5\n"))) + (eshell-match-command-output "for i in 1 2 { echo $i }" + "1\n2\n"))) + +(ert-deftest esh-cmd-test/for-loop-string () + "Test invocation of a for loop with complex string arguments." + (let ((eshell-test-value "X")) + (with-temp-eshell + (eshell-match-command-output "for i in a b$eshell-test-value { echo $i }" + "a\nbX\n")))) (ert-deftest esh-cmd-test/for-loop-list () "Test invocation of a for loop iterating over a list." @@ -328,7 +335,13 @@ processes correctly." (eshell-match-command-output "for i in (list 1 2 (list 3 4)) { echo $i }" "1\n2\n(3 4)\n"))) -(ert-deftest esh-cmd-test/for-loop-multiple-args () +(ert-deftest esh-cmd-test/for-loop-vector () + "Test invocation of a for loop iterating over a vector." + (with-temp-eshell + (eshell-match-command-output "for i in `[1 2 3] { echo $i }" + "1\n2\n3\n"))) + +(ert-deftest esh-cmd-test/for-loop-mixed-args () "Test invocation of a for loop iterating over multiple arguments." (with-temp-eshell (eshell-match-command-output "for i in 1 2 (list 3 4) { echo $i }" @@ -348,13 +361,6 @@ processes correctly." "echo $name; for name in 3 { echo $name }; echo $name" "env-value\n3\nenv-value\n")))) -(ert-deftest esh-cmd-test/for-loop-for-items-shadow () - "Test that the variable `for-items' isn't shadowed inside for loops." - (with-temp-eshell - (with-no-warnings (setq-local for-items "hello")) - (eshell-match-command-output "for i in 1 { echo $for-items }" - "hello\n"))) - (ert-deftest esh-cmd-test/for-loop-lisp-body () "Test invocation of a for loop with a Lisp body form." (with-temp-eshell diff --git a/test/lisp/eshell/esh-proc-tests.el b/test/lisp/eshell/esh-proc-tests.el index 3121e751006..973d9ccc213 100644 --- a/test/lisp/eshell/esh-proc-tests.el +++ b/test/lisp/eshell/esh-proc-tests.el @@ -135,16 +135,19 @@ (ert-deftest esh-proc-test/sentinel/change-buffer () "Check that changing the current buffer while running a command works. See bug#71778." - (eshell-with-temp-buffer bufname "" - (with-temp-eshell - (let (eshell-test-value) - (eshell-insert-command - (concat (format "for i in 1 2 {sleep 1; echo hello} > #<%s>; " bufname) - "setq eshell-test-value t")) - (with-current-buffer bufname - (eshell-wait-for (lambda () eshell-test-value)) - (should (equal (buffer-string) "hellohello"))) - (eshell-match-command-output "echo goodbye" "\\`goodbye\n"))))) + (let ((starting-process-list (process-list))) + (eshell-with-temp-buffer bufname "" + (with-temp-eshell + (let (eshell-test-value) + (eshell-insert-command + (concat (format "for i in 1 2 {sleep 1; echo hello} > #<%s>; " + bufname) + "setq eshell-test-value t")) + (with-current-buffer bufname + (eshell-wait-for (lambda () eshell-test-value)) + (should (equal (buffer-string) "hellohello"))) + (should (equal (process-list) starting-process-list)) + (eshell-match-command-output "echo goodbye" "\\`goodbye\n")))))) ;; Pipelines commit b3c82f939c3ca35bd43e9a9a22b0f9d3e3fa29f2 Author: Stefan Kangas Date: Sun Nov 3 16:13:06 2024 +0100 Mark IDLWAVE as obsolete * lisp/obsolete/idlw-complete-structtag.el: * lisp/obsolete/idlw-help.el: * lisp/obsolete/idlw-shell.el: * lisp/obsolete/idlw-toolbar.el: * lisp/obsolete/idlwave.el: Mark as obsolete. (Bug#71157) * lisp/files.el (auto-mode-alist): Remove IDLWAVE entry. * doc/emacs/programs.texi (Program Modes): Remove IDLWAVE from list of supported languages. diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index 948f4128acf..24e043e2c1c 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -84,7 +84,6 @@ mode for the C programming language is @code{c-mode}. @cindex Javascript mode @cindex Awk mode @cindex C# mode -@cindex IDLWAVE mode @cindex JSON mode @cindex SQL mode @cindex TypeScript mode @@ -94,7 +93,7 @@ mode for the C programming language is @code{c-mode}. @cindex TOML mode Emacs has programming language modes for Lisp, Scheme, the Scheme-based DSSSL expression language, Ada, ASM, AWK, C, C++, C#, -Elixir, Fortran, Icon, IDL (CORBA), HEEx, IDLWAVE, Java, Javascript, +Elixir, Fortran, Icon, IDL (CORBA), HEEx, Java, Javascript, Lua, M4, Makefiles, Metafont (@TeX{}'s companion for font creation), Modula2, Object Pascal, Objective-C, Octave, Pascal, Perl, PHP, Pike, PostScript, Prolog, Python, Ruby, Simula, SQL, Tcl, TypeScript, Verilog, @@ -141,10 +140,9 @@ For instance, entering C mode runs the hooks @code{prog-mode-hook} and @code{c-mode-hook}. @xref{Hooks}, for information about hooks. @ifnottex - Separate manuals are available for the modes for Ada (@pxref{Top,, -Ada Mode, ada-mode, Ada Mode}), C/C++/Objective C/Java/Corba -IDL/Pike/AWK (@pxref{Top, , CC Mode, ccmode, CC Mode}), Octave, VHDL, -and IDLWAVE (@pxref{Top,, IDLWAVE, idlwave, IDLWAVE User Manual}). + Separate manuals are available for the modes for Ada (@pxref{Top,, Ada +Mode, ada-mode, Ada Mode}), C/C++/Objective C/Java/Corba IDL/Pike/AWK +(@pxref{Top, , CC Mode, ccmode, CC Mode}), Octave, and VHDL. @end ifnottex @iftex The Emacs distribution contains Info manuals for the major modes for diff --git a/etc/NEWS b/etc/NEWS index e6fbe30178c..41a76d1cd95 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -149,6 +149,11 @@ Killed buffers stored in a register using 'buffer-to-register' are automatically converted to a file-query value if the buffer was visiting a file. +** IDLWAVE has been moved to GNU ELPA. +The version bundled with Emacs is out-of-date, and is now marked as +obsolete. Use 'M-x list-packages' to install the 'idlwave' package from +GNU ELPA instead. + * Editing Changes in Emacs 31.1 diff --git a/lisp/files.el b/lisp/files.el index 54f2397ee37..bffdaa288a5 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3052,8 +3052,6 @@ since only a single case-insensitive search through the alist is made." ;; Anyway, the following extensions are supported by gfortran. ("\\.f9[05]\\'" . f90-mode) ("\\.f0[38]\\'" . f90-mode) - ("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode - ("\\.\\(pro\\|PRO\\)\\'" . idlwave-mode) ("\\.srt\\'" . srecode-template-mode) ("\\.prolog\\'" . prolog-mode) ("\\.tar\\'" . tar-mode) diff --git a/lisp/obsolete/idlw-complete-structtag.el b/lisp/obsolete/idlw-complete-structtag.el index bcc2ee2f005..b1e8a891c18 100644 --- a/lisp/obsolete/idlw-complete-structtag.el +++ b/lisp/obsolete/idlw-complete-structtag.el @@ -7,6 +7,7 @@ ;; Old-Version: 1.2 ;; Keywords: languages ;; Package: idlwave +;; Obsolete-since: 31.1 ;; This file is part of GNU Emacs. @@ -25,6 +26,11 @@ ;;; Commentary: +;; NOTE: IDLWAVE has been moved to GNU ELPA. The version bundled with +;; Emacs is out-of-date, marked as obsolete, and will be removed +;; in a future release. Please use `M-x package-list' to install +;; IDLWAVE from GNU ELPA instead of using this version. + ;; Completion of structure tags can be done automatically in the ;; shell, since the list of tags can be determined dynamically through ;; interaction with IDL. diff --git a/lisp/obsolete/idlw-help.el b/lisp/obsolete/idlw-help.el index c311e1c5377..3fc654407b3 100644 --- a/lisp/obsolete/idlw-help.el +++ b/lisp/obsolete/idlw-help.el @@ -6,6 +6,7 @@ ;; Carsten Dominik ;; Maintainer: emacs-devel@gnu.org ;; Package: idlwave +;; Obsolete-since: 31.1 ;; This file is part of GNU Emacs. @@ -24,6 +25,11 @@ ;;; Commentary: +;; NOTE: IDLWAVE has been moved to GNU ELPA. The version bundled with +;; Emacs is out-of-date, marked as obsolete, and will be removed +;; in a future release. Please use `M-x package-list' to install +;; IDLWAVE from GNU ELPA instead of using this version. + ;; The help link information for IDLWAVE's online help feature for ;; system routines is extracted automatically from the IDL ;; documentation, and is available, along with general routine diff --git a/lisp/obsolete/idlw-shell.el b/lisp/obsolete/idlw-shell.el index b5d91f46b17..2abf4b5e6dc 100644 --- a/lisp/obsolete/idlw-shell.el +++ b/lisp/obsolete/idlw-shell.el @@ -8,6 +8,7 @@ ;; Maintainer: emacs-devel@gnu.org ;; Keywords: processes ;; Package: idlwave +;; Obsolete-since: 31.1 ;; This file is part of GNU Emacs. @@ -25,7 +26,12 @@ ;; along with GNU Emacs. If not, see . ;;; Commentary: -;; + +;; NOTE: IDLWAVE has been moved to GNU ELPA. The version bundled with +;; Emacs is out-of-date, marked as obsolete, and will be removed +;; in a future release. Please use `M-x package-list' to install +;; IDLWAVE from GNU ELPA instead of using this version. + ;; This mode is for IDL version 5 or later. ;; ;; Runs IDL as an inferior process of Emacs, much like the Emacs diff --git a/lisp/obsolete/idlw-toolbar.el b/lisp/obsolete/idlw-toolbar.el index c6cb47baa40..4e7d336ec31 100644 --- a/lisp/obsolete/idlw-toolbar.el +++ b/lisp/obsolete/idlw-toolbar.el @@ -6,6 +6,7 @@ ;; Maintainer: emacs-devel@gnu.org ;; Keywords: processes ;; Package: idlwave +;; Obsolete-since: 31.1 ;; This file is part of GNU Emacs. @@ -24,6 +25,11 @@ ;;; Commentary: +;; NOTE: IDLWAVE has been moved to GNU ELPA. The version bundled with +;; Emacs is out-of-date, marked as obsolete, and will be removed +;; in a future release. Please use `M-x package-list' to install +;; IDLWAVE from GNU ELPA instead of using this version. + ;; This file implements a debugging toolbar for IDLWAVE. ;; It requires toolbar and xpm support. diff --git a/lisp/obsolete/idlwave.el b/lisp/obsolete/idlwave.el index 02d1dacd89a..b456a542d35 100644 --- a/lisp/obsolete/idlwave.el +++ b/lisp/obsolete/idlwave.el @@ -8,6 +8,7 @@ ;; Maintainer: emacs-devel@gnu.org ;; Version: 6.1.22 ;; Keywords: languages +;; Obsolete-since: 31.1 ;; This file is part of GNU Emacs. @@ -26,6 +27,11 @@ ;;; Commentary: +;; NOTE: IDLWAVE has been moved to GNU ELPA. The version bundled with +;; Emacs is out-of-date, marked as obsolete, and will be removed +;; in a future release. Please use `M-x package-list' to install +;; IDLWAVE from GNU ELPA instead of using this version. + ;; IDLWAVE enables feature-rich development and interaction with IDL, ;; the Interactive Data Language. It provides a compelling, ;; full-featured alternative to the IDLDE development environment commit 75c5aaae893b932c122d8855b0908f2b76e28c1a Author: Stefan Kangas Date: Sun Nov 3 07:23:22 2024 +0100 Move IDLWAVE to lisp/obsolete * lisp/progmodes/idlw-complete-structtag.el: * lisp/progmodes/idlw-help.el: * lisp/progmodes/idlw-shell.el: * lisp/progmodes/idlw-toolbar.el: * lisp/progmodes/idlwave.el: Move from here... * lisp/obsolete/idlw-complete-structtag.el * lisp/obsolete/idlw-help.el * lisp/obsolete/idlw-shell.el * lisp/obsolete/idlw-toolbar.el * lisp/obsolete/idlwave.el: ...to here. (Bug#71157) diff --git a/lisp/progmodes/idlw-complete-structtag.el b/lisp/obsolete/idlw-complete-structtag.el similarity index 100% rename from lisp/progmodes/idlw-complete-structtag.el rename to lisp/obsolete/idlw-complete-structtag.el diff --git a/lisp/progmodes/idlw-help.el b/lisp/obsolete/idlw-help.el similarity index 100% rename from lisp/progmodes/idlw-help.el rename to lisp/obsolete/idlw-help.el diff --git a/lisp/progmodes/idlw-shell.el b/lisp/obsolete/idlw-shell.el similarity index 100% rename from lisp/progmodes/idlw-shell.el rename to lisp/obsolete/idlw-shell.el diff --git a/lisp/progmodes/idlw-toolbar.el b/lisp/obsolete/idlw-toolbar.el similarity index 100% rename from lisp/progmodes/idlw-toolbar.el rename to lisp/obsolete/idlw-toolbar.el diff --git a/lisp/progmodes/idlwave.el b/lisp/obsolete/idlwave.el similarity index 100% rename from lisp/progmodes/idlwave.el rename to lisp/obsolete/idlwave.el commit 378661dcd6d49e16f653d3eb6b676f0bcea0923b Author: Stefan Kangas Date: Sun Nov 3 07:22:20 2024 +0100 ; Whitespace fix in idlwave.el diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el index b3e9eb58196..02d1dacd89a 100644 --- a/lisp/progmodes/idlwave.el +++ b/lisp/progmodes/idlwave.el @@ -3900,7 +3900,7 @@ you specify /." "sh" nil errbuf nil "-c" (concat cmd append item))) 0 - 1))) + 1))) ;; ;; Append additional tags (setq append " --append ") @@ -4610,7 +4610,7 @@ Gets set in cached XML rinfo, or `idlw-rinfo.el'.") (if (setq master-elt (assoc master-link linkfiles)) (if (eq (car linkfiles) master-elt) linkfiles - (cons master-elt (delq master-elt linkfiles))) + (cons master-elt (delq master-elt linkfiles))) (push (list master-link) linkfiles)))) (defun idlwave-convert-xml-clean-statement-aliases (aliases) @@ -6326,7 +6326,7 @@ ARROW: Location of the arrow" (idlwave-routines) (let* (;(bos (save-excursion (idlwave-beginning-of-statement) (point))) (bos (save-excursion (idlwave-start-of-substatement 'pre) (point))) - (func-entry (idlwave-what-function bos)) + (func-entry (idlwave-what-function bos)) (func (car func-entry)) (func-class (nth 1 func-entry)) (func-arrow (nth 2 func-entry)) commit 53f0151518c767bb97dc90fea63efb37d8311dd2 Author: Andrea Corallo Date: Sun Nov 3 15:32:28 2024 +0100 * Remove warning introduced by 8e7f5f97db6 * lisp/term/w32-win.el (w32--get-clipboard-data-media): Declare. diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index b5c909f4a4e..7579608ac22 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -488,6 +488,8 @@ also be textual." (mapconcat #'identity w32--textual-mime-types "\\|") (symbol-name mime-type))) +(declare-function w32--get-clipboard-data-media "w32select.c") + (defun w32--get-selection (&optional type data-type) (cond ((and (eq type 'CLIPBOARD) (eq data-type 'STRING)) commit 8e7f5f97db647ce6e9606364dc15d8bbd7ef6016 Author: Cecilio Pardo Date: Mon Oct 28 22:18:13 2024 +0100 Add support for 'yank-media' on MS-Windows Adds the capacity to handle types different from strings to the clipboard management functions on MS-Windows, and some logic required to convert media types names and content to be what yank-media and the modes that use it expect (bug#71909). * lisp/term/w32-win.el (w32--selection-target-translations): New variable that holds the name translations for media types. (w32--translate-selection-target): New function, translate the name of a media type. (w32--translate-reverse-selection-target): New function, reverse translation. (w32--get-selection): Modified to translate target names when asked for targets, and retrieve media types when asked for them. (w32--mime-type-textual-p): New function, checks if a MIME type is textual. * lisp/textmodes/sgml-mode.el (html-mode--image-yank-handler): Fixed the image save mechanism, that added line feed characters on MS-Windows, breaking binary formats. * src/w32image.c (gdiplus_init): Modified to fetch more functions fromm gdiplus. (get_encoder_clsid): Renamed to 'w32_gdip_get_encoder_clsid' and made nonstatic. (gdiplus_startup): Renamed to 'w32_gdiplus_startup' and made nonstatic. * src/w32select.c (stdfmt_name): Made global, was static function. (convert_dibv5_to_png): New function to convert DIBV5 clipboard format to PNG. (get_clipboard_format_name): New function get the name of a format given its index. (Fw32__get_clipboard_data_media): New function, retrieves and converts media content. (syms_of_w32select): Export new lisp functions. * src/w32gdiplus.h: New file, for definitions in w32image.c * doc/lispref/frames.texi: Updated with MS-Windows support. * etc/NEWS: Added entry about new feature. diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 1b463eb51e5..bf4d5c05f3a 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -4759,14 +4759,14 @@ to encoding or decoding by any coding system. @section Yanking Media @cindex yank media from window-system selections - Data saved within window system selections is not restricted to -plain text. It is possible for selection data to encompass images or -other binary data of the like, as well as rich text content instanced -by HTML, and also PostScript. Since the selection data types incident -to this data are at variance with those for plain text, the insertion -of such data is facilitated by a set of functions dubbed -@dfn{yank-media handlers}, which are registered by each major mode -undertaking its insertion and called where warranted upon the + Data saved within window system selections and the MS-Windows +clipboard is not restricted to plain text. It is possible for selection +data to encompass images or other binary data of the like, as well as +rich text content instanced by HTML, and also PostScript. Since the +selection data types incident to this data are at variance with those +for plain text, the insertion of such data is facilitated by a set of +functions dubbed @dfn{yank-media handlers}, which are registered by each +major mode undertaking its insertion and called where warranted upon the execution of the @code{yank-media} command. @defun yank-media-handler types handler diff --git a/etc/NEWS b/etc/NEWS index 11c9cf397c9..e6fbe30178c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -820,6 +820,12 @@ DirectWrite rendering parameters. To show color Emoji in Emacs, customize the default fontset to use a color Emoji font installed on your system for the 'emoji' script. ++++ +** Emacs on MS-Windows now supports 'yank-media'. +This command inserts clipboard data of different formats into the +current buffer, if the major mode supports it. + + ---------------------------------------------------------------------- This file is part of GNU Emacs. diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index 75f8530010c..b5c909f4a4e 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -442,15 +442,82 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.") (w32-set-clipboard-data (string-replace "\0" "\\0" value)) (put 'x-selections (or type 'PRIMARY) value))) -(defun w32--get-selection (&optional type data-type) +(defvar w32--selection-target-translations + '((PNG . image/png) + (DIBV5 . image/png) + (HTML\ Format . text/html))) + +(defun w32--translate-selection-target (target) + (let ((xlat (assoc target w32--selection-target-translations))) + (if xlat + (cdr xlat) + target))) + +(defun w32--translate-reverse-selection-target (target) + (append + (mapcar #'car + (seq-filter + (lambda (x) + (eq target + (w32--translate-selection-target (car x)))) + w32--selection-target-translations)) + (list target))) + +(defvar w32--textual-mime-types + '("application/xml" + "application/json" + "application/yaml" + "application/json-seq" + "\\`text/" + "+xml\\'" + "+json\\'" + "+yaml\\'" + "+json-seq\\'")) + +(defun w32--mime-type-textual-p (mime-type) + "Returns t if MIME-TYPE, a symbol, names a textual MIME type. + +This function is intended to classify clipboard data. All MIME subtypes +of text/ are considered textual. Also those with suffixes +xml, +json, ++yaml, +json-seq. And application/xml, application/json, +application/yaml, application/json-seq. + +This classification is not exhaustive. Some MIME types not listed may +also be textual." + (string-match-p + (mapconcat #'identity w32--textual-mime-types "\\|") + (symbol-name mime-type))) + +(defun w32--get-selection (&optional type data-type) (cond ((and (eq type 'CLIPBOARD) (eq data-type 'STRING)) (with-demoted-errors "w32-get-clipboard-data:%S" (w32-get-clipboard-data))) ((eq data-type 'TARGETS) (if (eq type 'CLIPBOARD) - (w32-selection-targets type) + (vconcat + (delete-dups + (seq-map #'w32--translate-selection-target + (w32-selection-targets type)))) (if (get 'x-selections (or type 'PRIMARY)) '[STRING]))) + ((eq type 'CLIPBOARD) + (let ((tmp-file (make-temp-file "emacs-clipboard")) + (is-textual (w32--mime-type-textual-p data-type))) + (unwind-protect + (let* ((data-types (w32--translate-reverse-selection-target data-type)) + (data (w32--get-clipboard-data-media data-types tmp-file is-textual))) + (cond + ;; data is in the file + ((eq data t) + (with-temp-buffer + (set-buffer-multibyte nil) + (insert-file-contents-literally tmp-file) + (buffer-string))) + ;; data is in data var + ((stringp data) data) + ;; No data + (t nil))) + (delete-file tmp-file)))) (t (get 'x-selections (or type 'PRIMARY))))) (defun w32--selection-owner-p (selection) diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el index cc86294df09..fad7008adc0 100644 --- a/lisp/textmodes/sgml-mode.el +++ b/lisp/textmodes/sgml-mode.el @@ -2476,10 +2476,9 @@ To work around that, do: (when (and (file-exists-p file) (not (yes-or-no-p (format "%s exists; overwrite?" file)))) (user-error "%s exists" file)) - (with-temp-buffer - (set-buffer-multibyte nil) - (insert image) - (write-region (point-min) (point-max) file)) + (let ((coding-system-for-write 'emacs-internal)) + (with-temp-file file + (insert image))) (insert (format "\n" (file-relative-name file))) (insert-image (create-image file (mailcap-mime-type-to-extension type) nil diff --git a/src/w32gdiplus.h b/src/w32gdiplus.h new file mode 100644 index 00000000000..9d05ae6c190 --- /dev/null +++ b/src/w32gdiplus.h @@ -0,0 +1,112 @@ +#ifdef WINDOWSNT +typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) + (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); +typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); +typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) + (GpImage *, PROPID, UINT *); +typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) + (GpImage *, PROPID, UINT, PropertyItem *); +typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc) + (GpImage *, UINT *); +typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc) + (GpImage *, GUID *, UINT); +typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc) + (GpImage *, GDIPCONST GUID *, UINT *); +typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc) + (GpImage*, GDIPCONST GUID *, UINT); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc) + (WCHAR *, GpBitmap **); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc) + (IStream *, GpBitmap **); +typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromScan0_Proc) + (INT, INT, INT, PixelFormat, BYTE*, GpBitmap**); +typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); +typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) + (GpBitmap *, HBITMAP *, ARGB); +typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *); +typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *); +typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *); +typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *); +typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc) + (UINT, UINT, ImageCodecInfo *); +typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc) + (GDIPCONST WCHAR *,GpImage **); +typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc) + (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *); +typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc) + (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *, + GDIPCONST EncoderParameters *); +typedef GpStatus (WINGDIPAPI *GdipImageRotateFlip_Proc) + (GpImage *image, RotateFlipType rfType); + +extern GdiplusStartup_Proc fn_GdiplusStartup; +extern GdiplusShutdown_Proc fn_GdiplusShutdown; +extern GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; +extern GdipGetPropertyItem_Proc fn_GdipGetPropertyItem; +extern GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount; +extern GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList; +extern GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount; +extern GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; +extern GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; +extern GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; +extern GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; +extern SHCreateMemStream_Proc fn_SHCreateMemStream; +extern GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; +extern GdipDisposeImage_Proc fn_GdipDisposeImage; +extern GdipGetImageHeight_Proc fn_GdipGetImageHeight; +extern GdipGetImageWidth_Proc fn_GdipGetImageWidth; +extern GdipGetImageEncodersSize_Proc fn_GdipGetImageEncodersSize; +extern GdipGetImageEncoders_Proc fn_GdipGetImageEncoders; +extern GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; +extern GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; +extern GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; +extern GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; + +# undef GdiplusStartup +# undef GdiplusShutdown +# undef GdipGetPropertyItemSize +# undef GdipGetPropertyItem +# undef GdipImageGetFrameDimensionsCount +# undef GdipImageGetFrameDimensionsList +# undef GdipImageGetFrameCount +# undef GdipImageSelectActiveFrame +# undef GdipCreateBitmapFromFile +# undef GdipCreateBitmapFromStream +# undef GdipCreateBitmapFromScan0 +# undef SHCreateMemStream +# undef GdipCreateHBITMAPFromBitmap +# undef GdipDisposeImage +# undef GdipGetImageHeight +# undef GdipGetImageWidth +# undef GdipGetImageEncodersSize +# undef GdipGetImageEncoders +# undef GdipLoadImageFromFile +# undef GdipGetImageThumbnail +# undef GdipSaveImageToFile +# undef GdipSaveImageRotateFlip + +# define GdiplusStartup fn_GdiplusStartup +# define GdiplusShutdown fn_GdiplusShutdown +# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize +# define GdipGetPropertyItem fn_GdipGetPropertyItem +# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount +# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList +# define GdipImageGetFrameCount fn_GdipImageGetFrameCount +# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame +# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile +# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream +# define GdipCreateBitmapFromScan0 fn_GdipCreateBitmapFromScan0 +# define SHCreateMemStream fn_SHCreateMemStream +# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap +# define GdipDisposeImage fn_GdipDisposeImage +# define GdipGetImageHeight fn_GdipGetImageHeight +# define GdipGetImageWidth fn_GdipGetImageWidth +# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize +# define GdipGetImageEncoders fn_GdipGetImageEncoders +# define GdipLoadImageFromFile fn_GdipLoadImageFromFile +# define GdipGetImageThumbnail fn_GdipGetImageThumbnail +# define GdipSaveImageToFile fn_GdipSaveImageToFile +# define GdipImageRotateFlip fn_GdipImageRotateFlip +#endif + +int w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid); diff --git a/src/w32gui.h b/src/w32gui.h index 739a790911e..26565dcae6b 100644 --- a/src/w32gui.h +++ b/src/w32gui.h @@ -45,7 +45,9 @@ struct image; extern int w32_load_image (struct frame *f, struct image *img, Lisp_Object spec_file, Lisp_Object spec_data); extern bool w32_can_use_native_image_api (Lisp_Object); +extern bool w32_gdiplus_startup (void); extern void w32_gdiplus_shutdown (void); + extern size_t w32_image_size (Emacs_Pixmap); #define FACE_DEFAULT (~0) diff --git a/src/w32image.c b/src/w32image.c index 359a4fa3a72..44eed087528 100644 --- a/src/w32image.c +++ b/src/w32image.c @@ -38,44 +38,8 @@ along with GNU Emacs. If not, see . */ #include "frame.h" #include "coding.h" +#include "w32gdiplus.h" #ifdef WINDOWSNT - -typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc) - (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *); -typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR); -typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc) - (GpImage *, PROPID, UINT *); -typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc) - (GpImage *, PROPID, UINT, PropertyItem *); -typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc) - (GpImage *, UINT *); -typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc) - (GpImage *, GUID *, UINT); -typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc) - (GpImage *, GDIPCONST GUID *, UINT *); -typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc) - (GpImage*, GDIPCONST GUID *, UINT); -typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc) - (WCHAR *, GpBitmap **); -typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc) - (IStream *, GpBitmap **); -typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT); -typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc) - (GpBitmap *, HBITMAP *, ARGB); -typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *); -typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *); -typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *); -typedef GpStatus (WINGDIPAPI *GdipGetImageEncodersSize_Proc) (UINT *, UINT *); -typedef GpStatus (WINGDIPAPI *GdipGetImageEncoders_Proc) - (UINT, UINT, ImageCodecInfo *); -typedef GpStatus (WINGDIPAPI *GdipLoadImageFromFile_Proc) - (GDIPCONST WCHAR *,GpImage **); -typedef GpStatus (WINGDIPAPI *GdipGetImageThumbnail_Proc) - (GpImage *, UINT, UINT, GpImage**, GetThumbnailImageAbort, VOID *); -typedef GpStatus (WINGDIPAPI *GdipSaveImageToFile_Proc) - (GpImage *, GDIPCONST WCHAR *, GDIPCONST CLSID *, - GDIPCONST EncoderParameters *); - GdiplusStartup_Proc fn_GdiplusStartup; GdiplusShutdown_Proc fn_GdiplusShutdown; GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize; @@ -86,6 +50,7 @@ GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount; GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame; GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile; GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream; +GdipCreateBitmapFromScan0_Proc fn_GdipCreateBitmapFromScan0; SHCreateMemStream_Proc fn_SHCreateMemStream; GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap; GdipDisposeImage_Proc fn_GdipDisposeImage; @@ -96,6 +61,7 @@ GdipGetImageEncoders_Proc fn_GdipGetImageEncoders; GdipLoadImageFromFile_Proc fn_GdipLoadImageFromFile; GdipGetImageThumbnail_Proc fn_GdipGetImageThumbnail; GdipSaveImageToFile_Proc fn_GdipSaveImageToFile; +GdipImageRotateFlip_Proc fn_GdipImageRotateFlip; static bool gdiplus_init (void) @@ -146,6 +112,10 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream"); if (!fn_GdipCreateBitmapFromStream) return false; + fn_GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0_Proc) + get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromScan0"); + if (!fn_GdipCreateBitmapFromScan0) + return false; fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc) get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap"); if (!fn_GdipCreateHBITMAPFromBitmap) @@ -196,52 +166,14 @@ gdiplus_init (void) get_proc_addr (gdiplus_lib, "GdipSaveImageToFile"); if (!fn_GdipSaveImageToFile) return false; + fn_GdipImageRotateFlip = (GdipImageRotateFlip_Proc) + get_proc_addr (gdiplus_lib, "GdipImageRotateFlip"); + if (!fn_GdipImageRotateFlip) + return false; return true; } -# undef GdiplusStartup -# undef GdiplusShutdown -# undef GdipGetPropertyItemSize -# undef GdipGetPropertyItem -# undef GdipImageGetFrameDimensionsCount -# undef GdipImageGetFrameDimensionsList -# undef GdipImageGetFrameCount -# undef GdipImageSelectActiveFrame -# undef GdipCreateBitmapFromFile -# undef GdipCreateBitmapFromStream -# undef SHCreateMemStream -# undef GdipCreateHBITMAPFromBitmap -# undef GdipDisposeImage -# undef GdipGetImageHeight -# undef GdipGetImageWidth -# undef GdipGetImageEncodersSize -# undef GdipGetImageEncoders -# undef GdipLoadImageFromFile -# undef GdipGetImageThumbnail -# undef GdipSaveImageToFile - -# define GdiplusStartup fn_GdiplusStartup -# define GdiplusShutdown fn_GdiplusShutdown -# define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize -# define GdipGetPropertyItem fn_GdipGetPropertyItem -# define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount -# define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList -# define GdipImageGetFrameCount fn_GdipImageGetFrameCount -# define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame -# define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile -# define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream -# define SHCreateMemStream fn_SHCreateMemStream -# define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap -# define GdipDisposeImage fn_GdipDisposeImage -# define GdipGetImageHeight fn_GdipGetImageHeight -# define GdipGetImageWidth fn_GdipGetImageWidth -# define GdipGetImageEncodersSize fn_GdipGetImageEncodersSize -# define GdipGetImageEncoders fn_GdipGetImageEncoders -# define GdipLoadImageFromFile fn_GdipLoadImageFromFile -# define GdipGetImageThumbnail fn_GdipGetImageThumbnail -# define GdipSaveImageToFile fn_GdipSaveImageToFile - #endif /* WINDOWSNT */ static int gdip_initialized; @@ -252,8 +184,8 @@ static GdiplusStartupOutput output; /* Initialize GDI+, return true if successful. */ -static bool -gdiplus_startup (void) +bool +w32_gdiplus_startup (void) { GpStatus status; @@ -305,7 +237,7 @@ w32_can_use_native_image_api (Lisp_Object type) But we don't yet support these in image.c. */ return false; } - return gdiplus_startup (); + return w32_gdiplus_startup (); } enum PropertyItem_type { @@ -549,8 +481,8 @@ static struct thumb_type_data thumb_types [] = }; -static int -get_encoder_clsid (const char *type, CLSID *clsid) +int +w32_gdip_get_encoder_clsid (const char *type, CLSID *clsid) { /* A simple cache based on the assumptions that many thumbnails will be generated using the same TYPE. */ @@ -625,7 +557,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) if (!gdiplus_started) { - if (!gdiplus_startup ()) + if (!w32_gdiplus_startup ()) return Qnil; } @@ -649,7 +581,7 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) CLSID thumb_clsid; if (status == Ok /* Get the GUID of the TYPE's encoder. */ - && get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0) + && w32_gdip_get_encoder_clsid (SSDATA (type), &thumb_clsid) >= 0) { /* Save the thumbnail image to a file of specified TYPE. */ wchar_t thumb_file_w[MAX_PATH]; diff --git a/src/w32select.c b/src/w32select.c index 006bf408b47..7e8dc3f0702 100644 --- a/src/w32select.c +++ b/src/w32select.c @@ -73,12 +73,22 @@ along with GNU Emacs. If not, see . */ */ #include +#include +#include +#include +#include +#ifndef CF_DIBV5 +# define CF_DIBV5 17 +# undef CF_MAX +# define CF_MAX 18 +#endif #include "lisp.h" #include "w32common.h" /* os_subtype */ #include "w32term.h" /* for all of the w32 includes */ #include "w32select.h" #include "blockinput.h" #include "coding.h" +#include "w32gdiplus.h" #ifdef CYGWIN #include @@ -787,6 +797,166 @@ DEFUN ("w32-set-clipboard-data", Fw32_set_clipboard_data, return (ok ? string : Qnil); } +/* Xlib-like names for standard Windows clipboard data formats. + They are in upper-case to mimic xselect.c. A couple of the names + were changed to be more like their X counterparts. */ +static const char *stdfmt_name[] = { + "UNDEFINED", + "STRING", + "BITMAP", + "METAFILE", + "SYMLINK", + "DIF", + "TIFF", + "OEM_STRING", + "DIB", + "PALETTE", + "PENDATA", + "RIFF", + "WAVE", + "UTF8_STRING", + "ENHMETAFILE", + "FILE_NAMES", /* DND */ + "LOCALE", /* not used */ + "DIBV5" +}; + +/* Must be called with block_input() active. */ +static bool +convert_dibv5_to_png (char *data, int size, char *temp_file) +{ + CLSID clsid_png; + + if (!w32_gdiplus_startup () + || !w32_gdip_get_encoder_clsid ("png", &clsid_png)) + return false; + + BITMAPV5HEADER *bmi = (void *) data; + int stride = bmi->bV5SizeImage / bmi->bV5Height; + long offset = bmi->bV5Size + bmi->bV5ClrUsed * sizeof (RGBQUAD); + if (bmi->bV5Compression == BI_BITFIELDS) + offset += 12; + BYTE *scan0 = data + offset; + + GpBitmap *bitmap = NULL; + + GpStatus status + = GdipCreateBitmapFromScan0 (bmi->bV5Width, bmi->bV5Height, stride, + PixelFormat32bppARGB, scan0, &bitmap); + + if (status != Ok) + return false; + + /* The bitmap comes upside down. */ + GdipImageRotateFlip (bitmap, RotateNoneFlipY); + + WCHAR wide_filename[MAX_PATH]; + filename_to_utf16 (temp_file, wide_filename); + + status = GdipSaveImageToFile (bitmap, wide_filename, &clsid_png, NULL); + GdipDisposeImage (bitmap); + if (status != Ok) + return false; + return true; +} + +static int +get_clipboard_format_name (int format_index, char *name) +{ + *name = 0; + format_index = EnumClipboardFormats (format_index); + if (format_index == 0) + return 0; + if (format_index < CF_MAX) + strcpy (name, stdfmt_name[format_index]); + GetClipboardFormatName (format_index, name, 256); + return format_index; +} + +DEFUN ("w32--get-clipboard-data-media", Fw32__get_clipboard_data_media, + Sw32__get_clipboard_data_media, 3, 3, 0, + doc: /* Gets media (not plain text) clipboard data in one of the given formats. + +FORMATS is a list of formats. +TEMP-FILE-IN is the name of the file to store the data. + +Elements in FORMATS are symbols naming a format, such a image/png, or +image/jpeg. For compatibility with X systems, some conventional +format names are translated to equivalent MIME types, as configured with +the variable 'w32--selection-target-translations'. + +The file named in TEMP-FILE-IN must be created by the caller, and also +deleted if required. + +Returns nil it there is no such format, or something failed. +If it returns t, then the caller should read the file to get the data. +If it returns a string, then that is the data and the file is not used. + +When returning a string, it will be unibyte if IS-TEXTUAL is nil (the +content is binary data). */) + (Lisp_Object formats, Lisp_Object temp_file_in, Lisp_Object is_textual) +{ + CHECK_LIST (formats); + CHECK_STRING (temp_file_in); + + temp_file_in = Fexpand_file_name (temp_file_in, Qnil); + char *temp_file = SSDATA (ENCODE_FILE (temp_file_in)); + + Lisp_Object result = Qnil; + + block_input(); + if (!OpenClipboard (NULL)) + { + unblock_input(); + return Qnil; + } + + for (int format_index = 0;;) + { + static char name[256]; + format_index = get_clipboard_format_name (format_index, name); + if (format_index == 0) + break; + + /* If name doesn't match any of the formats, try the next format. */ + bool match = false; + for (Lisp_Object tail = formats; CONSP (tail); tail = XCDR (tail)) + if (strcmp (name, SSDATA (SYMBOL_NAME (XCAR (tail)))) == 0) + match = true; + if (!match) + continue; + + /* Of the standard formats, only DIBV5 is supported. */ + if (format_index < CF_MAX && format_index != CF_DIBV5) + continue; + + /* Found the format. */ + HANDLE d = GetClipboardData (format_index); + if (!d) + break; + int size = GlobalSize (d); + char *data = GlobalLock (d); + if (!data) + break; + if (strcmp (name, "DIBV5") == 0) + { + if (convert_dibv5_to_png (data, size, temp_file)) + result = Qt; + } + else + { + if (NILP (is_textual)) + result = make_unibyte_string (data, size); + else + result = make_string (data, size); + } + GlobalUnlock (d); + break; + } + CloseClipboard (); + unblock_input (); + return result; +} DEFUN ("w32-get-clipboard-data", Fw32_get_clipboard_data, Sw32_get_clipboard_data, 0, 1, 0, @@ -1069,29 +1239,6 @@ for `CLIPBOARD'. The return value is a vector of symbols, each symbol representing a data format that is currently available in the clipboard. */) (Lisp_Object selection, Lisp_Object terminal) { - /* Xlib-like names for standard Windows clipboard data formats. - They are in upper-case to mimic xselect.c. A couple of the names - were changed to be more like their X counterparts. */ - static const char *stdfmt_name[] = { - "UNDEFINED", - "STRING", - "BITMAP", - "METAFILE", - "SYMLINK", - "DIF", - "TIFF", - "OEM_STRING", - "DIB", - "PALETTE", - "PENDATA", - "RIFF", - "WAVE", - "UTF8_STRING", - "ENHMETAFILE", - "FILE_NAMES", /* DND */ - "LOCALE", /* not used */ - "DIBV5" - }; CHECK_SYMBOL (selection); /* Return nil for PRIMARY and SECONDARY selections; for CLIPBOARD, check @@ -1166,6 +1313,7 @@ syms_of_w32select (void) { defsubr (&Sw32_set_clipboard_data); defsubr (&Sw32_get_clipboard_data); + defsubr (&Sw32__get_clipboard_data_media); defsubr (&Sw32_selection_exists_p); defsubr (&Sw32_selection_targets); commit 5ee56b86938b7759dd92f507d03907280f48ffca Author: Eli Zaretskii Date: Sun Nov 3 09:25:51 2024 +0200 ; * etc/NEWS: Announce 'greek-polytonic'. (Bug#73909) diff --git a/etc/NEWS b/etc/NEWS index 22f11037453..11c9cf397c9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -163,6 +163,11 @@ pair with 'completing-read', and removes it from the translation table. --- *** Emacs now supports Unicode version 16.0. +--- +*** New input method 'greek-polytonic'. +This input method has support for polytonic and archaic Greek +characters. + --- *** New language-environment and input method for Tifinagh. The Tifinagh script is used to write the Berber languages. commit d276f45320b293a64f954e3e524a3718ddf87261 Author: Thanos Apollo Date: Sun Nov 3 05:44:27 2024 +0200 Add greek-polytonic input method diff --git a/lisp/leim/quail/greek.el b/lisp/leim/quail/greek.el index f2b68d17b13..ff335558a2e 100644 --- a/lisp/leim/quail/greek.el +++ b/lisp/leim/quail/greek.el @@ -1433,4 +1433,717 @@ e.g. (">>" ?»)) +(quail-define-package + "greek-polytonic" "Greek" "ῶ" t + "Ἑλληνικά: Greek input method, with support for polytonic & archaic +Greek letters." + nil t t t t nil nil nil nil nil t) + +(quail-define-rules + ("1" ?1) + ("2" ?2) + ("3" ?3) + ("4" ?4) + ("5" ?5) + ("6" ?6) + ("7" ?7) + ("8" ?8) + ("9" ?9) + ("0" ?0) + ("-" ?-) + ("=" ?=) + ("[" ?\[) + ("]" ?\]) + ;; Changed punction from greek.el + ("`" ?·) + ("~" ?:) + ;; tonoi + (";" ?΄) ;; U+1FFD (oxia) + ("q" ?`) ;; U+1FEF (varia) + ("'" ?῀) ;; U+1FC0 (perispomeni) + ("\"" ?ι) ;; U+1FBE (ypogegrammeni) + ;; pneumata + (":" ?᾿) ;; U+1FBF (psili) + ("Q" ?῾) ;; U+1FFE (dasia) + ("W" ?¨) ;; U+00A8 (dialytika) + ;; apostrophe combinations + ("; " ["’ "]) ;; U+2019 (apostrophe) + (";g" ["’γ"]) + (";d" ["’δ"]) + (";z" ["’ζ"]) + (";u" ["’θ"]) + (";k" ["’κ"]) + (";l" ["’λ"]) + (";m" ["’μ"]) + (";n" ["’ν"]) + (";j" ["’ξ"]) + (";p" ["’π"]) + (";ρ" ["’r"]) + (";s" ["’σ"]) + (";t" ["’τ"]) + (";f" ["’φ"]) + (";x" ["’χ"]) + (";c" ["’ψ"]) + ;; + (";G" ["’Γ"]) + (";D" ["’Δ"]) + (";Z" ["’Ζ"]) + (";U" ["’Θ"]) + (";K" ["’Κ"]) + (";L" ["’Λ"]) + (";M" ["’Μ"]) + (";N" ["’Ν"]) + (";J" ["’Ξ"]) + (";P" ["’Π"]) + (";Ρ" ["’R"]) + (";S" ["’Σ"]) + (";T" ["’Τ"]) + (";F" ["’Φ"]) + (";X" ["’Χ"]) + (";C" ["’Ψ"]) + ;; Combinations + ("W;" ?΅) ;; U+1FEE + (";W" ?΅) ;; U+1FEE + ("Wq" ?῭) ;; U+1FED + ("qW" ?῭) ;; U+1FED + (":;" ?῎) ;; U+1FCE + (";:" ?῎) ;; U+1FCE + ("qQ" ?῝) ;; U+1FDD + ("Qq" ?῝) ;; U+1FDD + ("q:" ?῍) ;; U+1FCD + (":q" ?῍) ;; U+1FCD + ("Q;" ?῞) ;; U+1FDE + (";Q" ?῞) ;; U+1FDE + ("':" ?῏) ;; U+1FCF + (":'" ?῏) ;; U+1FCF + ("'Q" ?῟) ;; U+1FDF + ("Q'" ?῟) ;; U+1FDF + ("'W" ?῁) ;; U+1FC1 + ("W'" ?῁) ;; U+1FC1 + ;; perispomeni combinations, used for vrachy and macron + ("''" ["῀῀"]) + ("'''" ["῀῀῀"]) + ;; ypogegrammeni combinations + ("\"'" ["῀ι"]) + ("'\"" ["῀ι"]) + ("\";" ["΄ι"]) + (";\"" ["ι΄"]) + ("\":" ["ι᾿"]) + (":\"" ["ι᾿"]) + ("\"q" ["ι`"]) + ("q\"" ["ι`"]) + ("\"Q" ["ι῾"]) + ("Q\"" ["ι῾"]) + ("Q\"'" ["ι῟"]) + ("\"Q'" ["ι῟"]) + + ("Q'\"" ["ι῟"]) + ("'Q\"" ["ι῟"]) + (":q\"" ["῍ι"]) + ("q:\"" ["῍ι"]) + ("\"q:" ["῍ι"]) + ("\":q" ["῍ι"]) + + (":;\"" ["῎ι"]) + (";:\"" ["῎ι"]) + ("\";:" ["῎ι"]) + ("\":;" ["῎ι"]) + ("Qq\"" ["῝ι"]) + ("qQ\"" ["῝ι"]) + ("\"Qq" ["῝ι"]) + ("\"qQ" ["῝ι"]) + + ("Q;\"" ["῞ι"]) + (";Q\"" ["῞ι"]) + ("\";Q" ["῞ι"]) + ("\"Q;" ["῞ι"]) + + (":'\"" ["῏ι"]) + ("':\"" ["῏ι"]) + ("\"':" ["῏ι"]) + ("\":'" ["῏ι"]) + ;; Misc characters + ("~" ?:) + ("``" "~") + ;; + ("W" ?¨) + ("," ?,) + ("." ?.) + ("/" ?/) + ("!" ?!) + ("@" ?@) + ("#" ?#) + ("$" ?€) + ("%" ?%) + ("^" ?^) + ("&" ?&) + ("*" ?*) + ("(" ?\() + (")" ?\)) + ("_" ?_) + ("+" ?+) + ("{" ?{) + ("}" ?}) + (";;" "\"") + ("<" ?<) + (">" ?>) + ("?" ?;) ;; U+037E (Greek Question Mark) + (">>" ?») ;; U+00BB + ("<<" ?«) ;; U+00AB + ;; Alpha + ("A" ?Α) ;; U+0391 + (":A" ?Ἀ) ;; U+1F08 + ("QA" ?Ἁ) ;; U+1F09 + (":qA" ?Ἂ) ;; U+1F0A + ("q:A" ?Ἂ) ;; U+1F0A + ("qQA" ?Ἃ) ;; U+1F0B + ("QqA" ?Ἃ) ;; U+1F0B + (":;A" ?Ἄ) ;; U+1F0C + ("Q;A" ?Ἅ) ;; U+1F0D + (";QA" ?Ἅ) ;; U+1F0D + (":'A" ?Ἆ) ;; U+1F0E + ("':A" ?Ἆ) ;; U+1F0E + ("Q'A" ?Ἇ) ;; U+1F0F + ("'QA" ?Ἇ) ;; U+1F0F + (":\"A" ?ᾈ) ;; U+1F88 + ("Q\"A" ?ᾉ) ;; U+1F89 + (":q\"A" ?ᾊ) ;; U+1F8A + ("q:\"A" ?ᾊ) ;; U+1F8A + ("q\":A" ?ᾊ) ;; U+1F8A + ("\"q:A" ?ᾊ) ;; U+1F8A + ("Qq\"A" ?ᾋ) ;; U+1F8B + ("qQ\"A" ?ᾋ) ;; U+1F8B + ("q\"QA" ?ᾋ) ;; U+1F8B + ("\"qQA" ?ᾋ) ;; U+1F8B + (":;\"A" ?ᾌ) ;; U+1F8C + (";:\"A" ?ᾌ) ;; U+1F8C + (";\":A" ?ᾌ) ;; U+1F8C + ("\";:A" ?ᾌ) ;; U+1F8C + ("Q;\"A" ?ᾍ) ;; U+1F8D + ("Q\";A" ?ᾍ) ;; U+1F8D + ("\"Q;A" ?ᾍ) ;; U+1F8D + ("\";QA" ?ᾍ) ;; U+1F8D + (":'\"A" ?ᾎ) ;; U+1F8E + (":\"'A" ?ᾎ) ;; U+1F8E + ("\":'A" ?ᾎ) ;; U+1F8E + ("\"':A" ?ᾎ) ;; U+1F8E + ("Q'\"A" ?ᾏ) ;; U+1F8F + ("'Q\"A" ?ᾏ) ;; U+1F8F + ("'\"QA" ?ᾏ) ;; U+1F8F + ("\"'QA" ?ᾏ) ;; U+1F8F + ("''A" ?Ᾰ) ;; U+1FB8 + ("'''A" ?Ᾱ) ;; U+1FB9 + ("qA" ?Ὰ) ;; U+1FBA + (";A" ?Ά) ;; U+1FBB + ("\"A" ?ᾼ) ;; U+1FBC + ("a" ?α) ;; U+03B1 + (":a" ?ἀ) ;; U+1F00 + ("Qa" ?ἁ) ;; U+1F01 + (":qa" ?ἂ) ;; U+1F02 + ("q:a" ?ἂ) ;; U+1F02 + ("Qqa" ?ἃ) ;; U+1F03 + ("qQa" ?ἃ) ;; U+1F03 + (":;a" ?ἄ) ;; U+1F04 + (";:a" ?ἄ) ;; U+1F04 + ("Q;a" ?ἅ) ;; U+1F05 + (";Qa" ?ἅ) ;; U+1F05 + (":'a" ?ἆ) ;; U+1F06 + ("':a" ?ἆ) ;; U+1F06 + ("Q'a" ?ἇ) ;; U+1F07 + ("'Qa" ?ἇ) ;; U+1F07 + ("qa" ?ὰ) ;; U+1F70 + (";a" ?ά) ;; U+1F71 + (":\"a" ?ᾀ) ;; U+1F80 + ("\":a" ?ᾀ) ;; U+1F80 + ("Q\"a" ?ᾁ) ;; U+1F81 + (":q\"a" ?ᾂ) ;; U+1F82 + (":\"qa" ?ᾂ) ;; U+1F82 + ("\":qa" ?ᾂ) ;; U+1F82 + ("\"q:a" ?ᾂ) ;; U+1F82 + ("Qq\"a" ?ᾃ) ;; U+1F83 + ("Q\"qa" ?ᾃ) ;; U+1F83 + ("\"qQa" ?ᾃ) ;; U+1F83 + ("\"Qqa" ?ᾃ) ;; U+1F83 + (":;\"a" ?ᾄ) ;; U+1F84 + (";\":a" ?ᾄ) ;; U+1F84 + ("\";:a" ?ᾄ) ;; U+1F84 + (";:\"a" ?ᾄ) ;; U+1F84 + (":;\"a" ?ᾄ) ;; U+1F84 + ("Q;\"a" ?ᾅ) ;; U+1F85 + ("Q\";a" ?ᾅ) ;; U+1F85 + ("\"Q;a" ?ᾅ) ;; U+1F85 + ("\";Qa" ?ᾅ) ;; U+1F85 + (";\"Qa" ?ᾅ) ;; U+1F85 + (":'\"a" ?ᾆ) ;; U+1F86 + ("':\"a" ?ᾆ) ;; U+1F86 + ("'\":a" ?ᾆ) ;; U+1F86 + ("\"':a" ?ᾆ) ;; U+1F86 + ("\":'a" ?ᾆ) ;; U+1F86 + ("Q'\"a" ?ᾇ) ;; U+1F87 + ("'Q\"a" ?ᾇ) ;; U+1F87 + ("'\"Qa" ?ᾇ) ;; U+1F87 + ("\"'Qa" ?ᾇ) ;; U+1F87 + ("\"Q'a" ?ᾇ) ;; U+1F87 + ("''a" ?ᾰ) ;; U+1FB0 + ("'''a" ?ᾱ) ;; U+1FB1 + ("q\"a" ?ᾲ) ;;U+1FB2 + ("\"qa" ?ᾲ) ;;U+1FB2 + ("\"a" ?ᾳ) ;; U+1FB3 + (";\"a" ?ᾴ) ;; U+1FB4 + ("'a" ?ᾶ) ;; U+1FB6 + ("'\"a" ?ᾷ) ;; U+1FB7 + ("\"'a" ?ᾷ) ;; U+1FB7 + ;; Beta + ("B" ?Β) ;; U+0392 + ("b" ?β) ;; U+03B2 + ;; Gamma + ("G" ?Γ) ;; U+0393 + ("g" ?γ) ;; U+03B3 + ;; Delta + ("D" ?Δ) ;; U+0394 + ("d" ?δ) ;; U+03B4 + ;; Epsilon + ("E" ?Ε) ;; U+0395 + (":E" ?Ἐ) ;; U+1F18 + ("QE" ?Ἑ) ;; U+1F19 + (":qE" ?Ἒ) ;; U+1F1A + ("q:E" ?Ἒ) ;; U+1F1A + ("QqE" ?Ἓ) ;; U+1F1B + ("qQE" ?Ἓ) ;; U+1F1B + (":;E" ?Ἔ) ;; U+1F1C + (";:E" ?Ἔ) ;; U+1F1C + ("Q;E" ?Ἕ) ;; U+1F1D + (";QE" ?Ἕ) ;; U+1F1D + ("qE" ?Ὲ) ;; U+1FC8 + (";E" ?Έ) ;; U+1FC9 + ("e" ?ε) ;; U+03B5 + ("qe" ?ὲ) ;; U+1F72 + (";e" ?έ) ;; U+1F73 + (":e" ?ἐ) ;; U+1F10 + ("Qe" ?ἑ) ;; U+1F11 + (":qe" ?ἒ) ;; U+1F12 + ("q:e" ?ἒ) ;; U+1F12 + ("Qqe" ?ἓ) ;; U+1F13 + ("qQe" ?ἓ) ;; U+1F13 + (":;e" ?ἔ) ;; U+1F14 + (";:e" ?ἔ) ;; U+1F14 + ("Q;e" ?ἕ) ;; U+1F15 + (";Qe" ?ἕ) ;; U+1F15 + ;; Zeta + ("Z" ?Ζ) ;; U+0396 + ("z" ?ζ) ;; U+03B6 + ;; Eta + ("H" ?Η) ;; U+0397 + (":H" ?Ἠ) ;; U+1F28 + ("QH" ?Ἡ) ;; U+1F29 + (":qH" ?Ἢ) ;; U+1F2A + ("q:H" ?Ἢ) ;; U+1F2A + ("QqH" ?Ἣ) ;; U+1F2B + ("qQH" ?Ἣ) ;; U+1F2B + (":;H" ?Ἤ) ;; U+1F2C + (";:H" ?Ἤ) ;; U+1F2C + ("Q;H" ?Ἥ) ;; U+1F2D + (";QH" ?Ἥ) ;; U+1F2D + (":'H" ?Ἦ) ;; U+1F2E + ("':H" ?Ἦ) ;; U+1F2E + ("Q'H" ?Ἧ) ;; U+1F2F + ("'QH" ?Ἧ) ;; U+1F2F + (":\"H" ?ᾘ) ;; U+1F98 + ("\":H" ?ᾘ) ;; U+1F98 + ("Q\"H" ?ᾙ) ;; U+1F99 + ("\"QH" ?ᾙ) ;; U+1F99 + (":q\"H" ?ᾚ) ;; U+1F9A + (":\"qH" ?ᾚ) ;; U+1F9A + ("\":qH" ?ᾚ) ;; U+1F9A + ("\"q:H" ?ᾚ) ;; U+1F9A + ("q\":H" ?ᾚ) ;; U+1F9A + ("Qq\"H" ?ᾛ) ;; U+1F9B + ("Q\"qH" ?ᾛ) ;; U+1F9B + ("\"QqH" ?ᾛ) ;; U+1F9B + ("\"qQH" ?ᾛ) ;; U+1F9B + ("q\"QH" ?ᾛ) ;; U+1F9B + (":;\"H" ?ᾜ) ;; U+1F9C + (":\";H" ?ᾜ) ;; U+1F9C + ("\":;H" ?ᾜ) ;; U+1F9C + ("\";:H" ?ᾜ) ;; U+1F9C + (";\":H" ?ᾜ) ;; U+1F9C + ("Q;\"H" ?ᾝ) ;; U+1F9D + ("Q\";H" ?ᾝ) ;; U+1F9D + ("\"Q;H" ?ᾝ) ;; U+1F9D + ("\";QH" ?ᾝ) ;; U+1F9D + (";\"QH" ?ᾝ) ;; U+1F9D + (":'\"H" ?ᾞ) ;; U+1F9E + (":\"'H" ?ᾞ) ;; U+1F9E + ("\":'H" ?ᾞ) ;; U+1F9E + ("\"':H" ?ᾞ) ;; U+1F9E + ("'\":H" ?ᾞ) ;; U+1F9E + ("Q'\"H" ?ᾟ) ;; U+1F9F + ("Q\"'H" ?ᾟ) ;; U+1F9F + ("\"Q'H" ?ᾟ) ;; U+1F9F + ("\"'QH" ?ᾟ) ;; U+1F9F + ("'\"QH" ?ᾟ) ;; U+1F9F + ("qH" ?Ὴ) ;; U+1FCA + (";H" ?Ή) ;; U+1FCB + ("\"H" ?ῌ) ;; U+1FCC + ;; + ("h" ?η) ;; U+03B7 + ("qh" ?ὴ) ;; U+1F74 + (";h" ?ή) ;; U+1F75 + (":h" ?ἠ) ;; U+1F20 + ("Qh" ?ἡ) ;; U+1F21 + (":qh" ?ἢ) ;; U+1F22 + ("q:h" ?ἢ) ;; U+1F22 + ("Qqh" ?ἣ) ;; U+1F23 + ("qQh" ?ἣ) ;; U+1F23 + (":;h" ?ἤ) ;; U+1F24 + (";:h" ?ἤ) ;; U+1F24 + ("Q;h" ?ἥ) ;; U+1F25 + (";Qh" ?ἥ) ;; U+1F25 + (":'h" ?ἦ) ;; U+1F26 + ("':h" ?ἦ) ;; U+1F26 + ("Q'h" ?ἧ) ;; U+1F27 + ("'Qh" ?ἧ) ;; U+1F27 + (":\"h" ?ᾐ) ;; U+1F90 + ("\":h" ?ᾐ) ;; U+1F90 + ("Q\"h" ?ᾑ) ;; U+1F91 + ("\"Qh" ?ᾑ) ;; U+1F91 + (":q\"h" ?ᾒ) ;; U+1F92 + (":\"qh" ?ᾒ) ;; U+1F92 + ("\":qh" ?ᾒ) ;; U+1F92 + ("\"q:h" ?ᾒ) ;; U+1F92 + ("q\":h" ?ᾒ) ;; U+1F92 + ("Qq\"h" ?ᾓ) ;; U+1F93 + ("Q\"qh" ?ᾓ) ;; U+1F93 + ("\"Qqh" ?ᾓ) ;; U+1F93 + ("\"qQh" ?ᾓ) ;; U+1F93 + ("q\"Qh" ?ᾓ) ;; U+1F93 + (":;\"h" ?ᾔ) ;; U+1F94 + (":\";h" ?ᾔ) ;; U+1F94 + ("\":;h" ?ᾔ) ;; U+1F94 + ("\";:h" ?ᾔ) ;; U+1F94 + (";\":h" ?ᾔ) ;; U+1F94 + ("Q;\"h" ?ᾕ) ;; U+1F95 + ("Q\";h" ?ᾕ) ;; U+1F95 + ("\"Q;h" ?ᾕ) ;; U+1F95 + ("\";Qh" ?ᾕ) ;; U+1F95 + (";\"Qh" ?ᾕ) ;; U+1F95 + (":'\"h" ?ᾖ) ;; U+1F96 + (":\"'h" ?ᾖ) ;; U+1F96 + ("\":'h" ?ᾖ) ;; U+1F96 + ("\"':h" ?ᾖ) ;; U+1F96 + ("'\":h" ?ᾖ) ;; U+1F96 + ("Q'\"h" ?ᾗ) ;; U+1F97 + ("Q\"'h" ?ᾗ) ;; U+1F97 + ("\"Q'h" ?ᾗ) ;; U+1F97 + ("\"'Qh" ?ᾗ) ;; U+1F97 + ("'\"Qh" ?ᾗ) ;; U+1F97 + ("q\"h" ?ῂ) ;; U+1FC2 + ("\"qh" ?ῂ) ;; U+1FC2 + ("\"h" ?ῃ) ;; U+1FC3 + (";\"h" ?ῄ) ;; U+1FC4 + ("\";h" ?ῄ) ;; U+1FC4 + ("'h" ?ῆ) ;; U+1FC6 + ("\"'h" ?ῇ) ;; U+1FC7 + ("'\"h" ?ῇ) ;; U+1FC7 + ;; Theta + ("U" ?Θ) ;; U+0398 + ("u" ?θ) ;; U+03B8 + ;; Iota + ("I" ?Ι) ;; U+0399 + ("WI" ?Ϊ) ;; U+03AA + (":I" ?Ἰ) ;; U+1F38 + ("QI" ?Ἱ) ;; U+1F39 + (":qI" ?Ἲ) ;; U+1F3A + ("q:I" ?Ἲ) ;; U+1F3A + ("QqI" ?Ἳ) ;; U+1F3B + ("qQI" ?Ἳ) ;; U+1F3B + (":;I" ?Ἴ) ;; U+1F3C + (";:I" ?Ἴ) ;; U+1F3C + ("Q;I" ?Ἵ) ;; U+1F3D + (";QI" ?Ἵ) ;; U+1F3D + (":'I" ?Ἶ) ;; U+1F3E + ("':I" ?Ἶ) ;; U+1F3E + ("Q'I" ?Ἷ) ;; U+1F3F + ("''I" ?Ῐ) ;; U+1FD8 + ("'''I" ?Ῑ) ;; U+1FD9 + ("qI" ?Ὶ) ;; U+1FDA + (";I" ?Ί) ;; U+1FDB + ("i" ?ι) ;; U+03B9 + ("Wi" ?ϊ) ;; U+03CA + ("qi" ?ὶ) ;; U+1F76 + (";i" ?ί) ;; U+1F77 + (":i" ?ἰ) ;; U+1F30 + ("Qi" ?ἱ) ;; U+1F31 + (":qi" ?ἲ) ;; U+1F32 + ("q:i" ?ἲ) ;; U+1F32 + ("Qqi" ?ἳ) ;; U+1F33 + ("qQi" ?ἳ) ;; U+1F33 + (":;i" ?ἴ) ;; U+1F34 + (";:i" ?ἴ) ;; U+1F34 + ("Q;i" ?ἵ) ;; U+1F35 + (";Qi" ?ἵ) ;; U+1F35 + (":'i" ?ἶ) ;; U+1F36 + ("':i" ?ἶ) ;; U+1F36 + ("Q'i" ?ἷ) ;; U+1F37 + ("'Qi" ?ἷ) ;; U+1F37 + ("''i" ?ῐ) ;; U+1FD0 + ("'''i" ?ῑ) ;; U+1FD1 + ("Wqi" ?ῒ) ;; U+1FD2 + ("qWi" ?ῒ) ;; U+1FD2 + (";Wi" ?ΐ) ;; U+1FD3 + ("W;i" ?ΐ) ;; U+1FD3 + ("'i" ?ῖ) ;; U+1FD6 + ("W'i" ?ῗ) ;; U+1FD7 + ("'Wi" ?ῗ) ;; U+1FD7 + ;; Kappa + ("K" ?Κ) ;; U+039A + ("k" ?κ) ;; U+03BA + ;; Lambda + ("L" ?Λ) ;; U+039B + ("l" ?λ) ;; U+03BB + ;; Mu + ("M" ?Μ) ;; U+039C + ("m" ?μ) ;; U+03BC + ;; Nu + ("N" ?Ν) ;; U+039D + ("n" ?ν) ;; U+03BD + ;; Xi + ("J" ?Ξ) ;; U+039E + ("j" ?ξ) ;; U+03BE + ;; Omicron + ("O" ?Ο) ;; U+039F + (":O" ?Ὀ) ;; U+1F48 + ("QO" ?Ὁ) ;; U+1F49 + (":qO" ?Ὂ) ;; U+1F4A + ("q:O" ?Ὂ) ;; U+1F4A + ("QqO" ?Ὃ) ;; U+1F4B + (":;O" ?Ὄ) ;; U+1F4C + ("Q;O" ?Ὅ) ;; U+1F4D + ("qO" ?Ὸ) ;; U+1FF8 + (";O" ?Ό) ;; U+1FF9 + ("o" ?ο) ;; U+03BF + ("qo" ?ὸ) ;; U+1F78 + (";o" ?ό) ;; U+1F79 + (":o" ?ὀ) ;; U+1F40 + ("Qo" ?ὁ) ;; U+1F41 + (":qo" ?ὂ) ;; U+1F42 + ("q:o" ?ὂ) ;; U+1F42 + ("Qqo" ?ὃ) ;; U+1F43 + ("qQo" ?ὃ) ;; U+1F43 + (":;o" ?ὄ) ;; U+1F44 + (";:o" ?ὄ) ;; U+1F44 + ("Q;o" ?ὅ) ;; U+1F45 + ;; Pi + ("P" ?Π) ;; U+03A0 + ("p" ?π) ;; U+03C0 + ;; Rho + ("R" ?Ρ) ;; U+03A1 + ("QR" ?Ῥ) ;; U+1FEC + ("r" ?ρ) ;; U+03C1 + (":r" ?ῤ) ;; U+1FE4 + ("Qr" ?ῥ) ;; U+1FE5 + ;; Sigma + ("S" ?Σ) ;; U+03A3 + ("s" ?σ) ;; U+03C3 + ("w" ?ς) ;; U+03C2 + ;; Tau + ("T" ?Τ) ;; U+03A4 + ("t" ?τ) ;; U+03C4 + ;; Upsilon + ("Y" ?Υ) ;; U+03A5 + ("WY" ?Ϋ) ;; U+03AB + ("QY" ?Ὑ) ;; U+1F59 + ("QqY" ?Ὓ) ;; U+1F5B + ("qQY" ?Ὓ) ;; U+1F5B + ("Q;Y" ?Ὕ) ;; U+1F5D + (";QY" ?Ὕ) ;; U+1F5D + ("Q'Y" ?Ὗ) ;; U+1F5F + ("'QY" ?Ὗ) ;; U+1F5F + ("y" ?υ) ;; U+03C5 + ("Wy" ?ϋ) ;; U+03CB + ("qy" ?ὺ) ;; U+1F7A + (";y" ?ύ) ;; U+1F7B + (":y" ?ὐ) ;; U+1F50 + ("Qy" ?ὑ) ;; U+1F51 + (":qy" ?ὒ) ;; U+1F52 + ("q:y" ?ὒ) ;; U+1F52 + ("Qqy" ?ὓ) ;; U+1F53 + ("qQy" ?ὓ) ;; U+1F53 + (":;y" ?ὔ) ;; U+1F54 + (";:y" ?ὔ) ;; U+1F54 + ("Q;y" ?ὕ) ;; U+1F55 + (";Qy" ?ὕ) ;; U+1F55 + (":'y" ?ὖ) ;; U+1F56 + ("':y" ?ὖ) ;; U+1F56 + ("Q'y" ?ὗ) ;; U+1F57 + ("'Qy" ?ὗ) ;; U+1F57 + ("''y" ?ῠ) ;; U+1FE0 + ("'''y" ?ῡ) ;; U+1FE1 + ("Wqy" ?ῢ) ;; U+1FE2 + ("qWy" ?ῢ) ;; U+1FE2 + ("W;y" ?ΰ) ;; U+1FE3 + (";Wy" ?ΰ) ;; U+1FE3 + ("'y" ?ῦ) ;; U+1FE6 + ("W'y" ?ῧ) ;; U+1FE7 + ("'Wy" ?ῧ) ;; U+1FE7 + ("''Y" ?Ῠ) ;; U+1FE8 + ("'''Y" ?Ῡ) ;; U+1FE8 + ("qY" ?Ὺ) ;; U+1FEA + (";Y" ?Ύ) ;; U+1FEB + ;; Phi + ("F" ?Φ) ;; U+03A6 + ("f" ?φ) ;; U+03C6 + ;; Chi + ("X" ?Χ) ;; U+03A7 + ("x" ?χ) ;; U+03C7 + ;; Chi + ("C" ?Ψ) ;; U+03A8 + ("c" ?ψ) ;; U+03C8 + ;; Omega + ("V" ?Ω) ;; U+03A9 + (":V" ?Ὠ) ;; U+1F68 + ("QV" ?Ὡ) ;; U+1F69 + (":qV" ?Ὢ) ;; U+1F6A + ("q:V" ?Ὢ) ;; U+1F6A + ("QqV" ?Ὣ) ;; U+1F6B + ("qQV" ?Ὣ) ;; U+1F6B + (":;V" ?Ὤ) ;; U+1F6C + (";:V" ?Ὤ) ;; U+1F6C + ("Q;V" ?Ὥ) ;; U+1F6D + (";QV" ?Ὥ) ;; U+1F6D + (":'V" ?Ὦ) ;; U+1F6E + ("':V" ?Ὦ) ;; U+1F6E + ("Q'V" ?Ὧ) ;; U+1F6F + (":\"V" ?ᾨ) ;; U+1FA8 + ("\":V" ?ᾨ) ;; U+1FA8 + ("Q\"V" ?ᾩ) ;; U+1FA9 + ("\"QV" ?ᾩ) ;; U+1FA9 + + (":q\"V" ?ᾪ) ;; U+1FAA + (":\"qV" ?ᾪ) ;; U+1FAA + ("\":qV" ?ᾪ) ;; U+1FAA + ("\"q:V" ?ᾪ) ;; U+1FAA + ("q\":V" ?ᾪ) ;; U+1FAA + ("q:\"V" ?ᾪ) ;; U+1FAA + + ("Qq\"V" ?ᾫ) ;; U+1FAB + ("qQ\"V" ?ᾫ) ;; U+1FAB + ("q\"QV" ?ᾫ) ;; U+1FAB + ("\"qQV" ?ᾫ) ;; U+1FAB + ("\"QqV" ?ᾫ) ;; U+1FAB + + (":\"qV" ?ᾫ) ;; U+1FAB + (":;\"V" ?ᾬ) ;; U+1FAC + (":\";V" ?ᾬ) ;; U+1FAC + ("\":;V" ?ᾬ) ;; U+1FAC + ("\";:V" ?ᾬ) ;; U+1FAC + (";\":V" ?ᾬ) ;; U+1FAC + ("Q;\"V" ?ᾭ) ;; U+1FAD + ("Q\";V" ?ᾭ) ;; U+1FAD + ("\"Q;V" ?ᾭ) ;; U+1FAD + ("\";QV" ?ᾭ) ;; U+1FAD + (";\"QV" ?ᾭ) ;; U+1FAD + (":'\"V" ?ᾮ) ;; U+1FAE + (":\"'V" ?ᾮ) ;; U+1FAE + ("\":'V" ?ᾮ) ;; U+1FAE + ("\"':V" ?ᾮ) ;; U+1FAE + ("'\":V" ?ᾮ) ;; U+1FAE + + ("Q'\"V" ?ᾯ) ;; U+1FAF + ("'Q\"V" ?ᾯ) ;; U+1FAF + ("Q\"'V" ?ᾯ) ;; U+1FAF + ("\"Q'V" ?ᾯ) ;; U+1FAF + ("\"'QV" ?ᾯ) ;; U+1FAF + ("'\"QV" ?ᾯ) ;; U+1FAF + + ("qV" ?Ὼ) ;; U+1FFA + (";V" ?Ώ) ;; U+1FFB + ("\"V" ?ῼ) ;; U+1FFC + ("v" ?ω) ;; U+03C9 + ("qv" ?ὼ) ;; U+1F7C + (";v" ?ώ) ;; U+1F7D + (":v" ?ὠ) ;; U+1F60 + ("Qv" ?ὡ) ;; U+1F61 + (":qv" ?ὢ) ;; U+1F62 + ("q:v" ?ὢ) ;; U+1F62 + ("Qqv" ?ὣ) ;; U+1F63 + ("qQv" ?ὣ) ;; U+1F63 + (":;v" ?ὤ) ;; U+1F64 + (";:v" ?ὤ) ;; U+1F64 + ("Q;v" ?ὥ) ;; U+1F65 + (";Qv" ?ὥ) ;; U+1F65 + (":'v" ?ὦ) ;; U+1F66 + ("':v" ?ὦ) ;; U+1F66 + ("Q'v" ?ὧ) ;; U+1F67 + ("'Qv" ?ὧ) ;; U+1F67 + (":\"v" ?ᾠ) ;; U+1FA0 + ("\":v" ?ᾠ) ;; U+1FA0 + ("Q\"v" ?ᾡ) ;; U+1FA1 + ("\"Qv" ?ᾡ) ;; U+1FA1 + (":q\"v" ?ᾢ) ;; U+1FA2 + (":\"qv" ?ᾢ) ;; U+1FA2 + ("\":qv" ?ᾢ) ;; U+1FA2 + ("\"q:v" ?ᾢ) ;; U+1FA2 + ("q\":v" ?ᾢ) ;; U+1FA2 + + ("Qq\"v" ?ᾣ) ;; U+1FA3 + ("q\"Qv" ?ᾣ) ;; U+1FA3 + ("\"qQv" ?ᾣ) ;; U+1FA3 + ("\"Qqv" ?ᾣ) ;; U+1FA3 + ("Q\"qv" ?ᾣ) ;; U+1FA3 + + (":;\"v" ?ᾤ) ;; U+1FA4 + (":\";v" ?ᾤ) ;; U+1FA4 + ("\":;v" ?ᾤ) ;; U+1FA4 + ("\";:v" ?ᾤ) ;; U+1FA4 + (";\":v" ?ᾤ) ;; U+1FA4 + (";:\"v" ?ᾤ) ;; U+1FA4 + + ("Q;\"v" ?ᾥ) ;; U+1FA5 + ("Q\";v" ?ᾥ) ;; U+1FA5 + ("\"Q;v" ?ᾥ) ;; U+1FA5 + ("\";Qv" ?ᾥ) ;; U+1FA5 + (";\"Qv" ?ᾥ) ;; U+1FA5 + (";Q\"v" ?ᾥ) ;; U+1FA5 + + (":'\"v" ?ᾦ) ;; U+1FA6 + (":\"'v" ?ᾦ) ;; U+1FA6 + ("\":'v" ?ᾦ) ;; U+1FA6 + ("\"':v" ?ᾦ) ;; U+1FA6 + ("'\":v" ?ᾦ) ;; U+1FA6 + ("':\"v" ?ᾦ) ;; U+1FA6 + + ("Q'\"v" ?ᾧ) ;; U+1FA7 + ("Q\"'v" ?ᾧ) ;; U+1FA7 + ("\"Q'v" ?ᾧ) ;; U+1FA7 + ("\"'Qv" ?ᾧ) ;; U+1FA7 + ("'\"Qv" ?ᾧ) ;; U+1FA7 + ("'Q\"v" ?ᾧ) ;; U+1FA7 + + ("q\"v" ?ῲ) ;; U+1FF2 + ("\"qv" ?ῲ) ;; U+1FF2 + ("\"v" ?ῳ) ;; U+1FF3 + (";\"v" ?ῴ) ;; U+1FF4 + ("'v" ?ῶ) ;; U+1FF6 + ("'\"v" ?ῷ) ;; U+1FF7 + ("\"'v" ?ῷ) ;; U+1FF7 + ;;; Archaic Letters ;;; + ;; Stigma + ("ww" ?ϛ) ;; U+03DB Note that capital stigma (U+03DA) is an invalid letter. + ;; Digamma + ("wF" ?Ϝ) ;; U+03DC + ("wf" ?ϝ) ;; U+03DD + ;; Koppa + ("wK" ?Ϟ) ;; U+03DE + ("wk" ?ϟ) ;; U+03DF + ;; Sampi + ("wP" ?Ϡ) ;; U+03E0 + ("wp" ?ϡ) ;; U+03E1 + ;; Koppa + ("wO" ?Ϙ) ;; U+03D8 + ("wo" ?ϙ) ;; U+03D9 + ) + +(provide 'greek-polytonic) + ;;; greek.el ends here commit 7cda5fa4cf6ecdfda108284717a1531cfc442fe4 Author: Thanos Apollo Date: Sun Nov 3 05:45:19 2024 +0200 Improve greek input method * lisp/leim/quail/greek.el ("greek"): Add sequences for DIALYTIKA TONOS (U+0385) and add proper bindings for double angle quotation marks. (Bug#73909) diff --git a/lisp/leim/quail/greek.el b/lisp/leim/quail/greek.el index 7cf839f2f58..f2b68d17b13 100644 --- a/lisp/leim/quail/greek.el +++ b/lisp/leim/quail/greek.el @@ -1245,6 +1245,8 @@ e.g. ("K" ?Κ) ("L" ?Λ) (":" ?¨) + (";:" ?΅) + (":;" ?΅) ("\"" ?\") ("|" ?|) ("Z" ?Ζ) @@ -1281,7 +1283,9 @@ e.g. (";:y" ?ΰ) (":;y" ?ΰ) (";<" ?«) - (";>" ?»)) + (";>" ?») + ("<<" ?«) + (">>" ?»)) (quail-define-package "greek-postfix" "GreekPost" "Ψ" nil