diff options
| author | Visuwesh | 2024-09-09 20:08:04 +0530 |
|---|---|---|
| committer | Eli Zaretskii | 2024-09-14 12:41:29 +0300 |
| commit | db1eb8a282c1832fd34be049e80dcb1a3b59ade2 (patch) | |
| tree | e0aed9c7549083dfad9a35bceb651082befbcc21 | |
| parent | 7c767ec781fdba02d073b79113b1d8d89548bb08 (diff) | |
| download | emacs-db1eb8a282c1832fd34be049e80dcb1a3b59ade2.tar.gz emacs-db1eb8a282c1832fd34be049e80dcb1a3b59ade2.zip | |
Make the *grep* buffer editable
* lisp/progmodes/compile.el (compilation--update-markers):
Factor out function...
(compilation-next-error-function): ...from here. Adjust
to use the above.
* lisp/progmodes/grep.el (grep-edit--prepare-buffer)
(grep-edit-mode-map, grep-edit-mode-hook, grep-edit-mode)
(grep-change-to-grep-edit-mode, grep-edit-save-changes): Add
new 'grep-edit-mode' to make the grep results editable like
in 'occur-edit-mode' by using the 'occur' framework.
(grep-mode-map): Bind 'e' to the new command
'grep-change-to-grep-edit-mode'.
* doc/emacs/building.texi (Grep Searching): Update Info
manual to include the above command.
* etc/NEWS: Announce the change. (Bug#70820)
| -rw-r--r-- | doc/emacs/building.texi | 10 | ||||
| -rw-r--r-- | etc/NEWS | 9 | ||||
| -rw-r--r-- | lisp/progmodes/compile.el | 95 | ||||
| -rw-r--r-- | lisp/progmodes/grep.el | 86 |
4 files changed, 156 insertions, 44 deletions
diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi index bb03d8cf325..4b2f1ed0649 100644 --- a/doc/emacs/building.texi +++ b/doc/emacs/building.texi | |||
| @@ -528,6 +528,16 @@ grep-find-toggle-abbreviation}. To disable this abbreviation of the | |||
| 528 | shell commands, customize the option @code{grep-find-abbreviate} to a | 528 | shell commands, customize the option @code{grep-find-abbreviate} to a |
| 529 | @code{nil} value. | 529 | @code{nil} value. |
| 530 | 530 | ||
| 531 | @findex grep-change-to-grep-edit-mode | ||
| 532 | @cindex Grep Edit mode | ||
| 533 | @cindex mode, Grep Edit | ||
| 534 | Typing @kbd{e} in the @file{*grep*} buffer makes the buffer writiable | ||
| 535 | and enters the Grep Edit mode. Similar to Occur Edit mode (@pxref{Other | ||
| 536 | Repeating Search}), you can edit the matching lines reported by | ||
| 537 | @code{grep} and have those changes reflected in the buffer visiting the | ||
| 538 | originating file. Type @kbd{C-c C-c} to leave the Grep Edit mode and | ||
| 539 | return to the Grep mode. | ||
| 540 | |||
| 531 | @node Flymake | 541 | @node Flymake |
| 532 | @section Finding Syntax Errors On The Fly | 542 | @section Finding Syntax Errors On The Fly |
| 533 | @cindex checking syntax | 543 | @cindex checking syntax |
| @@ -328,6 +328,15 @@ fontifying them, which can be slow for remote directories. Setting | |||
| 328 | 'dired-check-symlinks' to nil disables these checks. Defaults to t, can | 328 | 'dired-check-symlinks' to nil disables these checks. Defaults to t, can |
| 329 | be set as a connection-local variable. | 329 | be set as a connection-local variable. |
| 330 | 330 | ||
| 331 | ** Grep | ||
| 332 | |||
| 333 | +++ | ||
| 334 | *** Grep results can be edited to reflect changes in the originating file. | ||
| 335 | Like Occur Edit mode, typing 'e' in the '*grep*' buffer will now make | ||
| 336 | the 'grep' results editable. The edits will be reflected in the buffer | ||
| 337 | visiting the originating file. Typing 'C-c C-c' will leave the Grep | ||
| 338 | Edit mode. | ||
| 339 | |||
| 331 | 340 | ||
| 332 | * New Modes and Packages in Emacs 31.1 | 341 | * New Modes and Packages in Emacs 31.1 |
| 333 | 342 | ||
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index d2e74aa44a6..a78ac1b6462 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el | |||
| @@ -2855,6 +2855,53 @@ as a last resort." | |||
| 2855 | (current-buffer) | 2855 | (current-buffer) |
| 2856 | (next-error-find-buffer avoid-current 'compilation-buffer-internal-p))) | 2856 | (next-error-find-buffer avoid-current 'compilation-buffer-internal-p))) |
| 2857 | 2857 | ||
| 2858 | (defun compilation--update-markers (loc marker screen-columns first-column) | ||
| 2859 | "Update markers in LOC, and set MARKER to location pointed by LOC. | ||
| 2860 | SCREEN-COLUMNS and FIRST-COLUMN are the value of | ||
| 2861 | `compilation-error-screen-columns' and `compilation-first-column' to use | ||
| 2862 | if they are not set buffer-locally in the target buffer." | ||
| 2863 | (with-current-buffer | ||
| 2864 | (if (bufferp (caar (compilation--loc->file-struct loc))) | ||
| 2865 | (caar (compilation--loc->file-struct loc)) | ||
| 2866 | (apply #'compilation-find-file | ||
| 2867 | marker | ||
| 2868 | (caar (compilation--loc->file-struct loc)) | ||
| 2869 | (cadr (car (compilation--loc->file-struct loc))) | ||
| 2870 | (compilation--file-struct->formats | ||
| 2871 | (compilation--loc->file-struct loc)))) | ||
| 2872 | (let ((screen-columns | ||
| 2873 | ;; Obey the compilation-error-screen-columns of the target | ||
| 2874 | ;; buffer if its major mode set it buffer-locally. | ||
| 2875 | (if (local-variable-p 'compilation-error-screen-columns) | ||
| 2876 | compilation-error-screen-columns screen-columns)) | ||
| 2877 | (compilation-first-column | ||
| 2878 | (if (local-variable-p 'compilation-first-column) | ||
| 2879 | compilation-first-column first-column)) | ||
| 2880 | (last 1)) | ||
| 2881 | (save-restriction | ||
| 2882 | (widen) | ||
| 2883 | (goto-char (point-min)) | ||
| 2884 | ;; Treat file's found lines in forward order, 1 by 1. | ||
| 2885 | (dolist (line (reverse (cddr (compilation--loc->file-struct loc)))) | ||
| 2886 | (when (car line) ; else this is a filename without a line# | ||
| 2887 | (compilation-beginning-of-line (- (car line) last -1)) | ||
| 2888 | (setq last (car line))) | ||
| 2889 | ;; Treat line's found columns and store/update a marker for each. | ||
| 2890 | (dolist (col (cdr line)) | ||
| 2891 | (if (compilation--loc->col col) | ||
| 2892 | (if (eq (compilation--loc->col col) -1) | ||
| 2893 | ;; Special case for range end. | ||
| 2894 | (end-of-line) | ||
| 2895 | (compilation-move-to-column (compilation--loc->col col) | ||
| 2896 | screen-columns)) | ||
| 2897 | (beginning-of-line) | ||
| 2898 | (skip-chars-forward " \t")) | ||
| 2899 | (if (compilation--loc->marker col) | ||
| 2900 | (set-marker (compilation--loc->marker col) (point)) | ||
| 2901 | (setf (compilation--loc->marker col) (point-marker))) | ||
| 2902 | ;; (setf (compilation--loc->timestamp col) timestamp) | ||
| 2903 | )))))) | ||
| 2904 | |||
| 2858 | ;;;###autoload | 2905 | ;;;###autoload |
| 2859 | (defun compilation-next-error-function (n &optional reset) | 2906 | (defun compilation-next-error-function (n &optional reset) |
| 2860 | "Advance to the next error message and visit the file where the error was. | 2907 | "Advance to the next error message and visit the file where the error was. |
| @@ -2864,7 +2911,6 @@ This is the value of `next-error-function' in Compilation buffers." | |||
| 2864 | (setq compilation-current-error nil)) | 2911 | (setq compilation-current-error nil)) |
| 2865 | (let* ((screen-columns compilation-error-screen-columns) | 2912 | (let* ((screen-columns compilation-error-screen-columns) |
| 2866 | (first-column compilation-first-column) | 2913 | (first-column compilation-first-column) |
| 2867 | (last 1) | ||
| 2868 | (msg (compilation-next-error (or n 1) nil | 2914 | (msg (compilation-next-error (or n 1) nil |
| 2869 | (or compilation-current-error | 2915 | (or compilation-current-error |
| 2870 | compilation-messages-start | 2916 | compilation-messages-start |
| @@ -2876,9 +2922,9 @@ This is the value of `next-error-function' in Compilation buffers." | |||
| 2876 | (user-error "No next error")) | 2922 | (user-error "No next error")) |
| 2877 | (setq compilation-current-error (point-marker) | 2923 | (setq compilation-current-error (point-marker) |
| 2878 | overlay-arrow-position | 2924 | overlay-arrow-position |
| 2879 | (if (bolp) | 2925 | (if (bolp) |
| 2880 | compilation-current-error | 2926 | compilation-current-error |
| 2881 | (copy-marker (line-beginning-position)))) | 2927 | (copy-marker (line-beginning-position)))) |
| 2882 | ;; If loc contains no marker, no error in that file has been visited. | 2928 | ;; If loc contains no marker, no error in that file has been visited. |
| 2883 | ;; If the marker is invalid the buffer has been killed. | 2929 | ;; If the marker is invalid the buffer has been killed. |
| 2884 | ;; So, recalculate all markers for that file. | 2930 | ;; So, recalculate all markers for that file. |
| @@ -2895,46 +2941,7 @@ This is the value of `next-error-function' in Compilation buffers." | |||
| 2895 | ;; (equal (compilation--loc->timestamp loc) | 2941 | ;; (equal (compilation--loc->timestamp loc) |
| 2896 | ;; (setq timestamp compilation-buffer-modtime))) | 2942 | ;; (setq timestamp compilation-buffer-modtime))) |
| 2897 | ) | 2943 | ) |
| 2898 | (with-current-buffer | 2944 | (compilation--update-markers loc marker screen-columns first-column)) |
| 2899 | (if (bufferp (caar (compilation--loc->file-struct loc))) | ||
| 2900 | (caar (compilation--loc->file-struct loc)) | ||
| 2901 | (apply #'compilation-find-file | ||
| 2902 | marker | ||
| 2903 | (caar (compilation--loc->file-struct loc)) | ||
| 2904 | (cadr (car (compilation--loc->file-struct loc))) | ||
| 2905 | (compilation--file-struct->formats | ||
| 2906 | (compilation--loc->file-struct loc)))) | ||
| 2907 | (let ((screen-columns | ||
| 2908 | ;; Obey the compilation-error-screen-columns of the target | ||
| 2909 | ;; buffer if its major mode set it buffer-locally. | ||
| 2910 | (if (local-variable-p 'compilation-error-screen-columns) | ||
| 2911 | compilation-error-screen-columns screen-columns)) | ||
| 2912 | (compilation-first-column | ||
| 2913 | (if (local-variable-p 'compilation-first-column) | ||
| 2914 | compilation-first-column first-column))) | ||
| 2915 | (save-restriction | ||
| 2916 | (widen) | ||
| 2917 | (goto-char (point-min)) | ||
| 2918 | ;; Treat file's found lines in forward order, 1 by 1. | ||
| 2919 | (dolist (line (reverse (cddr (compilation--loc->file-struct loc)))) | ||
| 2920 | (when (car line) ; else this is a filename without a line# | ||
| 2921 | (compilation-beginning-of-line (- (car line) last -1)) | ||
| 2922 | (setq last (car line))) | ||
| 2923 | ;; Treat line's found columns and store/update a marker for each. | ||
| 2924 | (dolist (col (cdr line)) | ||
| 2925 | (if (compilation--loc->col col) | ||
| 2926 | (if (eq (compilation--loc->col col) -1) | ||
| 2927 | ;; Special case for range end. | ||
| 2928 | (end-of-line) | ||
| 2929 | (compilation-move-to-column (compilation--loc->col col) | ||
| 2930 | screen-columns)) | ||
| 2931 | (beginning-of-line) | ||
| 2932 | (skip-chars-forward " \t")) | ||
| 2933 | (if (compilation--loc->marker col) | ||
| 2934 | (set-marker (compilation--loc->marker col) (point)) | ||
| 2935 | (setf (compilation--loc->marker col) (point-marker))) | ||
| 2936 | ;; (setf (compilation--loc->timestamp col) timestamp) | ||
| 2937 | )))))) | ||
| 2938 | (compilation-goto-locus marker (compilation--loc->marker loc) | 2945 | (compilation-goto-locus marker (compilation--loc->marker loc) |
| 2939 | (compilation--loc->marker end-loc)) | 2946 | (compilation--loc->marker end-loc)) |
| 2940 | (setf (compilation--loc->visited loc) t))) | 2947 | (setf (compilation--loc->visited loc) t))) |
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index d2d0baa235c..54006560224 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el | |||
| @@ -310,6 +310,8 @@ See `compilation-error-screen-columns'." | |||
| 310 | (define-key map "}" #'compilation-next-file) | 310 | (define-key map "}" #'compilation-next-file) |
| 311 | (define-key map "\t" #'compilation-next-error) | 311 | (define-key map "\t" #'compilation-next-error) |
| 312 | (define-key map [backtab] #'compilation-previous-error) | 312 | (define-key map [backtab] #'compilation-previous-error) |
| 313 | |||
| 314 | (define-key map "e" #'grep-change-to-grep-edit-mode) | ||
| 313 | map) | 315 | map) |
| 314 | "Keymap for grep buffers. | 316 | "Keymap for grep buffers. |
| 315 | `compilation-minor-mode-map' is a cdr of this.") | 317 | `compilation-minor-mode-map' is a cdr of this.") |
| @@ -1052,6 +1054,90 @@ list is empty)." | |||
| 1052 | command-args) | 1054 | command-args) |
| 1053 | #'grep-mode)) | 1055 | #'grep-mode)) |
| 1054 | 1056 | ||
| 1057 | (defun grep-edit--prepare-buffer () | ||
| 1058 | "Mark relevant regions read-only, and add relevant occur text-properties." | ||
| 1059 | (save-excursion | ||
| 1060 | (goto-char (point-min)) | ||
| 1061 | (let ((inhibit-read-only t) | ||
| 1062 | (dummy (make-marker)) | ||
| 1063 | match) | ||
| 1064 | (while (setq match (text-property-search-forward 'compilation-annotation)) | ||
| 1065 | (add-text-properties (prop-match-beginning match) (prop-match-end match) | ||
| 1066 | '(read-only t))) | ||
| 1067 | (goto-char (point-min)) | ||
| 1068 | (while (setq match (text-property-search-forward 'compilation-message)) | ||
| 1069 | (add-text-properties (prop-match-beginning match) (prop-match-end match) | ||
| 1070 | '(read-only t occur-prefix t)) | ||
| 1071 | (let ((loc (compilation--message->loc (prop-match-value match))) | ||
| 1072 | m) | ||
| 1073 | ;; Update the markers if necessary. | ||
| 1074 | (unless (and (compilation--loc->marker loc) | ||
| 1075 | (marker-buffer (compilation--loc->marker loc))) | ||
| 1076 | (compilation--update-markers loc dummy compilation-error-screen-columns compilation-first-column)) | ||
| 1077 | (setq m (compilation--loc->marker loc)) | ||
| 1078 | (add-text-properties (prop-match-beginning match) | ||
| 1079 | (or (next-single-property-change | ||
| 1080 | (prop-match-end match) | ||
| 1081 | 'compilation-message) | ||
| 1082 | (1+ (pos-eol))) | ||
| 1083 | `(occur-target ((,m . ,m))))))))) | ||
| 1084 | |||
| 1085 | (defvar grep-edit-mode-map | ||
| 1086 | (let ((map (make-sparse-keymap))) | ||
| 1087 | (set-keymap-parent map text-mode-map) | ||
| 1088 | (define-key map (kbd "C-c C-c") #'grep-edit-save-changes) | ||
| 1089 | map) | ||
| 1090 | "Keymap for `grep-edit-mode'.") | ||
| 1091 | |||
| 1092 | (defvar grep-edit-mode-hook nil | ||
| 1093 | "Hooks run when changing to Grep-Edit mode.") | ||
| 1094 | |||
| 1095 | (defun grep-edit-mode () | ||
| 1096 | "Major mode for editing *grep* buffers. | ||
| 1097 | In this mode, changes to the *grep* buffer are applied to the | ||
| 1098 | originating files. | ||
| 1099 | \\<grep-edit-mode-map> | ||
| 1100 | Type \\[grep-edit-save-changes] to exit Grep-Edit mode, return to Grep | ||
| 1101 | mode. | ||
| 1102 | |||
| 1103 | The only editable texts in a Grep-Edit buffer are the match results." | ||
| 1104 | (interactive) | ||
| 1105 | (error "This mode can be enabled only by `grep-change-to-grep-edit-mode'")) | ||
| 1106 | (put 'grep-edit-mode 'mode-class 'special) | ||
| 1107 | |||
| 1108 | (defun grep-change-to-grep-edit-mode () | ||
| 1109 | "Switch to `grep-edit-mode' to edit *grep* buffer." | ||
| 1110 | (interactive) | ||
| 1111 | (unless (derived-mode-p 'grep-mode) | ||
| 1112 | (error "Not a Grep buffer")) | ||
| 1113 | (when (get-buffer-process (current-buffer)) | ||
| 1114 | (error "Cannot switch when grep is running")) | ||
| 1115 | (use-local-map grep-edit-mode-map) | ||
| 1116 | (grep-edit--prepare-buffer) | ||
| 1117 | (setq buffer-read-only nil) | ||
| 1118 | (setq major-mode 'grep-edit-mode) | ||
| 1119 | (setq mode-name "Grep-Edit") | ||
| 1120 | (buffer-enable-undo) | ||
| 1121 | (set-buffer-modified-p nil) | ||
| 1122 | (setq buffer-undo-list nil) | ||
| 1123 | (add-hook 'after-change-functions #'occur-after-change-function nil t) | ||
| 1124 | (run-mode-hooks 'grep-edit-mode-hook) | ||
| 1125 | (message "Editing: \\[grep-edit-save-changes] to return to Grep mode")) | ||
| 1126 | |||
| 1127 | (defun grep-edit-save-changes () | ||
| 1128 | "Switch back to Grep mode." | ||
| 1129 | (interactive) | ||
| 1130 | (unless (derived-mode-p 'grep-edit-mode) | ||
| 1131 | (error "Not a Grep-Edit buffer")) | ||
| 1132 | (remove-hook 'after-change-functions #'occur-after-change-function t) | ||
| 1133 | (use-local-map grep-mode-map) | ||
| 1134 | (setq buffer-read-only t) | ||
| 1135 | (setq major-mode 'grep-mode) | ||
| 1136 | (setq mode-name "Grep") | ||
| 1137 | (force-mode-line-update) | ||
| 1138 | (buffer-disable-undo) | ||
| 1139 | (setq buffer-undo-list t) | ||
| 1140 | (message "Switching to Grep mode")) | ||
| 1055 | 1141 | ||
| 1056 | ;;;###autoload | 1142 | ;;;###autoload |
| 1057 | (defun grep-find (command-args) | 1143 | (defun grep-find (command-args) |