commit 48bb25c0e37f8489b06b82a4c32f0c6dcc0856e9 (HEAD, refs/remotes/origin/master) Author: Elias G. Perez Date: Fri May 10 20:36:42 2024 -0600 Stipple support for MS Windows (bug#71159) * src/w32term.c (w32_fill_stipple_pattern): New function. (w32_draw_glyph_string_bg_rect w32_draw_stretch_glyph_string) (w32_draw_glyph_string_background): Use new stipple function. * src/w32term.h (w32_bitmap_record): Add stipple value. * src/image.c (image_create_bitmap_from_data): Create stipple bitmap. (image_create_bitmap_from_file): Add suuport for pixmap and create stipple bitmap. (free_bitmap_record): Release stipple. * etc/NEWS: Announce support for stipples in MS-Windows. diff --git a/etc/NEWS b/etc/NEWS index 77f2e3c885a..80bf0b4fefa 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2852,6 +2852,9 @@ thumbnail images and show them in the thumbnail buffer. Unlike with using 'convert', this fallback method is synchronous, so Emacs will wait until all the thumbnails are created and displayed, before showing them. +--- +*** Emacs on MS-Windows now supports the ':stipple' face attribute. + ---------------------------------------------------------------------- This file is part of GNU Emacs. diff --git a/src/image.c b/src/image.c index 3138ef25a63..321073a4fd9 100644 --- a/src/image.c +++ b/src/image.c @@ -130,6 +130,12 @@ typedef struct w32_bitmap_record Bitmap_Record; #define PIX_MASK_RETAIN 0 #define PIX_MASK_DRAW 1 +#define XBM_BIT_SHUFFLE(b) (~(b)) + +#else + +#define XBM_BIT_SHUFFLE(b) (b) + #endif /* HAVE_NTGUI */ #ifdef HAVE_NS @@ -214,6 +220,11 @@ static void free_color_table (void); static unsigned long *colors_in_color_table (int *n); #endif +#ifdef HAVE_NTGUI +static HBITMAP w32_create_pixmap_from_bitmap_data (int, int, char *); + +#endif + #if defined (HAVE_WEBP) || defined (HAVE_GIF) static void anim_prune_animation_cache (Lisp_Object); #endif @@ -596,13 +607,31 @@ image_create_bitmap_from_data (struct frame *f, char *bits, #endif /* HAVE_ANDROID && !defined ANDROID_STUBIFY */ #ifdef HAVE_NTGUI - Lisp_Object frame UNINIT; /* The value is not used. */ - Emacs_Pixmap bitmap; - bitmap = CreateBitmap (width, height, - FRAME_DISPLAY_INFO (XFRAME (frame))->n_planes, - FRAME_DISPLAY_INFO (XFRAME (frame))->n_cbits, - bits); - if (! bitmap) + Emacs_Pixmap stipple; + Emacs_Pixmap bitmap = CreateBitmap (width, height, dpyinfo->n_planes, + dpyinfo->n_cbits, bits); + + /* Convert X bitmap to W32 bitmap. */ + /* Windows mono bitmaps are reversed compared with X. */ + USE_SAFE_ALLOCA; + + { + char *invertedBits; + int nbytes = (width + CHAR_BIT - 1) / CHAR_BIT * height, i; + + invertedBits = bits; + + SAFE_NALLOCA (bits, 1, nbytes); + + for (i = 0; i < nbytes; i++) + bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]); + } + + stipple = w32_create_pixmap_from_bitmap_data (width, height, bits); + + SAFE_FREE (); + + if (!bitmap || !stipple) return -1; #endif /* HAVE_NTGUI */ @@ -681,6 +710,7 @@ image_create_bitmap_from_data (struct frame *f, char *bits, #ifdef HAVE_NTGUI dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].stipple = stipple; dpyinfo->bitmaps[id - 1].hinst = NULL; dpyinfo->bitmaps[id - 1].depth = 1; #endif /* HAVE_NTGUI */ @@ -699,7 +729,7 @@ typedef int image_fd; #endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */ #if defined HAVE_HAIKU || defined HAVE_NS || defined HAVE_PGTK \ - || defined HAVE_ANDROID + || defined HAVE_ANDROID || defined HAVE_NTGUI static char *slurp_file (image_fd, ptrdiff_t *); static Lisp_Object image_find_image_fd (Lisp_Object, image_fd *); static bool xbm_read_bitmap_data (struct frame *, char *, char *, @@ -711,10 +741,53 @@ static bool xbm_read_bitmap_data (struct frame *, char *, char *, ptrdiff_t image_create_bitmap_from_file (struct frame *f, Lisp_Object file) { -#if defined (HAVE_NTGUI) - return -1; /* W32_TODO : bitmap support */ -#else Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); + +#ifdef HAVE_NTGUI + ptrdiff_t id, size; + int width, height, rc; + image_fd fd; + char *contents, *data; + Emacs_Pixmap bitmap; + + if (!STRINGP (image_find_image_fd (file, &fd))) + return -1; + + contents = slurp_file (fd, &size); + + if (!contents) + return -1; + + rc = xbm_read_bitmap_data (f, contents, contents + size, + &width, &height, &data, 0); + + if (!rc) + { + xfree (contents); + return -1; + } + + { + /* Windows mono bitmaps are reversed compared with X. */ + + int nbytes, i; + nbytes = (width + CHAR_BIT - 1) / CHAR_BIT * height; + + for (i = 0; i < nbytes; i++) + data[i] = XBM_BIT_SHUFFLE (data[i]); + } + + id = image_allocate_bitmap_record (f); + bitmap = w32_create_pixmap_from_bitmap_data (width, height, data); + + dpyinfo->bitmaps[id - 1].height = width; + dpyinfo->bitmaps[id - 1].width = height; + dpyinfo->bitmaps[id - 1].stipple = bitmap; + dpyinfo->bitmaps[id - 1].file = xlispstrdup (file); + + xfree (contents); + xfree (data); + return id; #endif #ifdef HAVE_NS @@ -1037,6 +1110,7 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm) #ifdef HAVE_NTGUI DeleteObject (bm->pixmap); + DeleteObject (bm->stipple); #endif /* HAVE_NTGUI */ #ifdef HAVE_NS @@ -4800,12 +4874,6 @@ convert_mono_to_color_image (struct frame *f, struct image *img, img->pixmap = new_pixmap; } -#define XBM_BIT_SHUFFLE(b) (~(b)) - -#else - -#define XBM_BIT_SHUFFLE(b) (b) - #endif /* HAVE_NTGUI */ diff --git a/src/w32term.c b/src/w32term.c index 2bcd5d86a38..3ef6d0f11f1 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -1248,6 +1248,34 @@ w32_clear_glyph_string_rect (struct glyph_string *s, real_w, real_h); } +/* Fill background with bitmap pattern from S at specified position + given by X and Y. WIDTH and HEIGHT specifies bitmap size, GC is + used to get foreground and background color context and HDC where + fill it. */ + +static void +w32_fill_stipple_pattern (HDC hdc, struct glyph_string *s, Emacs_GC *gc, + int x, int y, unsigned int width, unsigned int height) +{ + SetTextColor (hdc, gc->foreground); + SetBkColor (hdc, gc->background); + + RECT r; + Emacs_Pixmap bm; + HBRUSH hb; + + r.left = x; + r.top = y; + r.right = x + width; + r.bottom = y + height; + + bm = FRAME_DISPLAY_INFO (s->f)->bitmaps[s->face->stipple - 1].stipple; + + hb = CreatePatternBrush (bm); + FillRect (hdc, &r, hb); + + DeleteObject (hb); +} /* Draw the background of glyph_string S. If S->background_filled_p is non-zero don't draw it. FORCE_P non-zero means draw the @@ -1264,21 +1292,16 @@ w32_draw_glyph_string_background (struct glyph_string *s, bool force_p) { int box_line_width = max (s->face->box_horizontal_line_width, 0); -#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ - XSetFillStyle (s->display, s->gc, FillOpaqueStippled); - XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), s->gc, s->x, - s->y + box_line_width, - s->background_width, - s->height - 2 * box_line_width); - XSetFillStyle (s->display, s->gc, FillSolid); + w32_fill_stipple_pattern (s->hdc, s, s->gc, s->x, + s->y + box_line_width, + s->background_width, + s->height - 2 * box_line_width); s->background_filled_p = true; } - else -#endif - if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font dimensions, since the actual glyphs might be much smaller. So in that case we always clear the @@ -2286,16 +2309,12 @@ w32_draw_image_foreground_1 (struct glyph_string *s, HBITMAP pixmap) static void w32_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h) { -#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ - XSetFillStyle (s->display, s->gc, FillOpaqueStippled); - XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), s->gc, x, y, w, h); - XSetFillStyle (s->display, s->gc, FillSolid); + w32_fill_stipple_pattern (s->hdc, s, s->gc, x, y, w, h); } else -#endif w32_clear_glyph_string_rect (s, x, y, w, h); } @@ -2500,16 +2519,12 @@ w32_draw_stretch_glyph_string (struct glyph_string *s) get_glyph_string_clip_rect (s, &r); w32_set_clip_rectangle (hdc, &r); -#if 0 /* TODO: stipple */ if (s->face->stipple) { /* Fill background with a stipple pattern. */ - XSetFillStyle (s->display, gc, FillOpaqueStippled); - XFillRectangle (s->display, FRAME_W32_WINDOW (s->f), gc, x, y, w, h); - XSetFillStyle (s->display, gc, FillSolid); + w32_fill_stipple_pattern (s->hdc, s, gc, x, y, w, h); } else -#endif { w32_fill_area (s->f, s->hdc, gc->background, x, y, w, h); } diff --git a/src/w32term.h b/src/w32term.h index a19be1a9e6a..38eac4230dd 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -58,6 +58,7 @@ struct w32_bitmap_record { Emacs_Pixmap pixmap; char *file; + Emacs_Pixmap stipple; HINSTANCE hinst; /* Used to load the file */ int refcount; /* Record some info about this pixmap. */ commit 5ad8ebe6e2808df001255e1f34e8c880e1e57ad4 Author: Alex Bochannek Date: Fri May 31 17:19:02 2024 -0700 Add new keyboard macro counter functions (bug#61549) Advanced keyboard macro counter commands for register integration and conditional macro termination * lisp/kmacro.el (kmacro-keymap) (kmacro-reg-load-counter, kmacro-reg-save-counter) (kmacro-reg-add-counter-equal, kmacro-reg-add-counter-less) (kmacro-reg-add-counter-greater, kmacro-reg-add-counter) (kmacro-quit-counter-equal, kmacro-quit-counter-less) (kmacro-quit-counter-greater, kmacro-quit-counter): Add advanced keyboard macro counter commands to kmacro keymap. Implement advanced keyboard macro counter commands. * test/lisp/kmacro-tests.el (kmacro-tests-test-reg-load) (kmacro-tests-test-reg-save) (kmacro-tests-test-reg-add-counter-equal-01) (kmacro-tests-test-reg-add-counter-equal-02) (kmacro-tests-test-reg-add-counter-equal-03) (kmacro-tests-test-reg-add-counter-equal-04) (kmacro-tests-test-reg-add-counter-less) (kmacro-tests-test-reg-add-counter-greater) (kmacro-tests-test-quit-counter-equal-01) (kmacro-tests-test-quit-counter-equal-02) (kmacro-tests-test-quit-counter-equal-03) (kmacro-tests-test-quit-counter-equal-04) (kmacro-tests-test-quit-counter-less) (kmacro-tests-test-quit-counter-greater): Implement unit tests for advanced keyboard macro counter commands. * etc/NEWS: Document advanced keyboard macro counter commands. diff --git a/etc/NEWS b/etc/NEWS index e5a63cc8a67..77f2e3c885a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1683,6 +1683,25 @@ The user option 'proced-auto-update-flag' can now be set to 2 additional values, which control automatic updates of Proced buffers that are not displayed in some window. +** Kmacro + ++++ +*** New Advanced Macro Counter functions. +New commands have been added to implement advanced macro counter +functions. + +The commands 'C-x C-k C-r l' and 'C-x C-k C-r s' load and save the +macro counter from and to a number register, respectively. + +The commands 'C-x C-k C-r a =', 'C-x C-k C-r a <', and +'C-x C-k C-r a >' compare the macro counter with the contents of a +number register and increment the counter by an optional prefix if the +comparison succeeds. + +The commands 'C-x C-k C-q =', 'C-x C-k C-q <', and 'C-x C-k C-q >' +compare the macro counter with an optional prefix and terminate the +macro if the comparison succeeds. + ** Kmacro Menu mode +++ diff --git a/lisp/kmacro.el b/lisp/kmacro.el index 07a13d5632c..19a0e06bbd5 100644 --- a/lisp/kmacro.el +++ b/lisp/kmacro.el @@ -187,6 +187,14 @@ macro to be executed before appending to it." "C-c" #'kmacro-set-counter "C-i" #'kmacro-insert-counter "C-a" #'kmacro-add-counter + "C-r l" #'kmacro-reg-load-counter + "C-r s" #'kmacro-reg-save-counter + "C-r a =" #'kmacro-reg-add-counter-equal + "C-r a <" #'kmacro-reg-add-counter-less + "C-r a >" #'kmacro-reg-add-counter-greater + "C-q =" #'kmacro-quit-counter-equal + "C-q <" #'kmacro-quit-counter-less + "C-q >" #'kmacro-quit-counter-greater ;; macro editing "C-e" #'kmacro-edit-macro-repeat @@ -346,6 +354,82 @@ information." (unless executing-kbd-macro (kmacro-display-counter))) +(defun kmacro-reg-load-counter (register) + "Load the value of a REGISTER into `kmacro-counter'." + (interactive + (list (register-read-with-preview "Load register to counter: "))) + (let ((register-val (get-register register))) + (when (numberp register-val) + (setq kmacro-counter register-val)))) + +(defun kmacro-reg-save-counter (register) + "Save the value of `kmacro-counter' to a REGISTER." + (interactive + (list (register-read-with-preview "Save counter to register: "))) + (set-register register kmacro-counter)) + +(defun kmacro-reg-add-counter-equal (&optional arg) + "Increment counter by one if it is equal to register value. +Optional non-nil ARG specifies the increment." + (interactive "p") + (let + ((register (register-read-with-preview "Compare counter to register: "))) + (kmacro-reg-add-counter #'= register arg))) + +(defun kmacro-reg-add-counter-less (&optional arg) + "Increment counter by one if it is less than register value. +Optional non-nil ARG specifies increment." + (interactive "p") + (let + ((register (register-read-with-preview "Compare counter to register: "))) + (kmacro-reg-add-counter #'< register arg))) + + +(defun kmacro-reg-add-counter-greater (&optional arg) + "Increment counter by one if it is greater than register value. +Optional non-nil ARG specifies increment." + (interactive "p") + (let + ((register (register-read-with-preview "Compare counter to register: "))) + (kmacro-reg-add-counter #'> register arg))) + +(defun kmacro-reg-add-counter (pred register arg) + "Increment `kmacro-counter' by ARG if PRED returns non-nil. +PRED is called with two arguments: `kmacro-counter' and REGISTER." + (let ((register-val (get-register register))) + (when (funcall pred kmacro-counter register-val) + (setq current-prefix-arg nil) + (kmacro-add-counter arg)))) + +(defun kmacro-quit-counter-equal (&optional arg) + "Quit the keyboard macro if the counter is equal to ARG. +ARG defaults to zero if nil or omitted." + (interactive "p") + (kmacro-quit-counter #'= arg)) + +(defun kmacro-quit-counter-less (&optional arg) + "Quit the keyboard macro if the counter is less than ARGS. +ARG defaults to zero if nil or omitted." + (interactive "p") + (kmacro-quit-counter #'< arg)) + +(defun kmacro-quit-counter-greater (&optional arg) + "Quit the keyboard macro if the counter is greater than ARG. +ARG defaults to zero if nil or omitted." + (interactive "p") + (kmacro-quit-counter #'> arg)) + +(defun kmacro-quit-counter (pred arg) + "Quit the keyboard macro if PRED returns non-nil. +PRED is called with two arguments: `kmacro-counter' and ARG. +ARG defaults to zero if it is nil." + (when kmacro-initial-counter-value + (setq kmacro-counter kmacro-initial-counter-value + kmacro-initial-counter-value nil)) + (let ((arg (if (null current-prefix-arg) + 0 arg))) + (when (funcall pred kmacro-counter arg) + (keyboard-quit)))) (defun kmacro-loop-setup-function () "Function called prior to each iteration of macro." diff --git a/test/lisp/kmacro-tests.el b/test/lisp/kmacro-tests.el index 2eead234988..52abe138ae9 100644 --- a/test/lisp/kmacro-tests.el +++ b/test/lisp/kmacro-tests.el @@ -275,6 +275,219 @@ cause the current test to fail." ;; Verify that the recording state has changed. (should (equal defining-kbd-macro 'append)))) + +(kmacro-tests-deftest kmacro-tests-test-reg-load () + "`kmacro-reg-load-counter' loads the value of a register into the counter." + (set-register ?\C-r 4) ;; Should be safe as a register name + (kmacro-tests-simulate-command '(kmacro-set-counter 1)) + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + "\C-x\C-k\C-i" + ;; Load from register + "\C-x\C-k\C-rl\C-r" + )) + (kmacro-tests-should-insert "1245" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-save () + "`kmacro-reg-save-counter' saves the counter to a register." + (set-register ?\C-r nil) ;; Should be safe as a register name + (kmacro-tests-simulate-command '(kmacro-set-counter 1)) + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Save to register + "\C-x\C-k\C-rs\C-r" + ;; Add to counter + "\C-u2\C-x\C-k\C-a" + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Insert register + "\C-xri\C-r" + )) + (kmacro-tests-should-insert "142586" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2))) + (set-register ?\C-r nil)) + + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-01 () + "`kmacro-reg-add-counter-equal' increments counter by one if equal to register." + (set-register ?\C-r 2) ;; Should be safe as a register name + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Increment counter if it matches + "\C-x\C-k\C-ra=\C-r" + )) + (kmacro-tests-should-insert "0134" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-02 () + "`kmacro-reg-add-counter-equal' increments counter by prefix if equal to register." + (set-register ?\C-r 2) ;; Should be safe as a register name + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Add two to counter if it matches + "\C-u2\C-x\C-k\C-ra=\C-r" + )) + (kmacro-tests-should-insert "0145" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-03 () + "`kmacro-reg-add-counter-equal' increments counter by universal arg if equal to register." + (set-register ?\C-r 2) ;; Should be safe as a register name + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Add four to counter if it matches + "\C-u\C-x\C-k\C-ra=\C-r" + )) + (kmacro-tests-should-insert "0167" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-04 () + "`kmacro-reg-add-counter-equal' decrements counter by one if equal to register." + (set-register ?\C-r 2) ;; Should be safe as a register name + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Decrement counter if it matches + "\C-u-\C-x\C-k\C-ra=\C-r" + )) + (kmacro-tests-should-insert "0111" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-less () + "`kmacro-reg-add-counter-less' decrements counter if less than register." + (set-register ?\C-r 6) ;; Should be safe as a register name + (kmacro-tests-simulate-command '(kmacro-set-counter 7)) + (kmacro-tests-define-macro (vconcat + ;; Decrement counter if it's + ;; less than the register + "\C-u-\C-x\C-k\C-ra<\C-r" + ;; Insert and decrement counter + "\C-u-\C-x\C-k\C-i" + )) + (kmacro-tests-should-insert "7642" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + +(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-greater () + "`kmacro-reg-add-counter-greater' increments counter if greater than register." + (set-register ?\C-r 1) ;; Should be safe as a register name + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Increment counter if it's greater + ;; than the register + "\C-x\C-k\C-ra>\C-r" + )) + (kmacro-tests-should-insert "0135" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (set-register ?\C-r nil)) + + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-01 () + "`kmacro-quit-counter-equal' stops macro if counter is equal to positive prefix." + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Stop if the counter is at 5 + "\C-u5\C-x\C-k\C-q=" + )) + (kmacro-tests-should-insert "0123" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should (= 4 kmacro-counter)) + (should (condition-case abort + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort)))) + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-02 () + "`kmacro-quit-counter-equal' stops macro if counter is equal to zero." + (kmacro-tests-simulate-command '(kmacro-set-counter 5)) + (kmacro-tests-define-macro (vconcat + ;; Insert and decrement counter + "\C-u-\C-x\C-k\C-i" + ;; Stop if the counter is at 0 + "\C-x\C-k\C-q=" + )) + (kmacro-tests-should-insert "5432" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should (= 1 kmacro-counter)) + (should (condition-case abort + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort)))) + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-03 () + "`kmacro-quit-counter-equal' stops macro if counter is equal to negative prefix." + (kmacro-tests-simulate-command '(kmacro-set-counter 4)) + (kmacro-tests-define-macro (vconcat + ;; Insert and decrement counter + "\C-u-\C-x\C-k\C-i" + ;; Stop if the counter is at -1 + "\C-u-\C-x\C-k\C-q=" + )) + (kmacro-tests-should-insert "4321" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should (= 0 kmacro-counter)) + (should (condition-case abort + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort)))) + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-04 () + "`kmacro-quit-counter-equal' doesn't stop macro if counter doesn't equal prefix." + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-u2\C-x\C-k\C-i" + ;; Stop if the counter is at 7 + "\C-u7\C-x\C-k\C-q=" + )) + (kmacro-tests-should-insert "0246" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should-not (condition-case abort + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort))) + (should (= 10 kmacro-counter))) + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-less () + "`kmacro-quit-counter-less' stops macro if counter is less than prefix." + (kmacro-tests-simulate-command '(kmacro-set-counter 8)) + (kmacro-tests-define-macro (vconcat + ;; Stop if the counter is less than 5 + "\C-u5\C-x\C-k\C-q<" + ;; Insert and decrement counter + "\C-u-\C-x\C-k\C-i" + )) + (kmacro-tests-should-insert "8765" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should (condition-case abort + (should (= 4 kmacro-counter)) + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort)))) + +(kmacro-tests-deftest kmacro-tests-test-quit-counter-greater () + "`kmacro-quit-counter-greater' stops macro if counter is greater than prefix." + (kmacro-tests-define-macro (vconcat + ;; Insert and increment counter + "\C-x\C-k\C-i" + ;; Stop if the counter is greater than 4 + "\C-u4\C-x\C-k\C-q>" + )) + (kmacro-tests-should-insert "0123" + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4))) + (should (condition-case abort + (should (= 4 kmacro-counter)) + (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1)) + (quit abort)))) + + (kmacro-tests-deftest kmacro-tests-end-call-macro-prefix-args () "kmacro-end-call-macro changes behavior based on prefix arg." ;; "Record" two macros. commit a0519d6d09c6df86adc658a89e97926bb352eb05 Author: Eli Zaretskii Date: Sun Jun 2 08:37:57 2024 +0300 ; * lisp/image/image-dired-external.el (image-dired-set-exif-data): Doc fix. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 8a270bb9388..da272c146c9 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -623,7 +623,10 @@ default value at the prompt." (string-replace "\n" "" (buffer-string)))))))) (defun image-dired-set-exif-data (file tag-name tag-value) - "In FILE, set EXIF tag TAG-NAME to value TAG-VALUE." + "In FILE, set EXIF tag TAG-NAME to value TAG-VALUE. +This function inserts any output from `exiftool' program into +the current buffer, so it could be shown to the user. If that +is not desirable, wrap the call in `with-temp-buffer'." (image-dired--check-executable-exists 'image-dired-cmd-write-exif-data-program) (let ((spec commit 9a2088bdd928b384beca3c95c2719843f74924a0 Author: Gerd Möllmann Date: Sat Jun 1 21:05:50 2024 +0200 Fix LLDB frame-format for optional column number info * lisp/progmodes/gud.el (gud--lldb-python-init-string): In the !gud part, make column number info optional by putting it in a scope. diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index c16d78c5097..7486804da1b 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -3959,7 +3959,7 @@ so they have been disabled.")) deb = lldb.debugger inst = deb.GetInstanceName() ff = deb.GetInternalVariableValue('frame-format', inst).GetStringAtIndex(0) -ff = ff[:-1] + '!gud ${line.number}:${line.column}:${line.file.fullpath}\\\\n\"' +ff = ff[:-1] + '!gud ${line.number}:{${line.column}}:${line.file.fullpath}\\\\n\"' _ = deb.SetInternalVariable('frame-format', ff, inst) def gud_complete(s, max): interpreter = lldb.debugger.GetCommandInterpreter() commit 8ecf1a995fc318ea055cbc71f9223340feb2acd0 Author: Eli Zaretskii Date: Sat Jun 1 20:50:40 2024 +0300 Improve error handling in 'image-dired-thumbnail-set-image-description'. * lisp/image/image-dired-external.el (image-dired-thumbnail-set-image-description): Show more detailed error messages in case of failure. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 1fa94e06e02..8a270bb9388 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -609,13 +609,18 @@ default value at the prompt." (if (not (image-dired-image-at-point-p)) (message "No thumbnail at point") (let* ((file (image-dired-original-file-name)) - (old-value (or (exif-field 'description (exif-parse-file file)) ""))) - (if (eq 0 - (image-dired-set-exif-data file "ImageDescription" - (read-string "Value of ImageDescription: " - old-value))) - (message "Successfully wrote ImageDescription tag") - (error "Could not write ImageDescription tag"))))) + (old-value (or (exif-field 'description (exif-parse-file file)) "")) + (defdir default-directory)) + (with-temp-buffer + (setq default-directory defdir) + (if (eq 0 + (image-dired-set-exif-data file "ImageDescription" + (read-string + "Value of ImageDescription: " + old-value))) + (message "Successfully wrote ImageDescription tag") + (error "Could not write ImageDescription tag: %s" + (string-replace "\n" "" (buffer-string)))))))) (defun image-dired-set-exif-data (file tag-name tag-value) "In FILE, set EXIF tag TAG-NAME to value TAG-VALUE." @@ -627,7 +632,7 @@ default value at the prompt." (cons ?u (image-dired--file-URI (expand-file-name file))) (cons ?t tag-name) (cons ?v tag-value)))) - (apply #'call-process image-dired-cmd-write-exif-data-program nil nil nil + (apply #'call-process image-dired-cmd-write-exif-data-program nil t nil (mapcar (lambda (arg) (format-spec arg spec)) image-dired-cmd-write-exif-data-options)))) commit d98ec75d649758c9fe96a7054c0a7829d04525a0 Author: Eli Zaretskii Date: Sat Jun 1 20:40:53 2024 +0300 ; * doc/emacs/dired.texi (Image-Dired): Improve and extend. diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi index 898c0bfaade..720d27ab3bb 100644 --- a/doc/emacs/dired.texi +++ b/doc/emacs/dired.texi @@ -1680,6 +1680,44 @@ directory, and displays them all in the thumbnail buffer. The thumbnails are generated in the background and are loaded as they become available. +@vindex image-dired-thumbnail-storage + Image-Dired supports three methods of generating and storing +thumbnails, controlled by the value of the option +@code{image-dired-thumbnail-storage}: + +@table @code +@vindex image-dired-dir +@vindex image-dired-thumb-naming +@item image-dired +This method stores thumbnails as @sc{JPEG} images in a single directory +specified by the variable @code{image-dired-dir}. This is the default. +The names of the thumbnail files are in this case constructed according +to the value of @code{image-dired-thumb-naming}. +@item standard +@itemx standard-large +@itemx standard-x-large +@itemx standard-xx-large +These methods, mandated by the +@url{https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html, +Thumbnail Managing Standard}, store thumbnails as @sc{PNG} images under +the @file{thumbnails} subdirectory of the directory specified by the +environment variable @env{XDG_CACHE_HOME} (which defaults to +@file{~/.cache}). +@item per-directory +This method stores the thumbnails of each directory in a +@file{.image-dired} subdirectory of that directory, as @sc{JPEG} images. +@end table + +@vindex image-dired-thumb-size + You can control the size of the thumbnail images by customizing the +variable @code{image-dired-thumb-size}. The default is 128 pixels. +This variable is in effect only for the first and the third method of +thumbnail storage described above; the Thumbnail Managing Standard uses +fixed sizes determined by the method: @code{standard} uses 128 pixels, +@code{standard-large} 256 pixels, etc. If you change the size after +some thumbnails were already created, you need to erase the thumbnail +files from their directory to have the new size take effect. + @findex image-dired-display-this @findex image-dired-display-next @findex image-dired-display-previous @@ -1737,6 +1775,13 @@ a comment from Dired (@code{image-dired-dired-comment-files}). @kbd{C-t e} will bring a buffer to edit comment and tags (@code{image-dired-dired-edit-comment-and-tags}). +@findex image-dired-thumbnail-set-image-description + If you have the @command{exiftool} program installed, you can set the +@sc{EXIF} @samp{ImageDescription} tag of an image file by invoking the +@code{image-dired-thumbnail-set-image-description} command with point at +the thumbnail of the image file. This command prompts for the +description of the image, and adds the @sc{EXIF} tag to it. + @vindex image-dired-thumb-visible-marks Files that are marked in Dired will also be marked in Image-Dired if @code{image-dired-thumb-visible-marks} is non-@code{nil} (which is the commit f0cd7eab0967c787703f144ac9d7c04e1d866306 Author: Michael Albinus Date: Sat Jun 1 19:22:21 2024 +0200 Minor Tramp changes * lisp/net/tramp-adb.el: * lisp/net/tramp-container.el: Add myself as maintainer. * lisp/net/tramp-compat.el (connection-local-default-application): Define if not bound. (tramp-compat-connection-local-p, tramp-compat-connection-local-value): Use it. diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index b794d8b481a..9db313e3ed0 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -3,6 +3,7 @@ ;; Copyright (C) 2011-2024 Free Software Foundation, Inc. ;; Author: Jürgen Hötzel +;; Maintainer: Michael Albinus ;; Keywords: comm, processes ;; Package: tramp diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index bbffdf7f3d9..f1e7a801ec1 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el @@ -304,6 +304,12 @@ Also see `ignore'." (lambda (function sequence) (delq nil (seq-map function sequence))))) +;; User option `connection-local-default-application' is new in Emacs 29.1. +(unless (boundp 'connection-local-default-application) + (defvar connection-local-default-application 'tramp + "Default application in connection-local functions, a symbol. +This variable must not be changed globally.")) + ;; User option `password-colon-equivalents' is new in Emacs 30.1. (if (boundp 'password-colon-equivalents) (defvaralias @@ -329,9 +335,10 @@ If APPLICATION is nil, the value of (declare (debug (symbolp &optional form))) (unless (symbolp variable) (signal 'wrong-type-argument (list 'symbolp variable))) - `(let ((criteria - (connection-local-criteria-for-default-directory ,application)) - connection-local-variables-alist file-local-variables-alist) + `(let* ((connection-local-default-application + (or ,application connection-local-default-application)) + (criteria (connection-local-criteria-for-default-directory)) + connection-local-variables-alist file-local-variables-alist) (when criteria (hack-connection-local-variables criteria) (and (assq ',variable connection-local-variables-alist) t))))) @@ -348,9 +355,10 @@ value is the default binding of the variable." (declare (debug (symbolp &optional form))) (unless (symbolp variable) (signal 'wrong-type-argument (list 'symbolp variable))) - `(let ((criteria - (connection-local-criteria-for-default-directory ,application)) - connection-local-variables-alist file-local-variables-alist) + `(let* ((connection-local-default-application + (or ,application connection-local-default-application)) + (criteria (connection-local-criteria-for-default-directory)) + connection-local-variables-alist file-local-variables-alist) (if (not criteria) ,variable (hack-connection-local-variables criteria) diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el index 278ce033da6..d0edbfea1e8 100644 --- a/lisp/net/tramp-container.el +++ b/lisp/net/tramp-container.el @@ -3,6 +3,7 @@ ;; Copyright © 2022-2024 Free Software Foundation, Inc. ;; Author: Brian Cully +;; Maintainer: Michael Albinus ;; Keywords: comm, processes ;; Package: tramp commit a154f0aa73bceeaaeefcd243e7db9d09e3f450d7 Author: Dmitry Gutov Date: Sat Jun 1 18:03:42 2024 +0300 shell-command-mode: New major mode for async-shell-command * etc/NEWS: Mention the additions. * lisp/shell.el (shell-command-mode): New major mode (bug#71049). * lisp/simple.el (async-shell-command-mode): New variable, with default value pointing to that mode. (shell-command): Refer to it here. (async-shell-command): Update docstring. * lisp/net/tramp.el (tramp-handle-shell-command): Use the new variable when available. diff --git a/etc/NEWS b/etc/NEWS index 2cae3730602..e5a63cc8a67 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1902,6 +1902,11 @@ than regular expressions, but less complexity than context-free grammars. The Info manual "(elisp) Parsing Expression Grammars" has documentation and examples. +** New major mode 'shell-command-mode'. +This mode is used by default for the output of 'async-shell-command'. +To revert to the previous behavior, set the (also new) variable +'async-shell-command-mode' to 'shell-mode'. Any hooks or mode-specific +variables used should be adapted appropriately. * Incompatible Lisp Changes in Emacs 30.1 diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index b2442f4538c..3dffe7544ab 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -5259,8 +5259,13 @@ support symbolic links." ;; Display output. (with-current-buffer output-buffer (setq mode-line-process '(":%s")) - (unless (eq major-mode 'shell-mode) - (shell-mode)) + (cond + ((boundp 'async-shell-command-mode) + ;; Emacs 30+ + (unless (eq major-mode async-shell-command-mode) + (funcall async-shell-command-mode))) + ((not (eq major-mode 'shell-mode)) + (shell-mode))) (set-process-filter p #'comint-output-filter) (set-process-sentinel p #'shell-command-sentinel) (when error-file diff --git a/lisp/shell.el b/lisp/shell.el index b3201726762..4352811912a 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -838,6 +838,13 @@ Sentinels will always get the two parameters PROCESS and EVENT." (with-current-buffer buf (insert (format "\nProcess %s %s\n" process event)))))) +(define-derived-mode shell-command-mode comint-mode "Shell" + "Major mode for the output of asynchronous `shell-command'." + (setq-local font-lock-defaults '(shell-font-lock-keywords t)) + ;; See comments in `shell-mode'. + (setq-local ansi-color-apply-face-function #'shell-apply-ansi-color) + (setq list-buffers-directory (expand-file-name default-directory))) + ;;;###autoload (defun shell (&optional buffer file-name) "Run an inferior shell, with I/O through BUFFER (which defaults to `*shell*'). diff --git a/lisp/simple.el b/lisp/simple.el index cb7a54409a6..68209eadc41 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -31,7 +31,6 @@ (eval-when-compile (require 'cl-lib)) (declare-function widget-convert "wid-edit" (type &rest args)) -(declare-function shell-mode "shell" ()) ;;; From compile.el (defvar compilation-current-error) @@ -4488,9 +4487,10 @@ to execute it asynchronously. The output appears in OUTPUT-BUFFER, which could be a buffer or the name of a buffer, and defaults to `shell-command-buffer-name-async' -if nil or omitted. That buffer is in shell mode. Note that, unlike -with `shell-command', OUTPUT-BUFFER can only be a buffer, a buffer's -name (a string), or nil. +if nil or omitted. That buffer is in major mode specified by the +variable `async-shell-command-mode'. Note that, unlike with +`shell-command', OUTPUT-BUFFER can only be a buffer, a buffer's name +(a string), or nil. You can customize `async-shell-command-buffer' to specify what to do when the buffer specified by `shell-command-buffer-name-async' is @@ -4534,6 +4534,9 @@ a shell (with its need to quote arguments)." (declare-function comint-output-filter "comint" (process string)) (declare-function comint-term-environment "comint" ()) +(defvar async-shell-command-mode 'shell-command-mode + "Major mode to use for the output of asynchronous `shell-command'.") + (defun shell-command (command &optional output-buffer error-buffer) "Execute string COMMAND in inferior shell; display output, if any. With prefix argument, insert the COMMAND's output at point. @@ -4544,9 +4547,9 @@ directory in the prompt. If COMMAND ends in `&', execute it asynchronously. The output appears in the buffer whose name is specified -by `shell-command-buffer-name-async'. That buffer is in shell -mode. You can also use `async-shell-command' that automatically -adds `&'. +by `shell-command-buffer-name-async'. That buffer is in major mode +specified by the variable `async-shell-command-mode'. You can also use +`async-shell-command' that automatically adds `&'. Otherwise, COMMAND is executed synchronously. The output appears in the buffer named by `shell-command-buffer-name'. If the output is @@ -4722,7 +4725,7 @@ impose the use of a shell (with its need to quote arguments)." (setq proc (start-process-shell-command "Shell" buffer command))) (setq mode-line-process '(":%s")) - (shell-mode) + (funcall async-shell-command-mode) (setq-local revert-buffer-function (lambda (&rest _) (async-shell-command command buffer))) commit d91ad9be5a72974784e0552069020c3ae0bc830e Author: Dmitry Gutov Date: Sat Jun 1 17:47:13 2024 +0300 go-ts-mode: Highlight variadic function parameter names * lisp/progmodes/go-ts-mode.el (go-ts-mode--font-lock-settings): Add matcher for variadic parameter declarations. diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 43f7e042590..2d3e6aac090 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -175,6 +175,8 @@ name: (field_identifier) @font-lock-property-name-face) (parameter_declaration name: (identifier) @font-lock-variable-name-face) + (variadic_parameter_declaration + name: (identifier) @font-lock-variable-name-face) (short_var_declaration left: (expression_list (identifier) @font-lock-variable-name-face commit 302142189222f4a1ba75bc2c8ce00307c2499689 Author: Noah Peart Date: Sun May 26 05:34:34 2024 -0700 Add font-locking for variables in go-ts-mode range clauses (bug#71209) * lisp/progmodes/go-ts-mode.el (go-ts-mode--font-lock-settings): Add font-locking rule for variable names in range clauses. * test/lisp/progmodes/go-ts-mode-tests.el (go-ts-test-font-lock): Add font-locking test for go-ts-mode. * test/lisp/progmodes/go-ts-mode-resources/font-lock.go: New file for go-ts-mode font-locking tests. diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index aef224ab3fa..43f7e042590 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -180,7 +180,10 @@ (identifier) @font-lock-variable-name-face ("," (identifier) @font-lock-variable-name-face)*)) (var_spec name: (identifier) @font-lock-variable-name-face - ("," name: (identifier) @font-lock-variable-name-face)*)) + ("," name: (identifier) @font-lock-variable-name-face)*) + (range_clause + left: (expression_list + (identifier) @font-lock-variable-name-face))) :language 'go :feature 'function diff --git a/test/lisp/progmodes/go-ts-mode-resources/font-lock.go b/test/lisp/progmodes/go-ts-mode-resources/font-lock.go new file mode 100644 index 00000000000..4e7a8e1710b --- /dev/null +++ b/test/lisp/progmodes/go-ts-mode-resources/font-lock.go @@ -0,0 +1,5 @@ +for idx, val := range arr {} +// ^ font-lock-variable-name-face +// ^ font-lock-variable-name-face +for idx := 0; idx < n; idx++ {} +// ^ font-lock-variable-name-face diff --git a/test/lisp/progmodes/go-ts-mode-tests.el b/test/lisp/progmodes/go-ts-mode-tests.el index fd9b57e8691..f36dbde5103 100644 --- a/test/lisp/progmodes/go-ts-mode-tests.el +++ b/test/lisp/progmodes/go-ts-mode-tests.el @@ -27,5 +27,10 @@ (skip-unless (treesit-ready-p 'go)) (ert-test-erts-file (ert-resource-file "indent.erts"))) +(ert-deftest go-ts-test-font-lock () + (skip-unless (treesit-ready-p 'go)) + (let ((treesit-font-lock-level 4)) + (ert-font-lock-test-file (ert-resource-file "font-lock.go") 'go-ts-mode))) + (provide 'go-ts-mode-tests) ;;; go-ts-mode-tests.el ends here commit d2dce513445d7235c9f751ea6d9b4847d62882e7 Author: Eli Zaretskii Date: Sat Jun 1 16:43:18 2024 +0300 Fix misc problems with thumbnails on MS-Windows * lisp/image/image-dired-external.el (image-dired-pngcrush-thumb): Fix deletion of intermediate file. (image-dired-cmd-pngcrush-options) (image-dired-cmd-create-standard-thumbnail-options): Use %u for file:// URI. (image-dired--file-URI): New function. (image-dired-create-thumb-1, image-dired-create-thumb-2) (image-dired-set-exif-data): Use it to generate correct URI on MS-Windows. * src/w32image.c (Fw32image_create_thumbnail): Copy the file names before mirroring their slashes. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 20438fa12e7..1fa94e06e02 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -103,21 +103,24 @@ It optimizes the compression of PNG images. It also adds PNG textual chunks with the information required by the Thumbnail Managing Standard." :type '(choice (const :tag "Not Set" nil) file)) +;; Note: the "-text" arguments below are according to specification in +;; https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#CREATION (defcustom image-dired-cmd-pngcrush-options `("-q" - "-text" "b" "Description" "Thumbnail of file://%f" - "-text" "b" "Software" ,(emacs-version) + "-text" "b" "Description" "Thumbnail of file://%u" + "-text" "b" "Software" ,(string-replace "\n" " " (emacs-version)) ;; "-text b \"Thumb::Image::Height\" \"%oh\" " ;; "-text b \"Thumb::Image::Mimetype\" \"%mime\" " ;; "-text b \"Thumb::Image::Width\" \"%ow\" " "-text" "b" "Thumb::MTime" "%m" ;; "-text b \"Thumb::Size\" \"%b\" " - "-text" "b" "Thumb::URI" "file://%f" + "-text" "b" "Thumb::URI" "file://%u" "%q" "%t") "Arguments for `image-dired-cmd-pngcrush-program'. The value can use the same %-format specifiers as in -`image-dired-cmd-create-thumbnail-options', with \"%q\" for a -temporary file name (typically generated by pnqnq)." +`image-dired-cmd-create-thumbnail-options', with \"%q\" standing for a +temporary file name (typically generated by pnqnq), +and \"%u\" standing for a file URI corresponding to file in \"%f\"." :version "26.1" :type '(repeat (string :tag "Argument"))) @@ -134,20 +137,22 @@ The value can use the same %-format specifiers as in :type '(repeat (string :tag "Argument")) :link '(url-link "man:optipng(1)")) +;; Note: the "-set" arguments below are according to specification in +;; https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#CREATION (defcustom image-dired-cmd-create-standard-thumbnail-options (let ((opts (list "-size" "%wx%h" "%f[0]" "-set" "Thumb::MTime" "%m" - "-set" "Thumb::URI" "file://%f" - "-set" "Description" "Thumbnail of file://%f" - "-set" "Software" (emacs-version) + "-set" "Thumb::URI" "file://%u" + "-set" "Description" "Thumbnail of file://%u" + "-set" "Software" (string-replace "\n" " " (emacs-version)) "-thumbnail" "%wx%h>" "png:%t"))) (if (executable-find "gm") (cons "convert" opts) opts)) "Options for creating thumbnails according to the Thumbnail Managing Standard. Used with `image-dired-cmd-create-thumbnail-program', if that is available. The value can use the same %-format specifiers as in `image-dired-cmd-create-thumbnail-options', with \"%m\" for file -modification time. +modification time and \"%u\" for the URI of the file in \"%f\". On MS-Windows, if the `convert' command is not available, and `w32image-create-thumbnail' is used instead, the textual chunks specified by the \"-set\" options will not be injected, and instead @@ -196,6 +201,12 @@ and %v which is replaced by the tag value." ;;; Util functions +(defun image-dired--file-URI (file) + ;; https://en.wikipedia.org/wiki/File_URI_scheme + (if (memq system-type '(windows-nt ms-dos)) + (concat "/" file) + file)) + (defun image-dired--probe-thumbnail-cmd (cmd) "Check whether CMD is usable for thumbnail creation." (cond @@ -327,11 +338,11 @@ on MS-Windows cannot have too many concurrent sub-processes.") (message "command %S %s" (process-command process) (string-replace "\n" "" status)) (message "command %S failed with status %s" - process status)) + process status))) (when (or (not (processp process)) (memq (process-status process) '(exit signal))) (let ((temp (cdr (assq ?q spec)))) - (delete-file temp)))))) + (delete-file temp))))) (proc (if (eq system-type 'windows-nt) ;; See above for the reasons we don't use 'start-process' @@ -385,6 +396,7 @@ on MS-Windows cannot have too many concurrent sub-processes.") (spec `((?s . ,size) (?w . ,size) (?h . ,size) (?m . ,modif-time) (?f . ,original-file) + (?u . ,(image-dired--file-URI original-file)) (?q . ,thumbnail-nq8-file) (?t . ,thumbnail-file))) (thumbnail-dir (file-name-directory thumbnail-file)) @@ -471,6 +483,7 @@ file is created by Emacs itself." (spec `((?s . ,size) (?w . ,size) (?h . ,size) (?m . ,modif-time) (?f . ,original-file) + (?u . ,(image-dired--file-URI original-file)) (?q . ,thumbnail-nq8-file) (?t . ,thumbnail-file)))) (cond @@ -611,6 +624,7 @@ default value at the prompt." (let ((spec (list (cons ?f (expand-file-name file)) + (cons ?u (image-dired--file-URI (expand-file-name file))) (cons ?t tag-name) (cons ?v tag-value)))) (apply #'call-process image-dired-cmd-write-exif-data-program nil nil nil diff --git a/src/w32image.c b/src/w32image.c index 6daf42c1916..e71471f4a7c 100644 --- a/src/w32image.c +++ b/src/w32image.c @@ -631,7 +631,8 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) /* Create an image by reading from INPUT_FILE. */ wchar_t input_file_w[MAX_PATH]; - input_file = ENCODE_FILE (Fexpand_file_name (input_file, Qnil)); + input_file + = ENCODE_FILE (Fexpand_file_name (Fcopy_sequence (input_file), Qnil)); unixtodos_filename (SSDATA (input_file)); filename_to_utf16 (SSDATA (input_file), input_file_w); GpImage *file_image; @@ -652,7 +653,9 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) { /* Save the thumbnail image to a file of specified TYPE. */ wchar_t thumb_file_w[MAX_PATH]; - thumb_file = ENCODE_FILE (Fexpand_file_name (thumb_file, Qnil)); + thumb_file + = ENCODE_FILE (Fexpand_file_name (Fcopy_sequence (thumb_file), + Qnil)); unixtodos_filename (SSDATA (thumb_file)); filename_to_utf16 (SSDATA (thumb_file), thumb_file_w); status = GdipSaveImageToFile (thumb_image, thumb_file_w, commit 7af5d6fc9a352d4f53f8e48a6bc9ae9a3bf235a3 Author: Po Lu Date: Sat Jun 1 21:27:51 2024 +0800 Improve touch-screen support on PGTK * lisp/touch-screen.el (touch-screen-translate-touch): Do not prepend posn if the symbol is such that keyboard.c will do so immediately after returning. * src/pgtkterm.c (pgtk_toolkit_position): Remove mistakenly ported code. (pgtk_create_terminal): Remove toolkit_position hook. (motion_notify_event, button_event): Ignore emulated pointer events, and apply an additional test to circumvent a GDK oversight. (touch_event_cb): Correct return type, and provide touch sequence initialization and removal events as `last_click_event's. diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index b77f3a6e07d..828810e7b33 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -1852,10 +1852,17 @@ if POSN is on a link or a button, or `mouse-1' otherwise." ;; no key events have been translated. (if event (or (and prefix (consp event) ;; Only generate virtual function keys for - ;; mouse events. + ;; mouse events... (memq (car event) '(down-mouse-1 mouse-1 mouse-2 mouse-movement)) + ;; .. and provided that Emacs has never + ;; previously encountered an event of this + ;; description, so that its `event-kind' + ;; property has yet to be initialized and + ;; keyboard.c will not understand whether and + ;; how to append a function key prefix. + (null (get (car event) 'event-kind)) ;; If this is a mode line event, then ;; generate the appropriate function key. (vector prefix event)) diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 886f115c391..49b7ea406f8 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -224,34 +224,6 @@ pgtk_regenerate_devices (struct pgtk_display_info *dpyinfo) pgtk_enumerate_devices (dpyinfo, false); } -static void -pgtk_toolkit_position (struct frame *f, int x, int y, - bool *menu_bar_p, bool *tool_bar_p) -{ - GdkRectangle test_rect; - int scale; - - y += (FRAME_MENUBAR_HEIGHT (f) - + FRAME_TOOLBAR_TOP_HEIGHT (f)); - x += FRAME_TOOLBAR_LEFT_WIDTH (f); - - if (FRAME_EXTERNAL_MENU_BAR (f)) - *menu_bar_p = (x >= 0 && x < FRAME_PIXEL_WIDTH (f) - && y >= 0 && y < FRAME_MENUBAR_HEIGHT (f)); - - if (FRAME_X_OUTPUT (f)->toolbar_widget) - { - scale = xg_get_scale (f); - test_rect.x = x / scale; - test_rect.y = y / scale; - test_rect.width = 1; - test_rect.height = 1; - - *tool_bar_p = gtk_widget_intersect (FRAME_X_OUTPUT (f)->toolbar_widget, - &test_rect, NULL); - } -} - static Lisp_Object pgtk_get_device_for_event (struct pgtk_display_info *dpyinfo, GdkEvent *event) @@ -4042,8 +4014,8 @@ xg_scroll_callback (GtkRange * range, /* Callback for button release. Sets dragging to -1 when dragging is done. */ static gboolean -xg_end_scroll_callback (GtkWidget * widget, - GdkEventButton * event, gpointer user_data) +xg_end_scroll_callback (GtkWidget *widget, + GdkEventButton *event, gpointer user_data) { struct scroll_bar *bar = user_data; bar->dragging = -1; @@ -4889,7 +4861,6 @@ pgtk_create_terminal (struct pgtk_display_info *dpyinfo) terminal->focus_frame_hook = pgtk_focus_frame; terminal->set_frame_offset_hook = pgtk_set_offset; terminal->free_pixmap = pgtk_free_pixmap; - terminal->toolkit_position_hook = pgtk_toolkit_position; /* Other hooks are NULL by default. */ @@ -5929,6 +5900,17 @@ motion_notify_event (GtkWidget *widget, GdkEvent *event, struct frame *f, *frame; struct pgtk_display_info *dpyinfo; Mouse_HLInfo *hlinfo; + GdkDevice *device; + + /* Ignore emulated pointer events generated from a touch screen + event. */ + if (gdk_event_get_pointer_emulated (event) + /* The event must not have emerged from a touch device either, as + GDK does not set pointer_emulated in events generated on + Wayland as on X, and as the X Input Extension specifies. */ + || ((device = gdk_event_get_source_device (event)) + && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) + return FALSE; EVENT_INIT (inev.ie); inev.ie.kind = NO_EVENT; @@ -6068,6 +6050,17 @@ button_event (GtkWidget *widget, GdkEvent *event, bool tab_bar_p = false; bool tool_bar_p = false; Lisp_Object tab_bar_arg = Qnil; + GdkDevice *device; + + /* Ignore emulated pointer events generated from a touch screen + event. */ + if (gdk_event_get_pointer_emulated (event) + /* The event must not have emerged from a touch device either, as + GDK does not set pointer_emulated in events generated on + Wayland as on X, and as the X Input Extension specifies. */ + || ((device = gdk_event_get_source_device (event)) + && (gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN))) + return FALSE; EVENT_INIT (inev.ie); inev.ie.kind = NO_EVENT; @@ -6642,7 +6635,7 @@ pgtk_find_touch_point (struct pgtk_display_info *dpyinfo, return NULL; } -static bool +static gboolean touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) { struct pgtk_display_info *dpyinfo; @@ -6742,6 +6735,15 @@ touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) { inev.ie.device = pgtk_get_device_for_event (dpyinfo, event); evq_enqueue (&inev); + + /* Next, save this event for future menu activations, unless it is + only an update. */ + if (event->type != GDK_TOUCH_UPDATE) + { + if (dpyinfo->last_click_event != NULL) + gdk_event_free (dpyinfo->last_click_event); + dpyinfo->last_click_event = gdk_event_copy (event); + } } return inev.ie.kind != NO_EVENT; commit b4a93b4484c7406a395f1c1f3e8d1236138ba2a9 Author: Eli Zaretskii Date: Sat Jun 1 15:37:51 2024 +0300 ; Fix a typo. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 4620689ac2d..20438fa12e7 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -34,7 +34,7 @@ (require 'image-dired-util) (declare-function image-dired-display-image "image-dired") -(declare-function clear-image-cache "image.c" (&optional flter)) +(declare-function clear-image-cache "image.c" (&optional filter)) (declare-function w32image-create-thumbnail "w32image.c") (defvar image-dired-dir) commit 22d9bbe284e96037f190e0152461efb05cae9455 Merge: bed63ea922a bf50aa38f9d Author: Eli Zaretskii Date: Sat Jun 1 08:34:43 2024 -0400 Merge from origin/emacs-29 bf50aa38f9d Improve documentation of case-conversion commands 225b426f256 ; Fix typos commit bed63ea922a4e13bd3d6fbb3e7e7f2b408779d3b Author: Eli Zaretskii Date: Sat Jun 1 15:33:10 2024 +0300 ; * lisp/image/image-dired.el (w32-shell-execute): Declare. diff --git a/lisp/image/image-dired.el b/lisp/image/image-dired.el index 1e970d60a96..90c6f7663b5 100644 --- a/lisp/image/image-dired.el +++ b/lisp/image/image-dired.el @@ -1239,6 +1239,8 @@ Ask user how many thumbnails should be displayed per row." ;;; Display image from thumbnail buffer +(declare-function w32-shell-execute "w32fns.c") + (defun image-dired-thumbnail-display-external () "Display original image for thumbnail at point using external viewer. The viewer command is specified by `image-dired-external-viewer'." commit de7e3c33241923ab44b3cda8b237281f00c6b49d Author: Eli Zaretskii Date: Sat Jun 1 15:30:03 2024 +0300 ; Fix compilation warning in 'image-dired-external.el' * lisp/image/image-dired-external.el (w32image-create-thumbnail): Declare. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 178eb539ec4..4620689ac2d 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -34,7 +34,8 @@ (require 'image-dired-util) (declare-function image-dired-display-image "image-dired") -(declare-function clear-image-cache "image.c" (&optional filter)) +(declare-function clear-image-cache "image.c" (&optional flter)) +(declare-function w32image-create-thumbnail "w32image.c") (defvar image-dired-dir) (defvar image-dired-thumb-size) commit e42da81f54ec7d3ddcb70b54fa461c7dd6c3b101 Author: Eli Zaretskii Date: Sat Jun 1 15:22:11 2024 +0300 Improve thumbnail generation on MS-Windows * lisp/image/image-dired-external.el (image-dired-create-thumb-2): Optimize PNG thumbnails. (image-dired-pngnq-thumb, image-dired-pngcrush-thumb) (image-dired-optipng-thumb): On MS-Windows, invoke the PNG optimization programs synchronously. (image-dired-cmd-create-thumbnail-program) (image-dired-cmd-create-thumbnail-options) (image-dired-cmd-pngcrush-program) (image-dired-cmd-optipng-program) (image-dired-cmd-create-standard-thumbnail-options) (image-dired-cmd-rotate-original-program) (image-dired-temp-rotate-image-file) (image-dired-cmd-write-exif-data-program) (image-dired-cmd-write-exif-data-options): Doc fixes. (image-dired-thumb-queue-run): Don't allow more than 30 concurrent thumbnail-creation jobs on MS-Windows. diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index cdeeba4c367..178eb539ec4 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el @@ -50,8 +50,10 @@ (defcustom image-dired-cmd-create-thumbnail-program (if (executable-find "gm") "gm" "convert") - "Executable used to create thumbnail. -Used together with `image-dired-cmd-create-thumbnail-options'." + "File name of the executable used to create thumbnails. +Used together with `image-dired-cmd-create-thumbnail-options'. +On MS-Windows, if such an executable is not available, Emacs +will use `w32image-create-thumbnail' to create thumbnails." :type 'file :version "29.1") @@ -61,7 +63,8 @@ Used together with `image-dired-cmd-create-thumbnail-options'." "-strip" "jpeg:%t"))) (if (executable-find "gm") (cons "convert" opts) opts)) "Options of command used to create thumbnail image. -Used with `image-dired-cmd-create-thumbnail-program'. +Used with `image-dired-cmd-create-thumbnail-program', if that is +available. Available format specifiers are: %s, %w and %h, which are replaced by `image-dired-thumb-size' %f which is replaced by the file name of the original image and @@ -77,7 +80,7 @@ Available format specifiers are: (or (executable-find "pngquant") (executable-find "pngnq-s9") (executable-find "pngnq")) - "The file name of the `pngquant' or `pngnq' program. + "The executable file name of the `pngquant' or `pngnq' program. It quantizes colors of PNG images down to 256 colors or fewer using the NeuQuant algorithm." :version "29.1" @@ -94,7 +97,7 @@ Value can use the same format specifiers as in :version "29.1") (defcustom image-dired-cmd-pngcrush-program (executable-find "pngcrush") - "The file name of the `pngcrush' program. + "The executable file name of the `pngcrush' program. It optimizes the compression of PNG images. It also adds PNG textual chunks with the information required by the Thumbnail Managing Standard." :type '(choice (const :tag "Not Set" nil) file)) @@ -118,13 +121,13 @@ temporary file name (typically generated by pnqnq)." :type '(repeat (string :tag "Argument"))) (defcustom image-dired-cmd-optipng-program (executable-find "optipng") - "The file name of the `optipng' program." + "The executable file name of the `optipng' program." :version "26.1" :type '(choice (const :tag "Not Set" nil) file)) (defcustom image-dired-cmd-optipng-options '("-o5" "%t") "Arguments passed to `image-dired-cmd-optipng-program'. -The value can use format specifiers described in +The value can use the same %-format specifiers as in `image-dired-cmd-create-thumbnail-options'." :version "26.1" :type '(repeat (string :tag "Argument")) @@ -140,14 +143,19 @@ The value can use format specifiers described in "-thumbnail" "%wx%h>" "png:%t"))) (if (executable-find "gm") (cons "convert" opts) opts)) "Options for creating thumbnails according to the Thumbnail Managing Standard. +Used with `image-dired-cmd-create-thumbnail-program', if that is available. The value can use the same %-format specifiers as in `image-dired-cmd-create-thumbnail-options', with \"%m\" for file -modification time." +modification time. +On MS-Windows, if the `convert' command is not available, and +`w32image-create-thumbnail' is used instead, the textual chunks +specified by the \"-set\" options will not be injected, and instead +they are added by `pngcrush' if that is available." :type '(repeat (string :tag "Argument")) :version "29.1") (defcustom image-dired-cmd-rotate-original-program "jpegtran" - "Executable program used to rotate original image. + "Executable file of a program used to rotate original image. Used together with `image-dired-cmd-rotate-original-options'." :type 'file) @@ -166,16 +174,16 @@ and %t which is replaced by `image-dired-temp-image-file'." (defcustom image-dired-temp-rotate-image-file (expand-file-name ".image-dired_rotate_temp" (locate-user-emacs-file "image-dired/")) - "Temporary file for rotate operations." + "Temporary file for image rotation operations." :type 'file) (defcustom image-dired-cmd-write-exif-data-program "exiftool" - "Program used to write EXIF data to image. + "Executable file of a program used to write EXIF data to images. Used together with `image-dired-cmd-write-exif-data-options'." :type 'file) (defcustom image-dired-cmd-write-exif-data-options '("-%t=%v" "%f") - "Arguments of command used to write EXIF data. + "Arguments of the command used to write EXIF data. Used with `image-dired-cmd-write-exif-data-program'. The value can use the following format specifiers are: %f which is replaced by the image file name, @@ -250,19 +258,21 @@ Each item has the form (ORIGINAL-FILE TARGET-FILE).") Increase at your own risk. If you want to experiment with this, consider setting `image-dired-debug' to a non-nil value to see the time spent on generating thumbnails. Run `clear-image-cache' -and remove the cached thumbnail files between each trial run.") +and remove the cached thumbnail files between each trial run. +This is unused on MS-Windows when `w32image-create-thumbnail' is +used instead of ImageMagick or GraphicsMagick commands. +In addition, even if those commands are available, the actual number +of concurrent jobs will be limited by 30 from above, since Emacs +on MS-Windows cannot have too many concurrent sub-processes.") (defun image-dired-pngnq-thumb (spec) "Quantize thumbnail described by format SPEC with command `pngnq'." - (let ((process - (apply #'start-process "image-dired-pngnq" nil - image-dired-cmd-pngnq-program - (mapcar (lambda (arg) (format-spec arg spec)) - image-dired-cmd-pngnq-options)))) - (setf (process-sentinel process) + (let* ((snt (lambda (process status) - (if (and (eq (process-status process) 'exit) - (zerop (process-exit-status process))) + (if (or (and (processp process) ; async case + (eq (process-status process) 'exit) + (zerop (process-exit-status process))) + (zerop status)) ; sync case ;; Pass off to pngcrush, or just rename the ;; THUMB-nq8.png file back to THUMB.png (if (and image-dired-cmd-pngcrush-program @@ -271,9 +281,28 @@ and remove the cached thumbnail files between each trial run.") (let ((nq8 (cdr (assq ?q spec))) (thumb (cdr (assq ?t spec)))) (rename-file nq8 thumb t))) - (message "command %S %s" (process-command process) - (string-replace "\n" "" status))))) - process)) + (if (processp process) + (message "command %S %s" (process-command process) + (string-replace "\n" "" status)))))) + (proc + (let ((args (mapcar (lambda (arg) (format-spec arg spec)) + image-dired-cmd-pngnq-options))) + (if (eq system-type 'windows-nt) + ;; Cannot safely use 'start-process' here, since awe + ;; could be called to produce thumbnails for many + ;; images, and we have a hard limitation of 32 + ;; simultaneous sub-processes on MS-Windows. + (apply #'call-process + image-dired-cmd-pngnq-program nil nil nil args) + (apply #'start-process + "image-dired-pngnq" nil + image-dired-cmd-pngnq-program args))))) + (if (processp proc) + (setf (process-sentinel proc) snt) + (unless (zerop proc) + (message "command %S failed" image-dired-cmd-pngnq-program)) + (funcall snt image-dired-cmd-pngnq-program proc)) + proc)) (defun image-dired-pngcrush-thumb (spec) "Optimize thumbnail described by format SPEC with command `pngcrush'." @@ -284,36 +313,65 @@ and remove the cached thumbnail files between each trial run.") (let ((temp (cdr (assq ?q spec))) (thumb (cdr (assq ?t spec)))) (copy-file thumb temp))) - (let ((process - (apply #'start-process "image-dired-pngcrush" nil - image-dired-cmd-pngcrush-program - (mapcar (lambda (arg) (format-spec arg spec)) - image-dired-cmd-pngcrush-options)))) - (setf (process-sentinel process) - (lambda (process status) - (unless (and (eq (process-status process) 'exit) - (zerop (process-exit-status process))) - (message "command %S %s" (process-command process) - (string-replace "\n" "" status))) - (when (memq (process-status process) '(exit signal)) - (let ((temp (cdr (assq ?q spec)))) - (delete-file temp))))) - process)) + (let* ((args (mapcar + (lambda (arg) + (format-spec arg spec)) + image-dired-cmd-pngcrush-options)) + (snt (lambda (process status) + (unless (or (and (processp process) + (eq (process-status process) 'exit) + (zerop (process-exit-status process))) + (zerop status)) + (if (processp process) + (message "command %S %s" (process-command process) + (string-replace "\n" "" status)) + (message "command %S failed with status %s" + process status)) + (when (or (not (processp process)) + (memq (process-status process) '(exit signal))) + (let ((temp (cdr (assq ?q spec)))) + (delete-file temp)))))) + (proc + (if (eq system-type 'windows-nt) + ;; See above for the reasons we don't use 'start-process' + ;; on MS-Windows. + (apply #'call-process + image-dired-cmd-pngcrush-program nil nil nil args) + (apply #'start-process "image-dired-pngcrush" nil + image-dired-cmd-pngcrush-program args)))) + (if (processp proc) + (setf (process-sentinel proc) snt) + (funcall snt image-dired-cmd-pngcrush-program proc)) + proc)) (defun image-dired-optipng-thumb (spec) "Optimize thumbnail described by format SPEC with command `optipng'." - (let ((process - (apply #'start-process "image-dired-optipng" nil - image-dired-cmd-optipng-program - (mapcar (lambda (arg) (format-spec arg spec)) - image-dired-cmd-optipng-options)))) - (setf (process-sentinel process) - (lambda (process status) - (unless (and (eq (process-status process) 'exit) - (zerop (process-exit-status process))) - (message "command %S %s" (process-command process) - (string-replace "\n" "" status))))) - process)) + (let* ((args (mapcar + (lambda (arg) + (format-spec arg spec)) + image-dired-cmd-optipng-options)) + (snt (lambda (process status) + (unless (or (and (processp process) + (eq (process-status process) 'exit) + (zerop (process-exit-status process))) + (zerop status)) + (if (processp process) + (message "command %S %s" (process-command process) + (string-replace "\n" "" status)) + (message "command %S failed with status %s" + process status))))) + (proc + (if (eq system-type 'windows-nt) + ;; See above for the reasons we don't use 'start-process' + ;; on MS-Windows. + (apply #'call-process + image-dired-cmd-optipng-program nil nil nil args) + (apply #'start-process "image-dired-optipng" nil + image-dired-cmd-optipng-program args)))) + (if (processp proc) + (setf (process-sentinel proc) snt) + (funcall snt image-dired-cmd-optipng-program proc)) + proc)) (defun image-dired-create-thumb-1 (original-file thumbnail-file) "For ORIGINAL-FILE, create thumbnail image named THUMBNAIL-FILE." @@ -400,8 +458,30 @@ file is created by Emacs itself." (message "Failed to create a thumbnail for %s" (abbreviate-file-name original-file)) (clear-image-cache thumbnail-file) - ;; FIXME: Add PNG optimization like image-dired-create-thumb-1 does. - ) + ;; PNG thumbnail has been created since we are following the XDG + ;; thumbnail spec, so try to optimize. + (when (memq image-dired-thumbnail-storage + image-dired--thumbnail-standard-sizes) + (let* ((modif-time (format-time-string + "%s" (file-attribute-modification-time + (file-attributes original-file)))) + (thumbnail-nq8-file (replace-regexp-in-string + ".png\\'" "-nq8.png" thumbnail-file)) + (spec `((?s . ,size) (?w . ,size) (?h . ,size) + (?m . ,modif-time) + (?f . ,original-file) + (?q . ,thumbnail-nq8-file) + (?t . ,thumbnail-file)))) + (cond + ((and image-dired-cmd-pngnq-program + (executable-find image-dired-cmd-pngnq-program)) + (image-dired-pngnq-thumb spec)) + ((and image-dired-cmd-pngcrush-program + (executable-find image-dired-cmd-pngcrush-program)) + (image-dired-pngcrush-thumb spec)) + ((and image-dired-cmd-optipng-program + (executable-find image-dired-cmd-optipng-program)) + (image-dired-optipng-thumb spec)))))) ;; Trigger next in queue once a thumbnail has been created. (image-dired-thumb-queue-run))) @@ -414,13 +494,18 @@ Number of simultaneous jobs is limited by `image-dired-queue-active-limit'." 'w32image-create-thumbnail) 'function)) ;; We have a usable gm/convert command; queue thethumbnail jobs. - (while (and image-dired-queue - (< image-dired-queue-active-jobs - image-dired-queue-active-limit)) - (cl-incf image-dired-queue-active-jobs) - (apply #'image-dired-create-thumb-1 (pop image-dired-queue))) - ;; We are on MS-Windows and need to generate thumbnails by our - ;; lonesome selves. + (let ((max-jobs + (if (eq system-type 'windows-nt) + ;; Can't have more than 32 concurrent sub-processes on + ;; MS-Windows. + (min 30 image-dired-queue-active-limit) + image-dired-queue-active-limit))) + (while (and image-dired-queue + (< image-dired-queue-active-jobs max-jobs)) + (cl-incf image-dired-queue-active-jobs) + (apply #'image-dired-create-thumb-1 (pop image-dired-queue)))) + ;; We are on MS-Windows with ImageMagick/GraphicsMagick, and need to + ;; generate thumbnails by our lonesome selves. (if image-dired-queue (let* ((job (pop image-dired-queue)) (orig-file (car job)) commit 2b7056db424ab0f8bf9e96b5a3c6aa12a3debf48 Author: Po Lu Date: Sat Jun 1 15:41:54 2024 +0800 Implement touch screen events on PGTK * etc/NEWS: Better qualify entry for touch screen events. * lisp/loadup.el (featurep 'pgtk): Load touch-screen.el. * lisp/touch-screen.el: Revise list of systems where touch screen events are reported. * src/gtkutil.c (xg_create_frame_widgets): Request GDK_TOUCH_MASK. * src/pgtkfns.c (pgtk_frame_parm_handlers, tip_window): Pacify compiler warning. * src/pgtkterm.c (pgtk_free_frame_resources): Free touch points linked to this frame. (pgtk_link_touch_point, pgtk_unlink_touch_point) (pgtk_unlink_touch_points, pgtk_find_touch_point): New functions, ported from X. (touch_event_cb): New event callback. (pgtk_set_event_handler): Register `touch_event_cb' as handler for `touch-event'. (pgtk_delete_display): Free residual touch points on this display. * src/pgtkterm.h (struct pgtk_touch_point): New structure. (struct pgtk_display_info) : New field. diff --git a/etc/NEWS b/etc/NEWS index 3c672ffed8f..2cae3730602 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -520,10 +520,11 @@ function call. +++ ** Emacs now has better support for touchscreen devices. -Many touch screen gestures are now implemented and translated into -mouse or gesture events, and support for tapping tool bar buttons and -opening menus has been written. Countless packages, such as Dired and -Custom have been adjusted to better understand touch screen input. +On systems that understand them, many touch screen gestures are now +implemented and translated into mouse or gesture events, and support for +tapping tool bar buttons and opening menus has been written. Countless +packages, such as Dired and Custom have been adjusted to better +understand touch screen input. --- ** On X, Emacs now supports input methods which perform "string conversion". diff --git a/lisp/loadup.el b/lisp/loadup.el index aab1231c8be..52ec0ea5006 100644 --- a/lisp/loadup.el +++ b/lisp/loadup.el @@ -369,6 +369,7 @@ (if (featurep 'pgtk) (progn (load "pgtk-dnd") + (load "touch-screen") (load "term/common-win") (load "term/pgtk-win"))) (if (fboundp 'x-create-frame) diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index 436b8d0954c..b77f3a6e07d 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -23,8 +23,8 @@ ;;; Commentary: ;; This file provides code to recognize simple touch screen gestures. -;; It is used on X and Android, currently the only systems where Emacs -;; supports touch input. +;; It is used on X, PGTK, and Android, currently the only systems where +;; Emacs supports touch input. ;; ;; See (elisp)Touchscreen Events for a description of the details of ;; touch events. diff --git a/src/gtkutil.c b/src/gtkutil.c index 7de8eba0aa1..d57627f152f 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1669,6 +1669,7 @@ xg_create_frame_widgets (struct frame *f) #ifdef HAVE_PGTK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK + | GDK_TOUCH_MASK #endif | GDK_VISIBILITY_NOTIFY_MASK); diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 6a8efb6d0bf..bdc6c5836fa 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -945,6 +945,7 @@ unless TYPE is `png'. */) return pgtk_cr_export_frames (frames, surface_type); } +extern frame_parm_handler pgtk_frame_parm_handlers[]; frame_parm_handler pgtk_frame_parm_handlers[] = { gui_set_autoraise, /* generic OK */ @@ -2619,7 +2620,7 @@ static Lisp_Object tip_frame; /* The window-system window corresponding to the frame of the currently visible tooltip. */ -GtkWidget *tip_window; +static GtkWidget *tip_window; /* A timer that hides or deletes the currently visible tooltip when it fires. */ diff --git a/src/pgtkterm.c b/src/pgtkterm.c index 8d9a47b932f..886f115c391 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -450,6 +450,8 @@ pgtk_frame_raise_lower (struct frame *f, bool raise_flag) /* Free X resources of frame F. */ +static void pgtk_unlink_touch_points (struct frame *); + void pgtk_free_frame_resources (struct frame *f) { @@ -462,6 +464,7 @@ pgtk_free_frame_resources (struct frame *f) block_input (); + pgtk_unlink_touch_points (f); #ifdef HAVE_XWIDGETS kill_frame_xwidget_views (f); #endif @@ -6524,6 +6527,230 @@ drag_drop (GtkWidget *widget, GdkDragContext *context, return TRUE; } + + +/* Touch screen events. */ + +/* Record a touch sequence with the identifier DETAIL from the given + FRAME on the specified DPYINFO. Round X and Y and record them as its + current position, assign an identifier to the touch sequence suitable + for reporting to Lisp, and return the same. */ + +static EMACS_INT +pgtk_link_touch_point (struct pgtk_display_info *dpyinfo, + GdkEventSequence *detail, gdouble x, + gdouble y, struct frame *frame) +{ + struct pgtk_touch_point *touchpoint; + static EMACS_INT local_detail; + + /* Assign an identifier suitable for reporting to Lisp. On builds + with 64-bit Lisp_Object, this is largely a theoretical problem, but + CARD32s easily overflow 32-bit systems, as they are not specific to + X clients (e.g. Emacs) but grow uniformly across all of them. */ + + if (FIXNUM_OVERFLOW_P (local_detail)) + local_detail = 0; + + touchpoint = xmalloc (sizeof *touchpoint); + touchpoint->next = dpyinfo->touchpoints; + touchpoint->x = lrint (x); + touchpoint->y = lrint (y); + touchpoint->number = detail; + touchpoint->local_detail = local_detail++; + touchpoint->frame = frame; + dpyinfo->touchpoints = touchpoint; + return touchpoint->local_detail; +} + +/* Free and remove the touch sequence with the identifier DETAIL. + DPYINFO is the display in which the touch sequence should be + recorded. If such a touch sequence exists, return its local + identifier in *LOCAL_DETAIL. + + Value is 0 if no touch sequence by that identifier exists inside + DPYINFO, or 1 if a touch sequence has been found. */ + +static int +pgtk_unlink_touch_point (GdkEventSequence *detail, + struct pgtk_display_info *dpyinfo, + EMACS_INT *local_detail) +{ + struct pgtk_touch_point *last, *tem; + + for (last = NULL, tem = dpyinfo->touchpoints; tem; + last = tem, tem = tem->next) + { + if (tem->number == detail) + { + if (!last) + dpyinfo->touchpoints = tem->next; + else + last->next = tem->next; + + *local_detail = tem->local_detail; + xfree (tem); + + return 1; + } + } + + return 0; +} + +/* Unlink all touch points associated with the frame F. This is done + upon destroying F's window (or its being destroyed), because touch + point delivery after that point is undefined. */ + +static void +pgtk_unlink_touch_points (struct frame *f) +{ + struct pgtk_touch_point **next, *last; + struct pgtk_display_info *dpyinfo; + + /* Now unlink all touch points on F's display matching F. */ + + dpyinfo = FRAME_DISPLAY_INFO (f); + for (next = &dpyinfo->touchpoints; (last = *next);) + { + if (last->frame == f) + { + *next = last->next; + xfree (last); + } + else + next = &last->next; + } +} + +/* Return the data associated with a touch sequence DETAIL recorded by + `pgtk_link_touch_point' from DPYINFO, or NULL if it can't be + found. */ + +static struct pgtk_touch_point * +pgtk_find_touch_point (struct pgtk_display_info *dpyinfo, + GdkEventSequence *detail) +{ + struct pgtk_touch_point *point; + + for (point = dpyinfo->touchpoints; point; point = point->next) + { + if (point->number == detail) + return point; + } + + return NULL; +} + +static bool +touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data) +{ + struct pgtk_display_info *dpyinfo; + struct frame *f; + EMACS_INT local_detail; + union buffered_input_event inev; + struct pgtk_touch_point *touchpoint; + Lisp_Object arg = Qnil; + int state; + + EVENT_INIT (inev.ie); + + f = pgtk_any_window_to_frame (gtk_widget_get_window (self)); + eassert (f); + dpyinfo = FRAME_DISPLAY_INFO (f); + switch (event->type) + { + case GDK_TOUCH_BEGIN: + + /* Verify that no touch point with this identifier is already at + large. */ + if (pgtk_find_touch_point (dpyinfo, event->touch.sequence)) + break; + + /* Record this in the display structure. */ + local_detail = pgtk_link_touch_point (dpyinfo, event->touch.sequence, + event->touch.x, event->touch.y, + f); + /* Generate the input event. */ + inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; + inev.ie.timestamp = event->touch.time; + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (event->touch.x)); + XSETINT (inev.ie.y, lrint (event->touch.y)); + XSETINT (inev.ie.arg, local_detail); + break; + + case GDK_TOUCH_UPDATE: + touchpoint = pgtk_find_touch_point (dpyinfo, + event->touch.sequence); + + if (!touchpoint + /* Don't send this event if nothing has changed + either. */ + || (touchpoint->x == lrint (event->touch.x) + && touchpoint->y == lrint (event->touch.y))) + break; + + /* Construct the input event. */ + touchpoint->x = lrint (event->touch.x); + touchpoint->y = lrint (event->touch.y); + inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT; + inev.ie.timestamp = event->touch.time; + XSETFRAME (inev.ie.frame_or_window, f); + + for (touchpoint = dpyinfo->touchpoints; + touchpoint; touchpoint = touchpoint->next) + { + if (touchpoint->frame == f) + arg = Fcons (list3i (touchpoint->x, touchpoint->y, + touchpoint->local_detail), + arg); + } + + inev.ie.arg = arg; + break; + + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + /* Remove this touch point's record, also establishing its + existence. */ + state = pgtk_unlink_touch_point (event->touch.sequence, + dpyinfo, &local_detail); + /* If it did exist... */ + if (state) + { + /* ... generate a suitable event. */ + inev.ie.kind = TOUCHSCREEN_END_EVENT; + inev.ie.timestamp = event->touch.time; + inev.ie.modifiers = (event->type != GDK_TOUCH_END); + + XSETFRAME (inev.ie.frame_or_window, f); + XSETINT (inev.ie.x, lrint (event->touch.x)); + XSETINT (inev.ie.y, lrint (event->touch.y)); + XSETINT (inev.ie.arg, local_detail); + } + break; + + default: + break; + } + + /* If the above produced a workable event, report the name of the + device that gave rise to it. */ + + if (inev.ie.kind != NO_EVENT) + { + inev.ie.device = pgtk_get_device_for_event (dpyinfo, event); + evq_enqueue (&inev); + } + + return inev.ie.kind != NO_EVENT; +} + + + +/* Callbacks for sundries. */ + static void pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) { @@ -6540,6 +6767,8 @@ pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer); + + void pgtk_set_event_handler (struct frame *f) { @@ -6609,6 +6838,8 @@ pgtk_set_event_handler (struct frame *f) G_CALLBACK (pgtk_selection_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event", G_CALLBACK (pgtk_selection_event), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "touch-event", + G_CALLBACK (touch_event_cb), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event", G_CALLBACK (pgtk_handle_event), NULL); } @@ -7028,6 +7259,7 @@ static void pgtk_delete_display (struct pgtk_display_info *dpyinfo) { struct terminal *t; + struct pgtk_touch_point *last, *tem; /* Close all frames and delete the generic struct terminal for this X display. */ @@ -7049,6 +7281,15 @@ pgtk_delete_display (struct pgtk_display_info *dpyinfo) tail->next = tail->next->next; } + /* Free remaining touchpoints. */ + tem = dpyinfo->touchpoints; + while (tem) + { + last = tem; + tem = tem->next; + xfree (last); + } + pgtk_free_devices (dpyinfo); xfree (dpyinfo); } diff --git a/src/pgtkterm.h b/src/pgtkterm.h index 8072d963691..90ca2aa22d4 100644 --- a/src/pgtkterm.h +++ b/src/pgtkterm.h @@ -50,13 +50,38 @@ struct pgtk_bitmap_record struct pgtk_device_t { + /* Lisp name of the device. */ + Lisp_Object name; + + /* Seat to which this device appertains. */ GdkSeat *seat; + + /* Pointer to this device's GdkDevice object. */ GdkDevice *device; - Lisp_Object name; + /* Next device in this chain. */ struct pgtk_device_t *next; }; +struct pgtk_touch_point +{ + /* The detail code reported to Lisp. */ + EMACS_INT local_detail; + + /* The frame associated with this touch point. */ + struct frame *frame; + + /* The next touch point in this list. */ + struct pgtk_touch_point *next; + + /* The touchpoint detail. This purports to be a pointer, but is a + number. */ + GdkEventSequence *number; + + /* The last known rounded X and Y positions of the touchpoint. */ + int x, y; +}; + #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) @@ -131,10 +156,13 @@ struct pgtk_display_info /* This says how to access this display through GDK. */ GdkDisplay *gdpy; - /* An alias defined to make porting X code easier. */ + /* An alias defined to facilitate porting X code. */ GdkDisplay *display; }; + /* List of active touch-points. */ + struct pgtk_touch_point *touchpoints; + /* This is a cons cell of the form (NAME . FONT-LIST-CACHE). */ Lisp_Object name_list_element; commit bf50aa38f9d2a3a5af8d32ce139c7533c912c476 Author: Eli Zaretskii Date: Tue May 28 15:39:13 2024 +0300 Improve documentation of case-conversion commands * doc/emacs/text.texi (Case): Include the commands with negative arguments. (Bug#71220) diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 2db31c66f3b..c99683f0516 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -839,10 +839,17 @@ range of text to upper case or to lower case. @table @kbd @item M-l Convert following word to lower case (@code{downcase-word}). +@item M-- M-l +Convert previous/last word to lower case. Note: @kbd{Meta--} is +Meta-minus. @item M-u Convert following word to upper case (@code{upcase-word}). +@item M-- M-u +Convert previous/last last word to all upper case. @item M-c Capitalize the following word (@code{capitalize-word}). +@item M-- M-c +Convert previous/last last word to lower case with capital initial. @item C-x C-l Convert region to lower case (@code{downcase-region}). @item C-x C-u @@ -869,10 +876,11 @@ from all upper case to mixed case, because you can move through the text using @kbd{M-l}, @kbd{M-u} or @kbd{M-c} on each word as appropriate, occasionally using @kbd{M-f} instead to skip a word. - When given a negative argument, the word case conversion commands apply -to the appropriate number of words before point, but do not move point. -This is convenient when you have just typed a word in the wrong case: you -can give the case conversion command and continue typing. + When given a negative argument, as in @w{@kbd{C-u - 5 M-c}}, the +word case-conversion commands apply to the appropriate number of words +before point, but do not move point. This is convenient when you have +just typed a word in the wrong case: you can give the case conversion +command, like @kbd{M-- M-u}, and continue typing. If a word case conversion command is given in the middle of a word, it applies only to the part of the word which follows point. (This is commit 225b426f256ba00aff7669ad18a5c85f86e22f67 Author: Stefan Kangas Date: Mon May 27 10:11:15 2024 +0200 ; Fix typos diff --git a/ChangeLog.3 b/ChangeLog.3 index d43ffa10bc7..21c4a092be0 100644 --- a/ChangeLog.3 +++ b/ChangeLog.3 @@ -6427,7 +6427,7 @@ * lisp/net/tramp-fuse.el (tramp-fuse-mount-timeout): New defconst. (tramp-fuse-mounted-p): Use it. Check for a file property instead of a connection property. - (tramp-fuse-unmount): Dito. + (tramp-fuse-unmount): Ditto. * lisp/net/tramp-sshfs.el (tramp-sshfs-maybe-open-connection): Do not trust existence of a process, whether the volume is mounted. @@ -11209,7 +11209,7 @@ (flymake--publish-diagnostics): Helper for flymake--handle-report. (flymake--mode-line-counter, flymake-show-diagnostic) (flymake--diagnostics-buffer-entries): Use - flymake-diagnostic-buffer, flymake-diagonstic-type, + flymake-diagnostic-buffer, flymake-diagnostic-type, flymake-diagnostic-beg. 2021-09-14 João Távora @@ -137530,7 +137530,7 @@ Bind `enable-local-variables' in `hack-connection-local-variables' * lisp/files-x.el (hack-connection-local-variables): - Bind `enable-local-variables', instead of re-declaring + Bind `enable-local-variables', instead of redeclaring `safe-local-variable-p'. 2019-03-23 Eli Zaretskii @@ -163179,7 +163179,7 @@ Quieten compilation of octave.el - * lisp/progmodes/octave.el (compilation-forget-errors): Re-declare. + * lisp/progmodes/octave.el (compilation-forget-errors): Redeclare. 2018-02-28 Glenn Morris diff --git a/ChangeLog.4 b/ChangeLog.4 index 4b806c21124..d9596005f70 100644 --- a/ChangeLog.4 +++ b/ChangeLog.4 @@ -1319,7 +1319,7 @@ Fix c-ts-mode indentation (bug#67357) - 1. In a compund_statement, we indent the first sibling against the + 1. In a compound_statement, we indent the first sibling against the parent, and the rest siblings against their previous sibling. But this strategy falls apart when the first sibling is not on its own line. We should regard the first sibling that is on its own line as @@ -11284,7 +11284,7 @@ Add array_initializer to java-ts-mode - Indent strings inside arrray_initializer one step: + Indent strings inside array_initializer one step: public class Java { void foo() { @@ -16406,7 +16406,7 @@ config-format[1] through a new major-mode: toml-ts-mode. I've read through the full spec[2], and from what I can see this - major-mode should provide correct syntax-highligting for every sort of + major-mode should provide correct syntax highlighting for every sort of config-declaration which adheres to the specification. Besides that it also adds support for imenu and basic tree-sitter @@ -26568,7 +26568,7 @@ option. (package-vc-archive-spec-alist): Add new variable to store the contents of 'elpa-packages' for each archive. - (pacakge-vc-desc->spec): Add function to query package specifications. + (package-vc-desc->spec): Add function to query package specifications. (package-vc--read-archive-data): Add a 'package-read-archive-hook' implementation. (package-vc--download-and-read-archives): Add a @@ -34210,7 +34210,7 @@ 2022-09-15 Mattias Engdegård - Include nil as valid wallpaper-commmand + Include nil as valid wallpaper-command * lisp/image/wallpaper.el (wallpaper-command): Include nil in the type since that is a valid value for the variable, @@ -44103,7 +44103,7 @@ * src/bytecode.c (exec_byte_code): * lisp/emacs-lisp/comp.el (comp-limplify-lap-inst): - * lisp/emacs-lisp/bytecomp.el: Restore the statu quo ante. + * lisp/emacs-lisp/bytecomp.el: Restore the status quo ante. * etc/NEWS: Remove the entry about the new optional argument. @@ -52809,7 +52809,7 @@ /emacs/configure: line 18002: syntax error near unexpected token `;;' /emacs/configure: line 18002: ` ;;' That is due to under-quoting of AC_CHECK_LIB's second argument, which led to - the comma in an embedded string being interpreted as paramater-delimiting. + the comma in an embedded string being interpreted as parameter-delimiting. * configure.ac: Quote the second arg of each AC_CHECK_LIB invocation. (Bug#56272) @@ -62459,7 +62459,7 @@ up-to-date) until the next invocation of 'eglot-flymake-backend'. For now, this doesn't affect Flymake "list-only" diagnostics. Those - are reported via the 'flymake-list-only-diagonstics' variable and + are reported via the 'flymake-list-only-diagnostics' variable and are always communicated immediately to it. * eglot.el: (eglot-handle-notification @@ -66876,7 +66876,7 @@ (eshell-get-delimited-modifier-argument): New functions... (eshell-pred-user-or-group, eshell-pred-file-time) (eshell-pred-file-links, eshell-pred-file-size) - (eshell-pred-substitute, eshell-join-memebers, eshell-split-members): + (eshell-pred-substitute, eshell-join-members, eshell-split-members): ... and use them here. (eshell-include-members): Pass 'mod-char' and use 'eshell-get-delimited-modifier-argument'. @@ -74587,7 +74587,7 @@ 2022-03-24 Jimmy Aguilar Mena - Merge 'completion-auto-select new value secont-tab' + Merge 'completion-auto-select new value second-tab' This includes the second-tab value for completion-auto-select and documentation related. @@ -82366,7 +82366,7 @@ 2022-02-06 Wang Chunye (tiny change) - optimization: constand folding for read-kbd-macro + optimization: constant folding for read-kbd-macro to boost startup performance, it is better to avoid invoking `read-kbd-macro` at run time which requires 'cl-lib. @@ -83611,7 +83611,7 @@ symbols since the rest is now available from `function-history`. * src/eval.c (un_autoload): Adjust accordingly. - * src/lread.c (load-history): Udate docstring. + * src/lread.c (load-history): Update docstring. * lisp/loadhist.el (loadhist-unload-filename): New var. (unload-feature): Bind it. @@ -102240,7 +102240,7 @@ 2021-11-06 Lars Ingebrigtsen - Remove too-agressive window refresh in the hourglass code + Remove too aggressive window refresh in the hourglass code * src/xterm.c (x_show_hourglass): Don't force a spurious refresh (bug#51649). @@ -110715,7 +110715,7 @@ 2020-11-21 Yuuki Harano - Implement Scroll-bar-forground and scroll-bar-background + Implement scroll-bar-foreground and scroll-bar-background * src/pgtkterm.h (struct pgtk_output): @@ -112654,7 +112654,7 @@ Rework and correct major part of xref glue code See comments of https://github.com/joaotavora/eglot/pull/314. Up to - now, xref-backend-indentifier-completion-table was a gross hack that + now, xref-backend-identifier-completion-table was a gross hack that only worked sometimes. It relied on some fugly gymnastics to cache a response from :textDocument/documentSymbol and somehow used that information to build a completion table. But it doesn't work well. @@ -113087,12 +113087,12 @@ Merge pull request from stribb/master - Add a line of documentation for (use-pacakage ... :hook). + Add a line of documentation for (use-package ... :hook). GitHub-reference: https://github.com/jwiegley/use-package/issues/759 2019-04-04 Andrew Stribblehill (tiny change) - Add a line of documentation for (use-pacakage ... :hook) + Add a line of documentation for (use-package ... :hook) 2019-02-13 João Távora @@ -113770,7 +113770,7 @@ Fix potential security issue fontifying lsp doc - Previously, a server could mistankely or maliciously call *-mode + Previously, a server could mistakenly or maliciously call *-mode functions by in the response to a completion or hover request, specifically in the :documentation field of the response. @@ -115537,7 +115537,7 @@ Also cquery sometimes send 0-length ranges upon which we now fallback to flymake-diag-region. - Finally, in eglot-eldoc-funciton, the previous hack of calling the + Finally, in eglot-eldoc-function, the previous hack of calling the eglot--hover-info outside of the when-buffer-window macrolet contained a bug. It must be called in the correct buffer. Revert the hack and do it by querying from eglot.el if ert is running tests. @@ -119347,7 +119347,7 @@ (use-package foopkg :bind "") - intendes to bind to 'foopkg command. + intends to bind to 'foopkg command. 2016-10-31 Noam Postavsky diff --git a/admin/notes/www b/admin/notes/www index 0a2d4aa9859..f22eff8f4c7 100644 --- a/admin/notes/www +++ b/admin/notes/www @@ -85,7 +85,7 @@ permanent redirects, and changes go live more-or-less straight away. This method is useful for making cross-references to non-Emacs manuals work; see manual/.htaccess in the repository. You only have to add a single redirect for every given external manual, you can redirect -html_node to hmtl_node and html_mono to html_mono. +html_node to html_node and html_mono to html_mono. * Why CVS? diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 163577f5d08..6abb2127e7b 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -200,7 +200,7 @@ doubling it up." (defun eshell-convertible-to-number-p (string) "Return non-nil if STRING can be converted to a number. -If `eshell-convert-numeric-aguments', always return nil." +If `eshell-convert-numeric-arguments', always return nil." (and eshell-convert-numeric-arguments (string-match (concat "\\`\\s-*" eshell-number-regexp "\\s-*\\'") @@ -209,7 +209,7 @@ If `eshell-convert-numeric-aguments', always return nil." (defun eshell-convert-to-number (string) "Try to convert STRING to a number. If STRING doesn't look like a number (or -`eshell-convert-numeric-aguments' is nil), just return STRING +`eshell-convert-numeric-arguments' is nil), just return STRING unchanged." (if (eshell-convertible-to-number-p string) (string-to-number string) @@ -224,7 +224,7 @@ trailing newlines removed. Otherwise, this behaves as follows: * Split multiline strings by line. -* If `eshell-convert-numeric-aguments' is non-nil and every line +* If `eshell-convert-numeric-arguments' is non-nil and every line of output looks like a number, convert them to numbers." (cond ((not (stringp string)) diff --git a/lisp/filesets.el b/lisp/filesets.el index 0b97bd4c518..3f7e078abb0 100644 --- a/lisp/filesets.el +++ b/lisp/filesets.el @@ -1654,7 +1654,7 @@ Assume MODE (see `filesets-entry-mode'), if provided." (cons entry (filesets-ingroup-cache-get entry)))) (:tree ;; Warning: ENTRY here could be of at least two - ;; differente forms, either + ;; different forms, either ;; (NAME (:tree DIRECTORY PATTERN)) ;; or ;; (DIRECTORY PATTERN) diff --git a/lisp/leim/quail/persian.el b/lisp/leim/quail/persian.el index de61481d7f1..676b3ab5c2e 100644 --- a/lisp/leim/quail/persian.el +++ b/lisp/leim/quail/persian.el @@ -500,7 +500,7 @@ ;; RIGHT-TO-LEFT EMBEDDING (sets base dir to RTL but allows embedded text) ("&rle;" ?\u202B) ;; (ucs-insert #x202B) named: زیرمتنِ راست‌به‌چپ ;; POP DIRECTIONAL FORMATTING (used for RLE or LRE and RLO or LRO) - ;; EMACS ANOMOLY --- Why does &pdf not show up in (describe-input-method 'farsi-transliterate-banan) + ;; EMACS ANOMALY --- Why does &pdf not show up in (describe-input-method 'farsi-transliterate-banan) ("&pdf;" ?\u202C) ;; (ucs-insert #x202C) named: پایانِ زیرمتن ("P" ?\u202C) ;; LEFT-TO-RIGHT OVERRIDE (overrides the bidirectional algorithm, display LTR) diff --git a/lisp/shell.el b/lisp/shell.el index ca86059f9de..373153f9b0c 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -37,7 +37,7 @@ ;; the hooks available for customizing it, see the file comint.el. ;; For further information on shell mode, see the comments below. -;; Needs fixin: +;; Needs fixing: ;; When sending text from a source file to a subprocess, the process-mark can ;; move off the window, so you can lose sight of the process interactions. ;; Maybe I should ensure the process mark is in the window when I send diff --git a/lisp/simple.el b/lisp/simple.el index d91efb23363..452c2ab2a5b 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -4505,7 +4505,7 @@ a shell (with its need to quote arguments)." (dired-get-filename nil t))))) (and filename (file-relative-name filename)))) nil - ;; FIXME: the following argument is always ignored by 'shell-commnd', + ;; FIXME: the following argument is always ignored by 'shell-command', ;; when the command is invoked asynchronously, except, perhaps, when ;; 'default-directory' is remote. shell-command-default-error-buffer)) diff --git a/lisp/textmodes/table.el b/lisp/textmodes/table.el index 973f589b204..2c0f918b0de 100644 --- a/lisp/textmodes/table.el +++ b/lisp/textmodes/table.el @@ -4134,7 +4134,7 @@ cache buffer into the designated cell in the table buffer." (currentp (equal cell-coord current-cell-coordinate))) (if currentp (table--goto-coordinate current-coordinate) (table--goto-coordinate (car cell-coord))) - (table-recognize-cell 'froce) + (table-recognize-cell 'force) (let ((table-inhibit-update t)) (table-with-cache-buffer (let ((sticky (and currentp @@ -4147,7 +4147,7 @@ cache buffer into the designated cell in the table buffer." (table--update-cell 'now) )) (table--goto-coordinate current-coordinate) - (table-recognize-cell 'froce))))) + (table-recognize-cell 'force))))) (defun table--update-cell-heightened (&optional now) "Update the contents of the cells that are affected by heightening operation." @@ -4176,7 +4176,7 @@ cache buffer into the designated cell in the table buffer." (currentp (equal cell-coord current-cell-coordinate))) (if currentp (table--goto-coordinate current-coordinate) (table--goto-coordinate (car cell-coord))) - (table-recognize-cell 'froce) + (table-recognize-cell 'force) (let ((table-inhibit-update t)) (table-with-cache-buffer (let ((sticky (and currentp @@ -4189,7 +4189,7 @@ cache buffer into the designated cell in the table buffer." (table--update-cell 'now) )) (table--goto-coordinate current-coordinate) - (table-recognize-cell 'froce))))) + (table-recognize-cell 'force))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 4f150dc7f36..f93659be02d 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -2640,7 +2640,7 @@ fixed, visit it in a buffer." (?- . (left-fringe diff-fringe-del diff-indicator-removed)) (?! . (left-fringe diff-fringe-rep diff-indicator-changed)) (?\s . (left-fringe diff-fringe-nul fringe))))))))) - ;; Mimicks the output of Magit's diff. + ;; Mimics the output of Magit's diff. ;; FIXME: This has only been tested with Git's diff output. ;; FIXME: Add support for Git's "rename from/to"? (while (re-search-forward "^diff " limit t) diff --git a/src/w32font.c b/src/w32font.c index f2d4e5e45e8..70cfdd6bbe1 100644 --- a/src/w32font.c +++ b/src/w32font.c @@ -430,7 +430,7 @@ w32font_encode_char (struct font *font, int c) } /* w32 implementation of text_extents for font backend. - Perform the size computation of glyphs of FONT and fillin members + Perform the size computation of glyphs of FONT and fill in members of METRICS. The glyphs are specified by their glyph codes in CODE (length NGLYPHS). Apparently metrics can be NULL, in this case just return the overall width. */ diff --git a/test/lisp/emacs-lisp/icons-tests.el b/test/lisp/emacs-lisp/icons-tests.el index fa320a49866..d3bf63b2b60 100644 --- a/test/lisp/emacs-lisp/icons-tests.el +++ b/test/lisp/emacs-lisp/icons-tests.el @@ -54,7 +54,7 @@ (enable-theme 'test-icons-theme) (should (equal (icon-string 'icon-test1) "<")))) -(ert-deftest test-icon-inheretance () +(ert-deftest test-icon-inheritance () (let ((icon-preference '(image emoji symbol text))) (should (equal (icon-string 'icon-test2) ">"))) (let ((icon-preference '(text))) diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 06943e22f5b..66eb4e7a29d 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -7159,12 +7159,12 @@ always located at the beginning of buffer." (forward-to-word 1) (should (eq (face-at-point) font-lock-keyword-face))))) -(ert-deftest python-ts-mode-named-assignement-face-1 () +(ert-deftest python-ts-mode-named-assignment-face-1 () (python-ts-tests-with-temp-buffer "var := 3" (should (eq (face-at-point) font-lock-variable-name-face)))) -(ert-deftest python-ts-mode-assignement-face-2 () +(ert-deftest python-ts-mode-assignment-face-2 () (python-ts-tests-with-temp-buffer "var, *rest = call()" (dolist (test '("var" "rest"))