From f6ecb707b36d71b6a24e224b3635223f7a5b8b33 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Wed, 1 Nov 2023 20:24:03 +0100 Subject: Upgrade lua-mode, markdown-mode and yasnippet --- .emacs.d/lisp/lua-mode.el | 23 +++--- .emacs.d/lisp/markdown-mode.el | 78 ++++++++++++++++++-- .emacs.d/lisp/yasnippet.el | 157 +++++++++++------------------------------ 3 files changed, 124 insertions(+), 134 deletions(-) diff --git a/.emacs.d/lisp/lua-mode.el b/.emacs.d/lisp/lua-mode.el index 6ab4d43..6c524f5 100644 --- a/.emacs.d/lisp/lua-mode.el +++ b/.emacs.d/lisp/lua-mode.el @@ -330,8 +330,9 @@ Should be a list of strings." :type 'string :group 'lua :set 'lua--customize-set-prefix-key - :get '(lambda (sym) - (let ((val (eval sym))) (if val (single-key-description (eval sym)) "")))) + :get (lambda (sym) + (let ((val (eval sym))) + (if val (single-key-description (eval sym)) "")))) (defvar lua-mode-menu (make-sparse-keymap "Lua") "Keymap for lua-mode's menu.") @@ -994,7 +995,7 @@ placed before the string." (defun lua-find-regexp (direction regexp &optional limit) "Searches for a regular expression in the direction specified. -Direction is one of 'forward and 'backward. +Direction is one of \\='forward and \\='backward. Matches in comments and strings are ignored. If the regexp is found, returns point position, nil otherwise." @@ -1097,12 +1098,12 @@ TOKEN-TYPE determines where the token occurs on a statement. open indicates that "Find matching open- or close-token for TOKEN in DIRECTION. Point has to be exactly at the beginning of TOKEN, e.g. with | being point - {{ }|} -- (lua-find-matching-token-word \"}\" 'backward) will return + {{ }|} -- (lua-find-matching-token-word \"}\" \\='backward) will return -- the first { - {{ |}} -- (lua-find-matching-token-word \"}\" 'backward) will find + {{ |}} -- (lua-find-matching-token-word \"}\" \\='backward) will find -- the second {. -DIRECTION has to be either 'forward or 'backward." +DIRECTION has to be either \\='forward or \\='backward." (let* ((token-info (lua-get-block-token-info token)) (match-type (lua-get-token-type token-info)) ;; If we are on a middle token, go backwards. If it is a middle or open, @@ -1177,7 +1178,7 @@ at the current point. Returns the point position of the first character of the matching token if successful, nil otherwise. Optional PARSE-START is a position to which the point should be moved first. -DIRECTION has to be 'forward or 'backward ('forward by default)." +DIRECTION has to be \\='forward or \\='backward (\\='forward by default)." (if parse-start (goto-char parse-start)) (let ((case-fold-search nil)) (if (looking-at lua-indentation-modifier-regexp) @@ -1286,7 +1287,7 @@ Returns final value of point as integer or nil if operation failed." "Regexp that matches the ending of a line that needs continuation. This regexp starts from eol and looks for a binary operator or an unclosed -block intro (i.e. 'for' without 'do' or 'if' without 'then') followed by +block intro (i.e. `for' without `do' or `if' without `then') followed by an optional whitespace till the end of the line.") (defconst lua-cont-bol-regexp @@ -1589,7 +1590,7 @@ block opening statement when it is closed. When a replace-matching token is seen, the last recorded info is removed, and the cdr of the replace-matching info is added in its place. This is used -when a middle-of the block (the only case is 'else') is seen on the same line +when a middle-of the block (the only case is `else') is seen on the same line the block is opened." (cond ( (eq 'multiple (car pair)) @@ -1755,8 +1756,8 @@ token should be indented relative to left-shifter expression indentation rather then to block-open token. For example: - -- 'local a = ' is a left-shifter expression - -- 'function' is a block-open token + -- `local a = ' is a left-shifter expression + -- `function' is a block-open token local a = function() -- block contents is indented relative to left-shifter foobarbaz() diff --git a/.emacs.d/lisp/markdown-mode.el b/.emacs.d/lisp/markdown-mode.el index 3abecce..0771060 100644 --- a/.emacs.d/lisp/markdown-mode.el +++ b/.emacs.d/lisp/markdown-mode.el @@ -51,6 +51,13 @@ (declare-function project-roots "project") (declare-function sh-set-shell "sh-script") +(declare-function mailcap-file-name-to-mime-type "mailcap") +(declare-function dnd-get-local-file-name "dnd") + +;; for older emacs<29 +(declare-function mailcap-mime-type-to-extension "mailcap") +(declare-function file-name-with-extension "files") +(declare-function yank-media-handler "yank-media") ;;; Constants ================================================================= @@ -73,6 +80,13 @@ (defvar markdown-gfm-language-history nil "History list of languages used in the current buffer in GFM code blocks.") +(defvar markdown-follow-link-functions nil + "Functions used to follow a link. +Each function is called with one argument, the link's URL. It +should return non-nil if it followed the link, or nil if not. +Functions are called in order until one of them returns non-nil; +otherwise the default link-following function is used.") + ;;; Customizable Variables ==================================================== @@ -7923,11 +7937,11 @@ If the link is a complete URL, open in browser with `browse-url'. Otherwise, open with `find-file' after stripping anchor and/or query string. Translate filenames using `markdown-filename-translate-function'." (interactive (list last-command-event)) - (save-excursion - (if event (posn-set-point (event-start event))) - (if (markdown-link-p) - (markdown--browse-url (markdown-link-url)) - (user-error "Point is not at a Markdown link or URL")))) + (if event (posn-set-point (event-start event))) + (if (markdown-link-p) + (or (run-hook-with-args-until-success 'markdown-follow-link-functions (markdown-link-url)) + (markdown--browse-url (markdown-link-url))) + (user-error "Point is not at a Markdown link or URL"))) (defun markdown-fontify-inline-links (last) "Add text properties to next inline link from point to LAST." @@ -8337,7 +8351,7 @@ See `markdown-follow-link-at-point' and `markdown-follow-wiki-link-at-point'." (interactive "P") (cond ((markdown-link-p) - (markdown--browse-url (markdown-link-url))) + (markdown-follow-link-at-point)) ((markdown-wiki-link-p) (markdown-follow-wiki-link-at-point arg)) (t @@ -9829,6 +9843,48 @@ rows and columns and the column alignment." (markdown--substitute-command-keys "\\[markdown-toggle-markup-hiding]")))))) +(defun markdown--image-media-handler (mimetype data) + (let* ((ext (symbol-name (mailcap-mime-type-to-extension mimetype))) + (filename (read-string "Insert filename for image: ")) + (link-text (read-string "Link text: ")) + (filepath (file-name-with-extension filename ext)) + (dir (file-name-directory filepath))) + (when (and dir (not (file-directory-p dir))) + (make-directory dir t)) + (with-temp-file filepath + (insert data)) + (when (string-match-p "\\s-" filepath) + (setq filepath (concat "<" filepath ">"))) + (markdown-insert-inline-image link-text filepath))) + +(defun markdown--file-media-handler (_mimetype data) + (let* ((data (split-string data "[\0\r\n]" t "^file://")) + (files (cdr data))) + (while (not (null files)) + (let* ((file (url-unhex-string (car files))) + (file (file-relative-name file)) + (prompt (format "Link text(%s): " (file-name-nondirectory file))) + (link-text (read-string prompt))) + (when (string-match-p "\\s-" file) + (setq file (concat "<" file ">"))) + (markdown-insert-inline-image link-text file) + (when (not (null (cdr files))) + (insert " ")) + (setq files (cdr files)))))) + +(defun markdown--dnd-local-file-handler (url _action) + (require 'mailcap) + (require 'dnd) + (let* ((filename (dnd-get-local-file-name url)) + (mimetype (mailcap-file-name-to-mime-type filename)) + (file (file-relative-name filename)) + (link-text "link text")) + (when (string-match-p "\\s-" file) + (setq file (concat "<" file ">"))) + (if (string-prefix-p "image/" mimetype) + (markdown-insert-inline-image link-text file) + (markdown-insert-inline-link link-text file)))) + ;;; Mode Definition ========================================================== @@ -9957,6 +10013,16 @@ rows and columns and the column alignment." (add-hook 'electric-quote-inhibit-functions #'markdown--inhibit-electric-quote nil :local) + ;; drag and drop handler + (setq-local dnd-protocol-alist (cons '("^file:///" . markdown--dnd-local-file-handler) + dnd-protocol-alist)) + + ;; media handler + (when (version< "29" emacs-version) + (yank-media-handler "image/.*" #'markdown--image-media-handler) + ;; TODO support other than GNOME, like KDE etc + (yank-media-handler "x-special/gnome-copied-files" #'markdown--file-media-handler)) + ;; Make checkboxes buttons (when markdown-make-gfm-checkboxes-buttons (markdown-make-gfm-checkboxes-buttons (point-min) (point-max)) diff --git a/.emacs.d/lisp/yasnippet.el b/.emacs.d/lisp/yasnippet.el index 78ef38a..c4f8ae4 100644 --- a/.emacs.d/lisp/yasnippet.el +++ b/.emacs.d/lisp/yasnippet.el @@ -1,6 +1,6 @@ -;;; yasnippet.el --- Yet another snippet extension for Emacs +;;; yasnippet.el --- Yet another snippet extension for Emacs -*- lexical-binding: t; -*- -;; Copyright (C) 2008-2019 Free Software Foundation, Inc. +;; Copyright (C) 2008-2023 Free Software Foundation, Inc. ;; Authors: pluskid , ;; João Távora , ;; Noam Postavsky @@ -9,7 +9,7 @@ ;; X-URL: http://github.com/joaotavora/yasnippet ;; Keywords: convenience, emulation ;; URL: http://github.com/joaotavora/yasnippet -;; Package-Requires: ((cl-lib "0.5")) +;; Package-Requires: ((cl-lib "0.5") (emacs "24.4")) ;; EmacsWiki: YaSnippetMode ;; This program is free software: you can redistribute it and/or modify @@ -474,20 +474,20 @@ See also Info node `(elisp) Syntax Descriptors'.") (defvar yas-after-exit-snippet-hook '() - "Hooks to run after a snippet exited. + "Hook run after a snippet exited. -The hooks will be run in an environment where some variables bound to +The functions will be run in an environment where some variables bound to proper values: `yas-snippet-beg' : The beginning of the region of the snippet. `yas-snippet-end' : Similar to beg. -Attention: These hooks are not run when exiting nested/stacked snippet expansion!") +Attention: This hook is not run when exiting nested/stacked snippet expansion!") (defvar yas-before-expand-snippet-hook '() - "Hooks to run just before expanding a snippet.") + "Hook run just before expanding a snippet.") (defconst yas-not-string-or-comment-condition '(if (let ((ppss (syntax-ppss))) @@ -611,38 +611,6 @@ can be useful." (defvar yas--snippet-id-seed 0 "Contains the next id for a snippet.") -(defvar yas--original-auto-fill-function nil - "The original value of `auto-fill-function'.") -(make-variable-buffer-local 'yas--original-auto-fill-function) - -(defvar yas--watch-auto-fill-backtrace nil) - -(defun yas--watch-auto-fill (sym newval op _where) - (when (and (or (and (eq sym 'yas--original-auto-fill-function) - (null newval) - (eq auto-fill-function 'yas--auto-fill)) - (and (eq sym 'auto-fill-function) - (eq newval 'yas--auto-fill) - (null yas--original-auto-fill-function))) - (null yas--watch-auto-fill-backtrace) - (fboundp 'backtrace-frames) ; Suppress compiler warning. - ;; If we're about to change `auto-fill-function' too, - ;; it's okay (probably). - (not (and (eq op 'makunbound) - (not (eq (default-value 'auto-fill-function) 'yas--auto-fill)) - (cl-member 'kill-all-local-variables - (backtrace-frames 'yas--watch-auto-fill) - :key (lambda (frame) (nth 1 frame)))))) - (setq yas--watch-auto-fill-backtrace - (backtrace-frames 'yas--watch-auto-fill)))) - -;; Try to get more info on #873/919 (this only works for Emacs 26+). -(when (fboundp 'add-variable-watcher) - (add-variable-watcher 'yas--original-auto-fill-function - #'yas--watch-auto-fill) - (add-variable-watcher 'auto-fill-function - #'yas--watch-auto-fill)) - (defun yas--snippet-next-id () (let ((id yas--snippet-id-seed)) (cl-incf yas--snippet-id-seed) @@ -676,11 +644,16 @@ expanded.") (defvar yas-minor-mode-map (let ((map (make-sparse-keymap))) - (define-key map [(tab)] yas-maybe-expand) + ;; Modes should always bind to TAB instead of `tab', so as not to override + ;; bindings that should take higher precedence but which bind to `TAB` + ;; instead (relying on `function-key-map` to remap `tab` to TAB). + ;; If this causes problem because of another package that binds to `tab`, + ;; complain to that other package! + ;;(define-key map [(tab)] yas-maybe-expand) (define-key map (kbd "TAB") yas-maybe-expand) - (define-key map "\C-c&\C-s" 'yas-insert-snippet) - (define-key map "\C-c&\C-n" 'yas-new-snippet) - (define-key map "\C-c&\C-v" 'yas-visit-snippet-file) + (define-key map "\C-c&\C-s" #'yas-insert-snippet) + (define-key map "\C-c&\C-n" #'yas-new-snippet) + (define-key map "\C-c&\C-v" #'yas-visit-snippet-file) map) "The keymap used when `yas-minor-mode' is active.") @@ -860,10 +833,9 @@ which decides on the snippet to expand.") "Hook run when `yas-minor-mode' is turned on.") (defun yas--auto-fill-wrapper () - (when (and auto-fill-function - (not (eq auto-fill-function #'yas--auto-fill))) - (setq yas--original-auto-fill-function auto-fill-function) - (setq auto-fill-function #'yas--auto-fill))) + (when auto-fill-function ;Turning the mode ON. + ;; (cl-assert (local-variable-p 'auto-fill-function)) + (add-function :around (local 'auto-fill-function) #'yas--auto-fill))) ;;;###autoload (define-minor-mode yas-minor-mode @@ -906,8 +878,8 @@ Key bindings: ;; auto-fill handler. (remove-hook 'post-command-hook #'yas--post-command-handler t) (remove-hook 'auto-fill-mode-hook #'yas--auto-fill-wrapper) - (when (local-variable-p 'yas--original-auto-fill-function) - (setq auto-fill-function yas--original-auto-fill-function)) + (when (local-variable-p 'auto-fill-function) + (remove-function (local 'auto-fill-function) #'yas--auto-fill)) (setq emulation-mode-map-alists (remove 'yas--direct-keymaps emulation-mode-map-alists))))) @@ -1344,7 +1316,7 @@ string and TEMPLATE is a `yas--template' structure." (save-excursion (save-restriction (save-match-data - (eval condition)))) + (eval condition t)))) (error (progn (yas--message 1 "Error in condition evaluation: %s" (error-message-string err)) nil)))) @@ -1502,7 +1474,7 @@ Also tries to work around Emacs Bug#30931." (save-excursion (yas--save-restriction-and-widen (save-match-data - (let ((result (eval form))) + (let ((result (eval form t))) (when result (format "%s" result)))))) ((debug error) (error-message-string oops))))) @@ -1518,7 +1490,7 @@ return an expression that when evaluated will issue an error." (condition-case err (read string) (error (and (not nil-on-error) - `(error (error-message-string ,err)))))) + `(error (error-message-string ',err)))))) (defun yas--read-keybinding (keybinding) "Read KEYBINDING as a snippet keybinding, return a vector." @@ -1813,7 +1785,8 @@ Optional PROMPT sets the prompt to use." SNIPPETS is a list of snippet definitions, each taking the following form - (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID SAVE-FILE) + (KEY TEMPLATE + NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID SAVE-FILE) Within these, only KEY and TEMPLATE are actually mandatory. @@ -2074,7 +2047,7 @@ prefix argument." "successfully"))))))) (defvar yas-after-reload-hook nil - "Hooks run after `yas-reload-all'.") + "Hook run after `yas-reload-all'.") (defun yas--load-pending-jits () (dolist (mode (yas--modes-to-activate)) @@ -2341,7 +2314,7 @@ value for the first time then always returns a cached value.") (put ',func 'yas--condition-cache (cons yas--condition-cache-timestamp new-value)) new-value))))) -(defalias 'yas-expand 'yas-expand-from-trigger-key) +(defalias 'yas-expand #'yas-expand-from-trigger-key) (defun yas-expand-from-trigger-key (&optional field) "Expand a snippet before point. @@ -2980,7 +2953,8 @@ marks it as something else (typically comment ender)." 'again)) (defun yas-longest-key-from-whitespace (start-point) - "As `yas-key-syntaxes' element, look for longest key between point and whitespace. + "Look for longest key between point and whitespace. +For use as `yas-key-syntaxes' element. A newline will be considered whitespace even if the mode syntax marks it as something else (typically comment ender)." @@ -3067,8 +3041,7 @@ snippet field. The arguments are the same as `completing-read'. (defun yas-throw (text) "Signal `yas-exception' with TEXT as the reason." (signal 'yas-exception (list text))) -(put 'yas-exception 'error-conditions '(error yas-exception)) -(put 'yas-exception 'error-message "[yas] Exception") +(define-error 'yas-exception "[yas] Exception") (defun yas-verify-value (possibilities) "Verify that the current field value is in POSSIBILITIES. @@ -3208,7 +3181,7 @@ expression that evaluates to its value." `(let ((,envvar ,env)) (cl-progv (mapcar #'car ,envvar) - (mapcar (lambda (v-f) (eval (cadr v-f))) ,envvar) + (mapcar (lambda (v-f) (eval (cadr v-f) t)) ,envvar) ,@body)))) (defun yas--snippet-map-markers (fun snippet) @@ -3349,7 +3322,7 @@ equivalent to a range covering the whole buffer." (cl-sort snippets #'>= :key #'yas--snippet-id)))) (define-obsolete-function-alias 'yas--snippets-at-point - 'yas-active-snippets "0.12") + #'yas-active-snippets "0.12") (defun yas-next-field-or-maybe-expand () "Try to expand a snippet at a key before point. @@ -3728,8 +3701,8 @@ Use as a `:filter' argument for a conditional keybinding." "Clears unmodified field if at field start, skips to next tab. Otherwise deletes a character normally by calling `delete-char'." - (interactive) (declare (obsolete "Bind to `yas-maybe-skip-and-clear-field' instead." "0.13")) + (interactive) (cond ((yas--maybe-clear-field-filter t) (yas--skip-and-clear (or field (yas-current-field))) (yas-next-field 1)) @@ -3880,7 +3853,7 @@ field start. This hook does nothing if an undo is in progress." snippet (yas--snippet-field-mirrors snippet))) (setq yas--todo-snippet-indent nil)))) -(defun yas--auto-fill () +(defun yas--auto-fill (orig-fun &rest args) ;; Preserve snippet markers during auto-fill. (let* ((orig-point (point)) (end (progn (forward-paragraph) (point))) @@ -3897,44 +3870,7 @@ field start. This hook does nothing if an undo is in progress." reoverlays)) (goto-char orig-point) (let ((yas--inhibit-overlay-hooks t)) - (if yas--original-auto-fill-function - (funcall yas--original-auto-fill-function) - ;; Shouldn't happen, gather more info about it (see #873/919). - (let ((yas--fill-fun-values `((t ,(default-value 'yas--original-auto-fill-function)))) - (fill-fun-values `((t ,(default-value 'auto-fill-function)))) - ;; Listing 2 buffers with the same value is enough - (print-length 3)) - (save-current-buffer - (dolist (buf (let ((bufs (buffer-list))) - ;; List the current buffer first. - (setq bufs (cons (current-buffer) - (remq (current-buffer) bufs))))) - (set-buffer buf) - (let* ((yf-cell (assq yas--original-auto-fill-function - yas--fill-fun-values)) - (af-cell (assq auto-fill-function fill-fun-values))) - (when (local-variable-p 'yas--original-auto-fill-function) - (if yf-cell (setcdr yf-cell (cons buf (cdr yf-cell))) - (push (list yas--original-auto-fill-function buf) yas--fill-fun-values))) - (when (local-variable-p 'auto-fill-function) - (if af-cell (setcdr af-cell (cons buf (cdr af-cell))) - (push (list auto-fill-function buf) fill-fun-values)))))) - (lwarn '(yasnippet auto-fill bug) :error - "`yas--original-auto-fill-function' unexpectedly nil in %S! Disabling auto-fill. - %S - `auto-fill-function': %S\n%s" - (current-buffer) yas--fill-fun-values fill-fun-values - (if (fboundp 'backtrace--print-frame) - (with-output-to-string - (mapc (lambda (frame) - (apply #'backtrace--print-frame frame)) - yas--watch-auto-fill-backtrace)) - "")) - ;; Try to avoid repeated triggering of this bug. - (auto-fill-mode -1) - ;; Don't pop up more than once in a session (still log though). - (defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'. - (add-to-list 'warning-suppress-types '(yasnippet auto-fill bug))))) + (apply orig-fun args)) (save-excursion (setq end (progn (forward-paragraph) (point))) (setq beg (progn (backward-paragraph) (point)))) @@ -4006,8 +3942,6 @@ Move the overlays, or create them if they do not exit." (cl-loop for snippet in snippets do (yas--commit-snippet snippet))))) -(add-to-list 'debug-ignored-errors "^Exit the snippet first!$") - ;;; Snippet expansion and "stacked" expansion: ;; @@ -4739,10 +4673,11 @@ The following count as a field: * \"${n: text}\", for a numbered field with default text, as long as N is not 0; -* \"${n: text$(expression)}, the same with a Lisp expression; - this is caught with the curiously named `yas--multi-dollar-lisp-expression-regexp' +* \"${n: text$(expression)}, the same with a Lisp expression; this is caught + with the curiously named `yas--multi-dollar-lisp-expression-regexp' -* the same as above but unnumbered, (no N:) and number is calculated automatically. +* the same as above but unnumbered, (no N:) and number is calculated + automatically. When multiple expressions are found, only the last one counts." ;; @@ -4988,18 +4923,6 @@ When multiple expressions are found, only the last one counts." ;; (defun yas--post-command-handler () "Handles various yasnippet conditions after each command." - (when (and yas--watch-auto-fill-backtrace - (fboundp 'backtrace--print-frame) - (null yas--original-auto-fill-function) - (eq auto-fill-function 'yas--auto-fill)) - (lwarn '(yasnippet auto-fill bug) :error - "`yas--original-auto-fill-function' unexpectedly nil! Please report this backtrace\n%S" - (with-output-to-string - (mapc #'backtrace--print-frame - yas--watch-auto-fill-backtrace))) - ;; Don't pop up more than once in a session (still log though). - (defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'. - (add-to-list 'warning-suppress-types '(yasnippet auto-fill bug))) (yas--do-todo-snippet-indent) (condition-case err (progn (yas--finish-moving-snippets) -- cgit v1.3