emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/dape 3d3edc944f 1/3: Rework dape-info to use revert-buf


From: ELPA Syncer
Subject: [elpa] externals/dape 3d3edc944f 1/3: Rework dape-info to use revert-buffer
Date: Sun, 25 Feb 2024 12:57:55 -0500 (EST)

branch: externals/dape
commit 3d3edc944ffae6341c804c5f356fbd1d747877be
Author: Daniel Pettersson <daniel@dpettersson.net>
Commit: Daniel Pettersson <daniel@dpettersson.net>

    Rework dape-info to use revert-buffer
    
    Use revert-buffer to align with emacs way of doing things
    
    Minimize footgunning by ensuring callback is called with the same
    buffer context as the request was invoked by.
---
 dape.el | 280 +++++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 145 insertions(+), 135 deletions(-)

diff --git a/dape.el b/dape.el
index 72a6d6cff8..484a94ab94 100644
--- a/dape.el
+++ b/dape.el
@@ -1159,27 +1159,34 @@ If NOWARN does not error on no active process."
   "Send request with COMMAND and ARGUMENTS to adapter CONN.
 If callback function CB is supplied, it's called on timeout
 and success.  See `dape--callback' for signature."
-  (jsonrpc-async-request conn command arguments
-                         :success-fn
-                         (when (functionp cb)
-                           (lambda (result)
-                             (funcall cb conn
-                                      (plist-get result :body)
-                                      (unless (eq (plist-get result :success) 
t)
-                                        (or (plist-get result :message) "")))))
-                         :error-fn 'ignore ;; will never be called
-                         :timeout-fn
-                         (when (functionp cb)
-                           (lambda ()
-                             (dape--repl-message
-                              (format
-                               "* Command %s timed out after %d seconds, the \
+  (let ((buffer (current-buffer)))
+    (jsonrpc-async-request conn command arguments
+                           :success-fn
+                           (when (functionp cb)
+                             (lambda (result)
+                               (with-current-buffer
+                                   (if (buffer-live-p buffer) buffer
+                                     (current-buffer))
+                                 (funcall cb conn
+                                          (plist-get result :body)
+                                          (unless (eq (plist-get result 
:success) t)
+                                            (or (plist-get result :message) 
""))))))
+                           :error-fn 'ignore ;; will never be called
+                           :timeout-fn
+                           (when (functionp cb)
+                             (lambda ()
+                               (dape--repl-message
+                                (format
+                                 "* Command %s timed out after %d seconds, the 
\
 timeout period is configurable with `dape-request-timeout' *"
-                               command
-                               dape-request-timeout)
-                              'dape-repl-error-face)
-                             (funcall cb conn nil "timeout")))
-                         :timeout dape-request-timeout))
+                                 command
+                                 dape-request-timeout)
+                                'dape-repl-error-face)
+                               (with-current-buffer
+                                   (if (buffer-live-p buffer) buffer
+                                     (current-buffer))
+                                 (funcall cb conn nil "timeout"))))
+                           :timeout dape-request-timeout)))
 
 (defun dape--initialize (conn)
   "Initialize and launch/attach adapter CONN."
@@ -2167,7 +2174,7 @@ Optional argument SKIP-REMOVE limits usage to only adding 
watched vars."
       (push (list :name expression)
             dape--watched)
       ;; FIXME don't want to have a depency on info ui in core commands
-      (dape--display-buffer (dape--info-buffer 'dape-info-watch-mode))))
+      (dape--display-buffer (dape--info-get-buffer-create 
'dape-info-watch-mode))))
   (run-hooks 'dape-update-ui-hooks))
 
 (defun dape-evaluate-expression (conn expression)
@@ -2662,8 +2669,6 @@ If SKIP-DISPLAY is non nil refrain from going to selected 
stack."
 (defvar-local dape--info-buffer-identifier nil
   "Identifying var for buffers, used only in scope buffer.
 Used there as scope index.")
-(defvar-local dape--info-buffer-in-redraw nil
-  "Guard for buffer `dape-info-update' fn.")
 
 (defvar dape--info-buffers nil
   "List containing `dape-info' buffers, might be un-live.")
@@ -2697,7 +2702,7 @@ REVERSED selects previous."
                               (cadr))
                  (car dape--info-buffer-related))))
     (gdb-set-window-buffer
-     (dape--info-buffer mode id) t)))
+     (dape--info-get-buffer-create mode id) t)))
 
 (defvar dape-info-parent-mode-map
   (let ((map (make-sparse-keymap)))
@@ -2709,17 +2714,16 @@ REVERSED selects previous."
 
 (defun dape--info-buffer-change-fn (&rest _rest)
   "Hook fn for `window-buffer-change-functions' to ensure update."
-  (ignore-errors
-    (dape--info-update (or (dape--live-connection 'stopped)
-                           (dape--live-connection 'newest t))
-                       (current-buffer))))
+  (when (derived-mode-p 'dape-info-parent-mode)
+    (ignore-errors (revert-buffer))))
 
 (define-derived-mode dape-info-parent-mode special-mode ""
   "Generic mode to derive all other Dape gud buffer modes from."
   :interactive nil
   (setq-local buffer-read-only t
               truncate-lines t
-              cursor-in-non-selected-windows nil)
+              cursor-in-non-selected-windows nil
+              revert-buffer-function #'dape--info-revert)
   (add-hook 'window-buffer-change-functions 'dape--info-buffer-change-fn
             nil 'local)
   (when dape-info-hide-mode-line
@@ -2738,8 +2742,9 @@ with HELP-ECHO string, MOUSE-FACE and FACE."
               (lambda (event) (interactive "e")
                 (save-selected-window
                   (select-window (posn-window (event-start event)))
-                   (gdb-set-window-buffer
-                    (dape--info-buffer mode id) t))))))
+                   (let ((buffer (dape--info-get-buffer-create mode id)))
+                     (with-current-buffer buffer (revert-buffer))
+                     (gdb-set-window-buffer buffer t)))))))
 
 (defun dape--info-set-header-line-format ()
   "Helper for dape info buffers to set header line.
@@ -2757,42 +2762,38 @@ Header line is custructed from buffer local
               " "))
          dape--info-buffer-related)))
 
-(defun dape--info-call-update-with (mode id fn)
-  (if dape--info-buffer-in-redraw
-      (run-with-timer 0.01 nil
-                      'dape--info-call-update-with mode id fn)
-    (when-let ((buffer (dape--info-get-live-buffer mode id)))
-      (let ((dape--info-buffer-in-redraw t))
-        (with-current-buffer buffer
-          (unless (derived-mode-p 'dape-info-parent-mode)
-            (error "Trying to update non info buffer"))
-          ;; Would be nice with replace-buffer-contents
-          ;; But it seams to messes up string properties
-          (let ((line (line-number-at-pos (point) t))
-                (old-window (selected-window)))
-            ;; Still don't know any better way of keeping window scroll?
-            (when-let ((window (get-buffer-window buffer)))
-              (select-window window))
-            (save-window-excursion
-              (let ((inhibit-read-only t))
-                (erase-buffer)
-                (funcall fn))
-              (ignore-errors
-                (goto-char (point-min))
-                (forward-line (1- line)))
-              (dape--info-set-header-line-format))
-            (when old-window
-              (select-window old-window))))))))
-
-(defmacro dape--info-update-with (mode id &rest body)
-  (declare (indent 2))
-  `(dape--info-call-update-with ,mode ,id (lambda () ,@body)))
-
-(defun dape--info-update (conn buffer)
-  "Update dape info BUFFER for adapter CONN."
-  (apply 'dape--info-buffer-update
-         conn (with-current-buffer buffer
-                (list major-mode dape--info-buffer-identifier))))
+(defun dape--info-call-update-with (fn &optional buffer)
+  "Helper for `dape--info-revert' functions.
+Erase buffer content and updates `header-line-format'.
+FN is expected to update insert buffer contents and
+update `dape--info-buffer-related'."
+  (setq buffer (or buffer (current-buffer)))
+  (with-current-buffer buffer
+    (unless (derived-mode-p 'dape-info-parent-mode)
+      (error "Trying to update non info buffer"))
+    ;; Would be nice with replace-buffer-contents
+    ;; But it seams to messes up string properties
+    (let ((line (line-number-at-pos (point) t))
+          (old-window (selected-window)))
+      ;; Still don't know any better way of keeping window scroll?
+      (when-let ((window (get-buffer-window buffer)))
+        (select-window window))
+      (save-window-excursion
+        (let ((inhibit-read-only t))
+          (erase-buffer)
+          (funcall fn))
+        (ignore-errors
+          (goto-char (point-min))
+          (forward-line (1- line)))
+        (dape--info-set-header-line-format))
+      (when old-window
+        (select-window old-window)))))
+
+(defmacro dape--info-update-with (&rest body)
+"Creates update function from BODY.
+See `dape--info-call-update-with'."
+  (declare (indent 0))
+  `(dape--info-call-update-with (lambda () ,@body)))
 
 (defun dape--info-get-live-buffer (mode &optional identifier)
   "Get live dape info buffer with MODE and IDENTIFIER."
@@ -2815,9 +2816,8 @@ Header line is custructed from buffer local
             ('dape-info-scope-mode (format "Scope <%s>" identifier))
             (_ (error "Unable to create mode from %s with %s" mode 
identifier)))))
 
-(defun dape--info-buffer (mode &optional identifier skip-update)
-  "Get or create info buffer with MODE and IDENTIFIER.
-If SKIP-UPDATE is non nil skip updating buffer contents."
+(defun dape--info-get-buffer-create (mode &optional identifier)
+  "Get or create info buffer with MODE and IDENTIFIER."
   (let ((buffer
          (or (dape--info-get-live-buffer mode identifier)
              (get-buffer-create (dape--info-buffer-name mode identifier)))))
@@ -2826,18 +2826,14 @@ If SKIP-UPDATE is non nil skip updating buffer 
contents."
         (funcall mode)
         (setq dape--info-buffer-identifier identifier)
         (push buffer dape--info-buffers)))
-    (unless skip-update
-      (dape--info-update (dape--live-connection 'newest t) buffer))
     buffer))
 
-(defun dape-info-update (&optional conn)
+(defun dape-info-update ()
   "Update and display `dape-info-*' buffers for adapter CONN."
   (dolist (buffer (dape--info-buffer-list))
     (when (get-buffer-window buffer)
-      (dape--info-update (or conn
-                             (dape--live-connection 'stopped t)
-                             (dape--live-connection 'newest t))
-                         buffer))))
+      (with-current-buffer buffer
+        (revert-buffer)))))
 
 (defun dape-info (&optional maybe-kill kill)
   "Update and display *dape-info* buffers.
@@ -2863,7 +2859,7 @@ When optional kill is non nil kill buffers *dape-info* 
buffers."
                           (dape--info-buffer-list))
           (setq buffer-displayed-p t)
           (dape--display-buffer
-           (dape--info-buffer 'dape-info-breakpoints-mode 'skip-update)))
+           (dape--info-get-buffer-create 'dape-info-breakpoints-mode)))
         ;; Open and update stack buffer
         (unless (seq-find (lambda (buffer)
                             (and (get-buffer-window buffer)
@@ -2874,7 +2870,7 @@ When optional kill is non nil kill buffers *dape-info* 
buffers."
                           (dape--info-buffer-list))
           (setq buffer-displayed-p t)
           (dape--display-buffer
-           (dape--info-buffer 'dape-info-stack-mode 'skip-update)))
+           (dape--info-get-buffer-create 'dape-info-stack-mode)))
         ;; Open stack 0 if not group-2 buffer displayed
         (unless (seq-find (lambda (buffer)
                             (and (get-buffer-window buffer)
@@ -2884,7 +2880,7 @@ When optional kill is non nil kill buffers *dape-info* 
buffers."
                           (dape--info-buffer-list))
           (setq buffer-displayed-p t)
           (dape--display-buffer
-           (dape--info-buffer 'dape-info-scope-mode 0 'skip-update)))
+           (dape--info-get-buffer-create 'dape-info-scope-mode 0)))
         (dape-info-update)
         (when (and maybe-kill (not buffer-displayed-p))
           (kill-dape-info))))))
@@ -2906,7 +2902,7 @@ When optional kill is non nil kill buffers *dape-info* 
buffers."
 (dape--command-at-line dape-info-breakpoint-delete (dape--info-breakpoint)
   "Delete breakpoint at line in dape info buffer."
   (dape--breakpoint-remove dape--info-breakpoint)
-  (dape--display-buffer (dape--info-buffer 'dape-info-breakpoints-mode)))
+  (dape--display-buffer (dape--info-get-buffer-create 
'dape-info-breakpoints-mode)))
 
 (dape--command-at-line dape-info-breakpoint-log-edit (dape--info-breakpoint)
   "Edit breakpoint at line in dape info buffer."
@@ -2943,9 +2939,10 @@ When optional kill is non nil kill buffers *dape-info* 
buffers."
   "Major mode for Dape info breakpoints."
   (setq dape--info-buffer-related dape--info-group-1-related))
 
-(cl-defmethod dape--info-buffer-update (_conn (mode (eql 
dape-info-breakpoints-mode)) id)
-  "Update buffer specified by MODE and ID."
-  (dape--info-update-with mode id
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-breakpoints-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-breakpoints-mode'."
+  (dape--info-update-with
     (let ((table (make-gdb-table)))
       (gdb-table-add-row table '("Type" "On" "Where" "What"))
       (dolist (breakpoint (reverse dape--breakpoints))
@@ -3050,14 +3047,16 @@ See `dape--callback' for expected CB signature."
         dape--info-buffer-related dape--info-group-1-related)
   (add-to-list 'overlay-arrow-variable-list 'dape--info-thread-position))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql 
dape-info-threads-mode)) id)
-  "Fetches data for `dape-info-threads-mode' and updates buffer.
-Buffer is specified by MODE and ID."
-  (if-let ((conn (or conn (dape--live-connection 'newest t)))
+
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-threads-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-threads-mode'."
+  (if-let ((conn (or (dape--live-connection 'stopped t)
+                     (dape--live-connection 'newest t)))
            ((dape--stopped-threads conn))
            (threads (dape--threads conn)))
       (dape--with dape--info-threads-all-stack-trace (conn)
-        (dape--info-update-with mode id
+        (dape--info-update-with
           (let ((table (make-gdb-table))
                 (current-thread (dape--current-thread conn)))
             (set-marker dape--info-thread-position nil)
@@ -3101,7 +3100,7 @@ Buffer is specified by MODE and ID."
                        for line from 1
                        until (eq current-thread thread)
                        finally (gdb-mark-line line 
dape--info-thread-position))))))
-    (dape--info-update-with mode id
+    (dape--info-update-with
       (set-marker dape--info-thread-position nil)
       (insert "No thread information available."))))
 
@@ -3169,16 +3168,18 @@ current buffer."
            until (eq current-stack-frame stack-frame)
            finally (gdb-mark-line line dape--info-stack-position)))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql dape-info-stack-mode)) 
id)
-  "Fetches data for `dape-info-stack-mode' and updates buffer.
-Buffer is specified by MODE and ID."
-  (let* ((current-thread (dape--current-thread conn))
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-stack-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-stack-mode'."
+  (let* ((conn (or (dape--live-connection 'stopped t)
+                   (dape--live-connection 'newest t)))
+         (current-thread (dape--current-thread conn))
          (stack-frames (plist-get current-thread :stackFrames))
          (current-stack-frame (dape--current-stack-frame conn)))
     (cond
      ((or (not current-stack-frame)
           (not (dape--stopped-threads conn)))
-      (dape--info-update-with mode id
+      (dape--info-update-with
         (set-marker dape--info-stack-position nil)
         (insert "No stopped threads.")))
      (t
@@ -3187,7 +3188,7 @@ Buffer is specified by MODE and ID."
       ;; at an 'update event, then we fetch the rest here.
 
       ;; Start off with shoving available stack info into buffer
-      (dape--info-update-with mode id
+      (dape--info-update-with
         (dape--info-stack-buffer-insert current-stack-frame stack-frames))
       (dape--with dape--stack-trace (conn
                                      current-thread
@@ -3195,7 +3196,7 @@ Buffer is specified by MODE and ID."
         ;; If stack trace lookup with `dape-stack-trace-levels' frames changed
         ;; the stack frame list, we need to update the buffer again
         (unless (eq stack-frames (plist-get current-thread :stackFrames))
-          (dape--info-update-with mode id
+          (dape--info-update-with
             (dape--info-stack-buffer-insert current-stack-frame
                                             (plist-get current-thread 
:stackFrames)))))))))
 
@@ -3222,10 +3223,14 @@ Buffer is specified by MODE and ID."
                                     (dape-info-modules-mode nil "Modules")
                                     (dape-info-sources-mode nil "Sources"))))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql 
dape-info-modules-mode)) id)
-  (dape--info-update-with mode id
-    ;; Use last connection if current is dead
-    (when-let ((conn (or conn dape--connection)))
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-modules-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-modules-mode'."
+  (dape--info-update-with
+      ;; Use last connection if current is dead
+      (when-let ((conn (or (dape--live-connection 'stopped t)
+                           (dape--live-connection 'newest t)
+                           dape--connection)))
       (cl-loop with modules = (dape--modules conn)
                with table = (make-gdb-table)
                for module in (reverse modules)
@@ -3271,26 +3276,25 @@ Buffer is specified by MODE and ID."
                                     (dape-info-modules-mode nil "Modules")
                                     (dape-info-sources-mode nil "Sources"))))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql 
dape-info-sources-mode)) id)
-  (dape--info-update-with mode id
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-sources-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-sources-mode'."
+  (dape--info-update-with
     ;; Use last connection if current is dead
-    (when-let ((conn (or conn dape--connection)))
-      (cl-loop with sources = (dape--sources conn)
-               with table = (make-gdb-table)
-               for source in (reverse sources)
-               do
-               (gdb-table-add-row
-                table
-                (list
-                 (concat
-                  (plist-get source :name)
-                  " "))
-                (list
-                 'dape--info-source source
-                 'mouse-face 'highlight
-                 'keymap dape-info-sources-line-map
-                 'help-echo "mouse-2, RET: goto source"))
-               finally (insert (gdb-table-string table " "))))))
+      (when-let ((conn (or (dape--live-connection 'stopped t)
+                           (dape--live-connection 'newest t)
+                           dape--connection)))
+        (cl-loop with sources = (dape--sources conn)
+                 with table = (make-gdb-table)
+                 for source in (reverse sources)
+                 do (gdb-table-add-row table
+                                       (list (concat (plist-get source :name) 
" "))
+                                       (list
+                                        'dape--info-source source
+                                        'mouse-face 'highlight
+                                        'keymap dape-info-sources-line-map
+                                        'help-echo "mouse-2, RET: goto 
source"))
+                 finally (insert (gdb-table-string table " "))))))
 
 
 ;;; Info scope buffer
@@ -3304,7 +3308,7 @@ Buffer is specified by MODE and ID."
     (user-error "No stopped threads"))
   (puthash dape--info-path (not (gethash dape--info-path 
dape--info-expanded-p))
            dape--info-expanded-p)
-  (dape--info-buffer major-mode dape--info-buffer-identifier))
+  (revert-buffer))
 
 (dape--buffer-map dape-info-variable-prefix-map dape-info-scope-toggle)
 
@@ -3315,7 +3319,8 @@ Buffer is specified by MODE and ID."
                    (eq major-mode 'dape-info-watch-mode)
                    (eq major-mode 'dape-info-scope-mode))
   (when (derived-mode-p 'dape-info-parent-mode)
-    (gdb-set-window-buffer (dape--info-buffer 'dape-info-watch-mode) t)))
+    (gdb-set-window-buffer
+     (dape--info-get-buffer-create 'dape-info-watch-mode) t)))
 
 (dape--buffer-map dape-info-variable-name-map dape-info-scope-watch-dwim)
 
@@ -3446,17 +3451,19 @@ plist are used as keymap for each sections defined by 
the key."
   (setq dape--info-buffer-related '((dape-info-watch-mode nil "Watch")))
   (dape--info-set-header-line-format))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql dape-info-scope-mode)) 
id)
-  "Fetches data for `dape-info-scope-mode' and updates buffer.
-Buffer is specified by MODE and ID."
-  (when-let* ((conn (or conn (dape--live-connection 'stopped t)))
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-scope-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-scope-mode'."
+  (when-let* ((conn (or (dape--live-connection 'stopped t)
+                        (dape--live-connection 'newest t)
+                        dape--connection))
               (frame (dape--current-stack-frame conn))
               (scopes (plist-get frame :scopes))
               ;; FIXME if scope is out of range here scope list could
               ;;       have shrunk since last update and current
               ;;       scope buffer should be killed and replaced if
               ;;       if visible
-              (scope (nth id scopes))
+              (scope (nth dape--info-buffer-identifier scopes))
               ;; Check for stopped threads to reduce flickering
               ((dape--stopped-threads conn)))
     (dape--with dape--variables (conn scope)
@@ -3469,7 +3476,7 @@ Buffer is specified by MODE and ID."
                   (gethash (cons (plist-get object :name) path)
                            dape--info-expanded-p))))
         (when (and scope scopes (dape--stopped-threads conn))
-          (dape--info-update-with mode id
+          (dape--info-update-with
             (rename-buffer (format "*dape-info %s*" (plist-get scope :name)) t)
             (setq dape--info-buffer-related
                   (dape--info-group-2-related-buffers scopes))
@@ -3498,20 +3505,23 @@ Buffer is specified by MODE and ID."
   :interactive nil
   (setq dape--info-buffer-related '((dape-info-watch-mode nil "Watch"))))
 
-(cl-defmethod dape--info-buffer-update (conn (mode (eql dape-info-watch-mode)) 
id)
-  "Fetches data for `dape-info-watch-mode' and updates buffer.
-Buffer is specified by MODE and ID."
-  (let* ((frame (dape--current-stack-frame conn))
+(cl-defmethod dape--info-revert (&context (major-mode (eql 
dape-info-watch-mode))
+                                          &optional _ignore-auto _noconfirm 
_preserve-modes)
+  "Revert buffer function for `dape-info-watch-mode'."
+  (let* ((conn (or (dape--live-connection 'stopped t)
+                   (dape--live-connection 'newest t)
+                   dape--connection))
+         (frame (dape--current-stack-frame conn))
          (scopes (plist-get frame :scopes))
          (responses 0))
     (cond
      ((not dape--watched)
-      (dape--info-update-with mode id
+      (dape--info-update-with
         (setq dape--info-buffer-related
               (dape--info-group-2-related-buffers scopes))
         (insert "No watched variable.")))
      ((not (and conn (jsonrpc-running-p conn)))
-      (dape--info-update-with mode id
+      (dape--info-update-with
         (cl-loop with table = (make-gdb-table)
                  for watch in dape--watched
                  initially (setf (gdb-table-right-align table)
@@ -3544,7 +3554,7 @@ Buffer is specified by MODE and ID."
                    (and (not (eq (plist-get object :expensive) t))
                         (gethash (cons (plist-get object :name) path)
                                  dape--info-expanded-p))))
-              (dape--info-update-with mode id
+              (dape--info-update-with
                 (when scopes
                   (setq dape--info-buffer-related
                         (dape--info-group-2-related-buffers scopes)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]