From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: David Karr Newsgroups: gmane.emacs.help Subject: Advice on custom packages that conflict with tramp Date: Tue, 7 Mar 2023 13:30:55 -0800 Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="28606"; mail-complaints-to="usenet@ciao.gmane.io" To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Tue Mar 07 22:32:48 2023 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pZevQ-0007HK-DW for geh-help-gnu-emacs@m.gmane-mx.org; Tue, 07 Mar 2023 22:32:48 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pZett-0001Dc-GF; Tue, 07 Mar 2023 16:31:13 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pZetr-0000ym-Nq for help-gnu-emacs@gnu.org; Tue, 07 Mar 2023 16:31:11 -0500 Original-Received: from mail-vs1-xe2c.google.com ([2607:f8b0:4864:20::e2c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pZeto-0001MB-Dv for help-gnu-emacs@gnu.org; Tue, 07 Mar 2023 16:31:11 -0500 Original-Received: by mail-vs1-xe2c.google.com with SMTP id a3so13678598vsi.0 for ; Tue, 07 Mar 2023 13:31:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678224667; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=UHIUO2Rb0Ze6ZhR5RSJCdMWaL1YHjC3+H0VM+b68aL8=; b=BOWYcjZIip/xmOPm//iFwEWL1Z6R6MuiUqu3nikdFTD7sk00niu6k7pXcV0Mj7qTJl vzumZRTolMIOgtmrFt/vCzdESl1vWyAn5h3GByzBajlVmAnQraOHjG/v7UOzp/cTbCtI O/0QTViGrSGLXyFAmfzoFQ1ifAtwFMN8YtMvUG4NPhNuAi2Gc65B7GEsPWBvdxtsME2I MfHc9YsHTUpSQCrhc9kYcOkYnlJjMErk2PLiHyq2fSV8D3iojH+YhQOEbAo3jiLoMm3C iRV0H3iEda4ubOBKEXu+r8CRmdAtmBNTMh7FJm8zPTWhgKqOvjJ/AZRp+7A0AuR0WTB5 dOEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678224667; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=UHIUO2Rb0Ze6ZhR5RSJCdMWaL1YHjC3+H0VM+b68aL8=; b=FanJDCvrhuCY9ja87geP0psik2oEIJdSmymnSQbE3oisCr7bvTXRPNF6ncnyW1VTxB BdAdz9Ljvv9iWmtN5sMXYoejHfflWwRWUmFGX9h/5+MAOXy9mGbBXgw59JB+He2++D0c EujVZ3rY1WSpfPI7c6+zaUQlRWaZ2Diqtz4qnzJdv2ihK4AWJK0Ws2nI5Fr7YS5DSNdX Pg9vSz2qgazQFNd/HyZi0ATbJ3vgTSnSEEIPfgKWOfwOUMAFtLC2JlvRIK6zJHLBJ/YQ VUw2Pn8Z9vj1guWNHd7514UP3qbwQxRdonSbpSN9iR7WwdYox+Fr6XXYC0FKUsDU/wla EiTQ== X-Gm-Message-State: AO0yUKUEBl/Qk8yhpBRKFyESTqPKH8NJHdaeQoM+EdMZUg5so2zUr62b xuy7XvKHGQOn3CsLzHi4hNARpkayVz6JYWkfArUNlRdmzFI= X-Google-Smtp-Source: AK7set81gEoEhPAnlFCCdcTWuxQcTh4T8FDdJYfzl52UkNHmmoS1AHnNyAj20SwGT4FwuDHqOSEc4C1Z6sd7UNumWnU= X-Received: by 2002:a67:edcb:0:b0:402:9b84:1be0 with SMTP id e11-20020a67edcb000000b004029b841be0mr10575652vsp.2.1678224666459; Tue, 07 Mar 2023 13:31:06 -0800 (PST) Received-SPF: pass client-ip=2607:f8b0:4864:20::e2c; envelope-from=davidmichaelkarr@gmail.com; helo=mail-vs1-xe2c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.help:142938 Archived-At: I've been using Emacs for a very long time, although I don't consider myself a sophisticated user. I mostly use it for shell buffers and viewing files, and occasionally editing. Just about 25 years ago, I wrote two very small packages that I use to manage a ring of shell buffers, which provides the following primary features: * When I'm in a shell buffer, executing the "main function" wilI create a new shell that goes to the end of the ring * When I'm not in a shell buffer, executing that function just goes to the first shell buffer in the ring * When I'm in a shell buffer, I can press one key sequence to go to the next (or previous) buffer in the ring, going to the next buffer from the last buffer in the ring goes to the first one * When I'm in a shell buffer, I can execute one function that lets me enter a search string representing a directory, and it will put me in the first shell buffer whose current directory contains that substring The resulting shell buffer names are just "shell", "shell-1", "shell-2", et cetera. As I said, I'm not really a sophisticated elisper. I think it's likely that what I wrote violates any number of conventions and rules, but for what I mainly use it for, it works fine. However, I'm now trying to see if the Tramp package can make some of the ssh things I have to do a little easier. I've been talking to the Tramp team, and it appears that something I'm doing in my shell package is conflicting with Tramp. If I start Emacs and immediately use Tramp, it works fine. If I first create a shell buffer and then try to use Tramp, the connection times out. One of the Tramp team members took a brief look at my packages and said that he did see at least one oddity in how I'm creating the shell buffers, being that it creates the shell buffer (so I can control the name) and then calls "shell" for that buffer. I'm not sure how to fix that so my shell package still works and Tramp also works. If I had to lose the control over the buffer name, I could live with that, but the basic features that I listed up above have to work. I'm going to include here the two packages that implement this. I'd appreciate any constructive advice on refactoring this so the original functionality still works, and Tramp also works. ----cycle-shell.el----------- ;;; ;;; cycle-shell.el --- Package to allow creation and cycling between multiple ;;; "shell" buffers. This requires the "buffer-cycle" ;;; package and the "shell-for-cycle" package (which is just ;;; a barely modified version of shell.el from the v19 ;;; distribution). ;;; ;; Author: David M. Karr ;; Keywords: buffers shell ;;; This package allows the user to create multiple shell buffers and quickly ;;; move between them. (require 'buffer-cycle) (defvar last-shell-buffer nil "BUFFER object, last shell buffer") (defun cycle-make-shell () "Implements a ring of *shell* buffers. If current buffer is not a shell buffer, then it will just execute 'shell'. If it IS a shell buffer, then create a new shell buffer, starting with '*shell-1*', but skipping to the next number if that already exists." (interactive) (let* ((bufname (buffer-name (current-buffer)))) (if (string-match "\*shell\\(\*\\|-\\([0-9][0-9]*\\)\*\\)" bufname) (progn (setq change-dir default-directory) (setq done nil) (while (not done) (progn (setq new-bufname (next-bufname bufname "shell")) (if (bufferp (get-buffer new-bufname)) (setq bufname new-bufname) (setq done t) ) ) ) (if (bufferp (get-buffer "*shell*")) (progn (set-buffer "*shell*") (rename-uniquely) (setq tmp-bufname (buffer-name)) )) (shell) (sit-for 1) (set-buffer "*shell*") (rename-buffer new-bufname) ;; Now we need to somehow change the directory to "change-dir". (set-buffer tmp-bufname) (rename-buffer "*shell*") (set-buffer new-bufname) ) (progn ;; check for existence of buffer last-shell-buffer. If it exists, ;; go to it. If not, then execute "shell". (if (and (bufferp last-shell-buffer) (not (killed-buffer-p last-shell-buffer))) (switch-to-buffer last-shell-buffer) (shell)) ) ) ) ) (defun cycle-go-shell (&optional arg) "If in a shell buffer, go to the next shell buffer in the ring." (interactive "P") (if arg (if (numberp arg) (cycle-go-buffer "shell" arg) (cycle-prev-buffer "shell")) (cycle-next-buffer "shell")) (if (not (eq major-mode 'shell-mode)) (shell)) (setq last-shell-buffer (current-buffer)) ) (defun cycle-find-shell (&optional string) (interactive "sEnter directory substring: ") (let* ((buflist (buffer-list)) (next-buffer nil) (chosen-buffer nil) ) (while (setq next-buffer (car buflist)) (setq buflist (cdr buflist)) (setq bufname (buffer-name next-buffer)) (setq substring "*shell") (if (string-equal (substring bufname 0 (min (length substring) (length bufname))) substring) (progn (set-buffer next-buffer) (if (string-match string default-directory) (setq chosen-buffer next-buffer) ) ) ) ) (if chosen-buffer (progn (switch-to-buffer chosen-buffer) (setq last-shell-buffer chosen-buffer) ) (error (concat "PWD with \"" string "\" not found.")) ) ) ) (defun killed-buffer-p (buffer) "Return t if BUFFER is killed." (not (buffer-name buffer))) (defun shells-buffer-list () (interactive) (electric-buffer-list "^\*shell") ) (defun cycle-find-shell-or-shells-buffer-list (&optional arg) (interactive "P") (if arg (shells-buffer-list) (call-interactively 'cycle-find-shell) ) ) ----cycle-shell.el----------- -----buffer-cycle.el----------- ;;; ;;; buffer-cycle.el --- defuns to cycle between several buffers of the same ;;; type. ;;; ;; Author: David M. Karr ;; Keywords: buffers ;;; This package defines a small number of utility defuns to be used by other ;;; packages to provide the facility of cycling quickly between several buffers ;;; of the same type. It assumes the first buffer of the type will be named ;;; "*something*", and following ones will be named "*something-1*", etc. ;;; ;;; The defun "next-bufname" takes a BUFNAME and a CORESTRING and returns what ;;; would be the next buffer name in the cycle. ;;; ;;; The defun "cycle-next-buffer" takes a CORESTRING. It looks at the current ;;; buffer and gets the result of "next-bufname" given the current buffer and ;;; the CORESTRING. If that buffer exists, then it tries to switch to that ;;; new buffer. If buffers in the middle of the ring are deleted, then the ;;; buffers at the end are unreachable by this method. It could be made more ;;; robust by storing the buffer names in a list and tracking buffer deletes, ;;; etc., but this is probably good enough. (provide 'buffer-cycle) (defun next-bufname (bufname corestring) "Given a particular BUFNAME and a CORESTRING (like \"*CORESTRING*\"), return the next buffer in line." (if (string-equal (concat "*" corestring "*") bufname) (concat "*" corestring "-1*") (progn (string-match (concat "\*" corestring "\\(\*\\|-\\([0-9][0-9]*\\)\*\\)") bufname) (concat "*" corestring "-" (int-to-string (+ (string-to-number (substring bufname (match-beginning 2) (match-end 2))) 1)) "*") ) ) ) (defun prev-bufname (bufname corestring) "Given a particular BUFNAME and a CORESTRING (like \"*CORESTRING*\"), return the previous buffer in line." (string-match (concat "\*" corestring "\\(\*\\|-\\([0-9][0-9]*\\)\*\\)") bufname) (setq new-bufname (concat "*" corestring "-" (int-to-string (- (string-to-number (substring bufname (match-beginning 2) (match-end 2))) 1)) "*")) (if (string= new-bufname (concat "\*" corestring "-0\*")) (concat "\*" corestring "\*") new-bufname) ) (defun cycle-next-buffer (corestring) (let* ((bufname (buffer-name (current-buffer)))) (if (string-match (concat "\*" corestring "\\(\*\\|-\\([0-9][0-9]*\\)\*\\)") bufname) (progn (setq new-bufname (next-bufname bufname corestring)) (if (bufferp (get-buffer new-bufname)) (switch-to-buffer new-bufname) (switch-to-buffer (concat "*" corestring "*")) ) ) (switch-to-buffer (concat "*" corestring "*")) ) ) ) (defun cycle-prev-buffer (corestring) (let* ((bufname (buffer-name (current-buffer)))) (if (string-match (concat "\*" corestring "\\(\*\\|-\\([0-9][0-9]*\\)\*\\)") bufname) (progn (if (string= (concat "\*" corestring "\*") bufname) (let ((last-bufname bufname)) (while (bufferp (get-buffer (setq new-bufname (next-bufname last-bufname corestring)))) (setq last-bufname new-bufname) ) (switch-to-buffer last-bufname) ) (let ((new-bufname (prev-bufname bufname corestring))) (if (bufferp (get-buffer new-bufname)) (switch-to-buffer new-bufname) (switch-to-buffer (concat "*" corestring "*")) ) ) ) ) (switch-to-buffer (concat "*" corestring "*")) ) ) ) (defun cycle-go-buffer (corestring bufnum) (setq new-bufname (concat "\*" corestring (if (not (eq bufnum 0)) (concat "-" (number-to-string bufnum))) "\*")) (if (bufferp (get-buffer new-bufname)) (switch-to-buffer new-bufname) (error (concat "No " corestring " buffer in " new-bufname "."))) ) -----buffer-cycle.el-----------