From 5c2c9a50da3a3f534842ffe95a49fe990000a072 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Tue, 6 Jan 2026 21:25:57 +0100 Subject: Update markdown, rust and yasnippet --- .emacs.d/lisp/markdown-mode.el | 95 +++++++++++++++++++++++++---------- .emacs.d/lisp/rust-cargo-tests.el | 17 +++++++ .emacs.d/lisp/rust-cargo.el | 13 +++-- .emacs.d/lisp/rust-compile.el | 18 +++++++ .emacs.d/lisp/rust-mode-tests.el | 102 +++++++++++++++++++++++++++++++++++++- .emacs.d/lisp/rust-rustfmt.el | 6 ++- .emacs.d/lisp/yasnippet.el | 25 ++++++---- 7 files changed, 231 insertions(+), 45 deletions(-) diff --git a/.emacs.d/lisp/markdown-mode.el b/.emacs.d/lisp/markdown-mode.el index 671210e..77f9bf5 100644 --- a/.emacs.d/lisp/markdown-mode.el +++ b/.emacs.d/lisp/markdown-mode.el @@ -187,12 +187,10 @@ fewer than six nested heading levels are used." :safe 'natnump :package-version '(markdown-mode . "2.4")) -(defcustom markdown-asymmetric-header nil +(defcustom markdown-asymmetric-header t "Determines if atx header style will be asymmetric. Set to a non-nil value to use asymmetric header styling, placing -header markup only at the beginning of the line. By default, -balanced markup will be inserted at the beginning and end of the -line around the header title." +header markup only at the beginning of the line." :group 'markdown :type 'boolean) @@ -2612,7 +2610,11 @@ Return the point at the end when a list item was found at the original point. If the point is not in a list item, do nothing." (let (indent) (forward-line) - (setq indent (current-indentation)) + ;; #904 consider a space indentation and tab indentation case + (save-excursion + (let ((pos (point))) + (back-to-indentation) + (setq indent (- (point) pos)))) (while (cond ;; Stop at end of the buffer. @@ -2902,7 +2904,8 @@ data. See `markdown-inline-code-at-point-p' for inline code." (defun markdown-heading-at-point (&optional pos) "Return non-nil if there is a heading at the POS. Set match data for `markdown-regex-header'." - (let ((match-data (get-text-property (or pos (point)) 'markdown-heading))) + (let* ((p (or pos (if (and (eolp) (>= (point) 2)) (1- (point)) (point)))) + (match-data (get-text-property p 'markdown-heading))) (when match-data (set-match-data match-data) t))) @@ -9321,6 +9324,37 @@ position." (require 'edit-indirect nil t) (defvar edit-indirect-guess-mode-function) (defvar edit-indirect-after-commit-functions) +(defvar edit-indirect--overlay) +(declare-function edit-indirect-commit "edit-indirect") +(declare-function edit-indirect--commit "edit-indirect") + +(defvar-local markdown--edit-indirect-committed-position nil) + +(defun markdown--edit-indirect-save-committed-position () + "Save where editing is committed in a local variable in the parent buffer." + (if-let* ((parent-buffer (overlay-buffer edit-indirect--overlay)) + ((with-current-buffer parent-buffer + (derived-mode-p 'markdown-mode))) + (pos (cons (line-number-at-pos) (current-column)))) + (with-current-buffer parent-buffer + (setq markdown--edit-indirect-committed-position pos)))) + +(with-eval-after-load 'edit-indirect + (advice-add #'edit-indirect--commit :after #'markdown--edit-indirect-save-committed-position)) + +(defun markdown--edit-indirect-move-to-committed-position () + "Move the point in the code block corresponding to the saved committed position." + (when-let* ((pos markdown--edit-indirect-committed-position) + (bounds (markdown-get-enclosing-fenced-block-construct)) + (fence-begin (nth 0 bounds))) + (goto-char fence-begin) + (let ((block-indentation (current-indentation))) + (forward-line (car pos)) + (move-to-column (+ block-indentation (cdr pos))))) + (setq markdown--edit-indirect-committed-position nil)) + +(with-eval-after-load 'edit-indirect + (advice-add #'edit-indirect-commit :after #'markdown--edit-indirect-move-to-committed-position)) (defun markdown--edit-indirect-after-commit-function (beg end) "Corrective logic run on code block content from lines BEG to END. @@ -9342,18 +9376,24 @@ at the END of code blocks." (interactive) (save-excursion (if (fboundp 'edit-indirect-region) - (let* ((bounds (markdown-get-enclosing-fenced-block-construct)) - (begin (and bounds (not (null (nth 0 bounds))) (goto-char (nth 0 bounds)) (line-beginning-position 2))) - (end (and bounds(not (null (nth 1 bounds))) (goto-char (nth 1 bounds)) (line-beginning-position 1)))) - (if (and begin end) - (let* ((indentation (and (goto-char (nth 0 bounds)) (current-indentation))) - (lang (markdown-code-block-lang)) - (mode (or (and lang (markdown-get-lang-mode lang)) - markdown-edit-code-block-default-mode)) - (edit-indirect-guess-mode-function - (lambda (_parent-buffer _beg _end) - (funcall mode))) - (indirect-buf (edit-indirect-region begin end 'display-buffer))) + (if-let* ((bounds (markdown-get-enclosing-fenced-block-construct)) + (fence-begin (nth 0 bounds)) + (fence-end (nth 1 bounds))) + (let* ((original-line (line-number-at-pos)) + (original-column (current-column)) + (begin (progn (goto-char fence-begin) (line-beginning-position 2))) + (line (max 0 (- original-line (line-number-at-pos) 1))) + (indentation (current-indentation)) + (column (max 0 (- original-column indentation))) + (end (progn (goto-char fence-end) (line-beginning-position 1))) + (lang (markdown-code-block-lang)) + (mode (or (and lang (markdown-get-lang-mode lang)) + markdown-edit-code-block-default-mode)) + (edit-indirect-guess-mode-function + (lambda (_parent-buffer _beg _end) + (funcall mode))) + (indirect-buf (edit-indirect-region begin end 'display-buffer))) + (with-current-buffer indirect-buf ;; reset `sh-shell' when indirect buffer (when (and (not (member system-type '(ms-dos windows-nt))) (member mode '(shell-script-mode sh-mode)) @@ -9361,16 +9401,17 @@ at the END of code blocks." (mapcar (lambda (e) (symbol-name (car e))) sh-ancestor-alist) '("csh" "rc" "sh")))) - (with-current-buffer indirect-buf - (sh-set-shell lang))) + (sh-set-shell lang)) (when (> indentation 0) ;; un-indent in edit-indirect buffer - (with-current-buffer indirect-buf - (indent-rigidly (point-min) (point-max) (- indentation))))) - (user-error "Not inside a GFM or tilde fenced code block"))) + (indent-rigidly (point-min) (point-max) (- indentation))) + (goto-char (point-min)) + (forward-line line) + (move-to-column column))) + (user-error "Not inside a GFM or tilde fenced code block")) (when (y-or-n-p "Package edit-indirect needed to edit code blocks. Install it now? ") - (progn (package-refresh-contents) - (package-install 'edit-indirect) - (markdown-edit-code-block)))))) + (package-refresh-contents) + (package-install 'edit-indirect) + (markdown-edit-code-block))))) ;;; Table Editing ============================================================= @@ -10522,7 +10563,7 @@ rows and columns and the column alignment." (define-key map (kbd "SPC") #'scroll-up-command) (define-key map (kbd ">") #'end-of-buffer) (define-key map (kbd "<") #'beginning-of-buffer) - (define-key map (kbd "q") #'kill-this-buffer) + (define-key map (kbd "q") #'kill-current-buffer) (define-key map (kbd "?") #'describe-mode) map) "Keymap for `markdown-view-mode'.") diff --git a/.emacs.d/lisp/rust-cargo-tests.el b/.emacs.d/lisp/rust-cargo-tests.el index fe78ac7..1b072ee 100644 --- a/.emacs.d/lisp/rust-cargo-tests.el +++ b/.emacs.d/lisp/rust-cargo-tests.el @@ -21,6 +21,13 @@ (find-file main-file) ,expr))) +(defmacro rust-test--with-snippet-buffer (expr) + `(let* ((test-dir (expand-file-name "test-project/" default-directory)) + (snippet-file (expand-file-name "src/rustfmt-default.rs" test-dir))) + (save-current-buffer + (find-file snippet-file) + ,expr))) + (defun rust-test--find-string (string) "Find STRING in current buffer." (goto-char (point-min)) @@ -70,3 +77,13 @@ (should (eq major-mode 'rust-format-mode)) (should (rust-test--find-string "error:"))) (kill-buffer "*rustfmt*"))) + +(ert-deftest rust-test-respect-rustfmt-defaults () + (skip-unless (executable-find "rustfmt")) + (rust-test--with-snippet-buffer + (let ((old-content (buffer-string)) + (ret (rust-format-buffer))) + (should (string= old-content (buffer-string)))))) + +(ert-deftest rust-test-ensure-rustfmt-switches-nil () + (should (eq rust-rustfmt-switches nil))) diff --git a/.emacs.d/lisp/rust-cargo.el b/.emacs.d/lisp/rust-cargo.el index d9f1be5..d323b5d 100644 --- a/.emacs.d/lisp/rust-cargo.el +++ b/.emacs.d/lisp/rust-cargo.el @@ -31,6 +31,11 @@ worksapce for commands like `cargo check`." :type 'string :group 'rust-mode) +(defcustom rust-cargo-clippy-default-arguments '() + "Default arguments for running `cargo clippy`." + :type '(repeat string) + :group 'rust-mode) + ;;; Buffer Project (defvar-local rust-buffer-project nil) @@ -134,11 +139,13 @@ output buffer will be in comint mode, i.e. interactive." (interactive) (when (null rust-buffer-project) (rust-update-buffer-project)) - (let* ((args (list rust-cargo-bin "clippy" - (concat "--manifest-path=" rust-buffer-project))) + (let* ((args (append (list rust-cargo-bin "clippy" + (concat "--manifest-path=" rust-buffer-project)) + rust-cargo-clippy-default-arguments)) ;; set `compile-command' temporarily so `compile' doesn't ;; clobber the existing value - (compile-command (mapconcat #'shell-quote-argument args " "))) + (compile-command (concat (mapconcat #'shell-quote-argument args " ") + " " rust-cargo-default-arguments))) (rust--compile nil compile-command))) ;;; _ diff --git a/.emacs.d/lisp/rust-compile.el b/.emacs.d/lisp/rust-compile.el index 04ac6b6..cbdf43a 100644 --- a/.emacs.d/lisp/rust-compile.el +++ b/.emacs.d/lisp/rust-compile.el @@ -28,6 +28,12 @@ See `compilation-error-regexp-alist' for help on their format.") "Specifications for matching `:::` hints in rustc invocations. See `compilation-error-regexp-alist' for help on their format.") +(defvar rustc-backtrace-compilation-regexps + (let ((re (concat "^ +at " rustc-compilation-location))) + (cons re '(2 3 4 0 1))) + "Specifications for matching stack backtraces in rustc invocations. +See `compilation-error-regexp-alist' for help on their format.") + (defvar rustc-refs-compilation-regexps (let ((re "^\\([0-9]+\\)[[:space:]]*|")) (cons re '(nil 1 nil 0 1))) @@ -48,6 +54,12 @@ See `compilation-error-regexp-alist' for help on their format.") "Specifications for matching panics in cargo test invocations. See `compilation-error-regexp-alist' for help on their format.") +(defvar rustc-dbg!-compilation-regexps + (let ((re (concat "\\[" rustc-compilation-location "\\]"))) + (cons re '(2 3 4 0 1))) + "Specifications for matching dbg! output. +See `compilation-error-regexp-alist' for help on their format.") + (defun rustc-scroll-down-after-next-error () "In the new style error messages, the regular expression matches on the file name (which appears after `-->`), but the @@ -79,12 +91,18 @@ the compilation window until the top of the error is visible." (add-to-list 'compilation-error-regexp-alist-alist (cons 'rustc-colon rustc-colon-compilation-regexps)) (add-to-list 'compilation-error-regexp-alist 'rustc-colon) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rustc-backtrace rustc-backtrace-compilation-regexps)) + (add-to-list 'compilation-error-regexp-alist 'rustc-backtrace) (add-to-list 'compilation-error-regexp-alist-alist (cons 'cargo cargo-compilation-regexps)) (add-to-list 'compilation-error-regexp-alist-alist (cons 'rustc-panics rustc-panics-compilation-regexps)) (add-to-list 'compilation-error-regexp-alist 'rustc-panics) (add-to-list 'compilation-error-regexp-alist 'cargo) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rust-dbg! rustc-dbg!-compilation-regexps)) + (add-to-list 'compilation-error-regexp-alist 'rust-dbg!) (add-hook 'next-error-hook #'rustc-scroll-down-after-next-error))) ;;; _ diff --git a/.emacs.d/lisp/rust-mode-tests.el b/.emacs.d/lisp/rust-mode-tests.el index 62cd261..259afb2 100644 --- a/.emacs.d/lisp/rust-mode-tests.el +++ b/.emacs.d/lisp/rust-mode-tests.el @@ -887,6 +887,98 @@ struct A { " )) +;; When point is inside an example code block, indent-for-tab-command +;; should reindent the example code. +(ert-deftest indent-inside-doc-example () + (rust-test-manip-code + " +/// ``` +/// if 2 + 2 == 4 { +/// success(); +/// } +/// ``` +" + 34 + #'indent-for-tab-command + " +/// ``` +/// if 2 + 2 == 4 { +/// success(); +/// } +/// ``` +" + 38)) + +;; Inside example code blocks, hidden lines starting with "# " should +;; be indented as if the "# " wasn't there. +(ert-deftest indent-inside-doc-example-hidden-code () + (rust-test-manip-code + " +/// ``` +/// # if 2 + 2 == 4 { +/// # success(); +/// # } +/// ``` +" + 36 + #'indent-for-tab-command + " +/// ``` +/// # if 2 + 2 == 4 { +/// # success(); +/// # } +/// ``` +" + 42)) + +;; Inside example code blocks, hidden lines starting with "# " +;; shouldn't affect indentation of non-hidden lines. +(ert-deftest indent-inside-doc-example-with-hidden-block () + (rust-test-manip-code + " +/// ``` +/// # if 2 + 2 == 4 { +/// success(); +/// # } +/// ``` +" + 40 + #'indent-for-tab-command + " +/// ``` +/// # if 2 + 2 == 4 { +/// success(); +/// # } +/// ``` +" + 36)) + +;; When point is outside the comment, indent-for-tab-command should +;; reindent the comment line without affecting its contents. +(ert-deftest indent-outside-doc-example () + (rust-test-manip-code + " +impl Foo { + /// ``` + /// if 2 + 2 == 4 { + /// success(); + /// } + /// ``` +} +" + 49 + #'indent-for-tab-command + " +impl Foo { + /// ``` + /// if 2 + 2 == 4 { + /// success(); + /// } + /// ``` +} +" + 53)) + (defconst rust-test-motion-string " fn fn1(arg: i32) -> bool { @@ -3601,6 +3693,8 @@ let b = 1;" (insert "note: `ZZZ` could also refer to the constant imported here -> b\n --> file4.rs:12:34\n\n") (insert " ::: file5.rs:12:34\n\n") (insert "thread 'main' panicked at src/file7.rs:12:34:\n\n") + (insert "[src/file8.rs:159:5] symbol_value(SOME_VAR) = Some(\n\n") + (insert " at file9.rs:12:34\n\n") ;; should not match (insert "werror found a -> b\n --> no_match.rs:12:34\n\n") (insert "error[E0061]: this function takes 1 parameter but 2 parameters were supplied\n --> file6.rs:132:34 @@ -3620,12 +3714,16 @@ let b = 1;" (("file5.rs" "12" "34" compilation-info "file5.rs:12:34")) ((like-previous-one "82" back-to-indentation compilation-info "82") (like-previous-one "132" back-to-indentation compilation-info "132")) - (("src/file7.rs" "12" "34" nil "src/file7.rs:12:34"))) + (("src/file7.rs" "12" "34" nil "src/file7.rs:12:34")) + (("src/file8.rs" "159" "5" compilation-info "src/file8.rs:159:5")) + (("file9.rs" "12" "34" compilation-info "file9.rs:12:34"))) (mapcar #'rust-collect-matches (list rustc-compilation-regexps rustc-colon-compilation-regexps rustc-refs-compilation-regexps - rustc-panics-compilation-regexps)))))) + rustc-panics-compilation-regexps + rustc-dbg!-compilation-regexps + rustc-backtrace-compilation-regexps)))))) ;; If electric-pair-mode is available, load it and run the tests that use it. If not, ;; no error--the tests will be skipped. diff --git a/.emacs.d/lisp/rust-rustfmt.el b/.emacs.d/lisp/rust-rustfmt.el index 6fb0e87..adaeb0d 100644 --- a/.emacs.d/lisp/rust-rustfmt.el +++ b/.emacs.d/lisp/rust-rustfmt.el @@ -33,8 +33,10 @@ :type 'string :group 'rust-mode) -(defcustom rust-rustfmt-switches '("--edition" "2024") - "Arguments to pass when invoking the `rustfmt' executable." +(defcustom rust-rustfmt-switches nil + "Arguments to pass when invoking the `rustfmt' executable. This variable +will override any user configuration (e.g. rustfmt.toml). Recommendation +is to not modify this and rely on declarative configuration instead." :type '(repeat string) :group 'rust-mode) diff --git a/.emacs.d/lisp/yasnippet.el b/.emacs.d/lisp/yasnippet.el index 806f2bc..cbeebd1 100644 --- a/.emacs.d/lisp/yasnippet.el +++ b/.emacs.d/lisp/yasnippet.el @@ -5,7 +5,7 @@ ;; João Távora , ;; Noam Postavsky ;; Maintainer: Noam Postavsky -;; Version: 0.14.2 +;; Version: 0.14.3 ;; X-URL: http://github.com/joaotavora/yasnippet ;; Keywords: convenience, emulation ;; URL: http://github.com/joaotavora/yasnippet @@ -1933,16 +1933,18 @@ With prefix argument USE-JIT do jit-loading of snippets." (let ((output-file (expand-file-name ".yas-compiled-snippets.el" directory))) (with-temp-file output-file - (insert (format ";;; Compiled snippets and support files for `%s'\n" + (insert (format ";;; \"Compiled\" snippets and support files for `%S' -*- lexical-binding:t -*-\n" mode-sym)) (yas--load-directory-2 directory mode-sym) (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string))))) ;; Normal case. (unless (file-exists-p (expand-file-name ".yas-skip" directory)) - (unless (and (load (expand-file-name ".yas-compiled-snippets" directory) - 'noerror (<= yas-verbosity 3)) - (progn (yas--message 4 "Loaded compiled snippets from %s" directory) t)) + (if (let ((warning-inhibit-types + '((files missing-lexbind-cookie)))) + (load (expand-file-name ".yas-compiled-snippets" directory) + 'noerror (<= yas-verbosity 3))) + (yas--message 4 "Loaded compiled snippets from %s" directory) (yas--message 4 "Loading snippet files from %s" directory) (yas--load-directory-2 directory mode-sym))))) @@ -3200,12 +3202,13 @@ ENV is a lisp expression that evaluates to list of elements with the form (VAR FORM), where VAR is a symbol and FORM is a lisp expression that evaluates to its value." (declare (debug (form body)) (indent 1)) - (let ((envvar (make-symbol "envvar"))) - `(let ((,envvar ,env)) - (cl-progv - (mapcar #'car ,envvar) - (mapcar (lambda (v-f) (eval (cadr v-f) t)) ,envvar) - ,@body)))) + `(yas--letenv-f ,env (lambda () ,@body))) + +(defun yas--letenv-f (env body-fun) + (cl-progv + (mapcar #'car env) + (mapcar (lambda (v-f) (eval (cadr v-f) t)) env) + (funcall body-fun))) (defun yas--snippet-map-markers (fun snippet) "Apply FUN to all marker (sub)fields in SNIPPET. -- cgit v1.3