Firszt - Selectrum 3.1 is _amazing_; prior versions were wonderful, but this latest update a few days ago really improved many things, but notably performance; M-x was taking a couple seconds to open before, now nearly instantly (and thats with the extra help annotations added by other packages.)
Problem - Just doing open file (C-x C-f) and entering /ssh: (goal is to put in somethign like /ssh:foo@hostname... for Tramp obviously), and as soon as the : is listed Emacs essentially hangs for quiter awhile; C-g to break out sometimes works, and I end up spamming it for awhile.
Enabling tramp verbose logging suggests that selectrum is returning a pile of stuff there (?), and Tramp or selecturm is trying to open everything; like, it seems Tramp is being tried against all IPs I've opened redcently (perhaps Selectrum or Tramp is reviewing recentf's cache? or bookmarks? not sure where its getting the list, its quite a pile of IPs its finding, but they're all valid ones I've used recently.)
Not sure if this is a Tramp or Selectrum issue, as both have had updates recently.
Thank, I also just also discovered that Tramp is slow again, too. It doesn't seem to happen with 3.1 release candidate or does it? Are you on current master?
Should be fixed by 46f79d17f0f5fe6d66f1880c09efa1da1c4803e4?
@minad We should work out something else but to I just reverted for now as I'm short on time.
Ah I see. It seems the optimization is useful because the following cl-position call uses selectrum--get-full which is too slow. Does it make sense to use selectrum--get-full? Is this really necessary? Is it possible to optimize this function? The problem I see here is that the shortcut works nicely, but we could get a slowdown again if move-default=nil. Maybe a better fix would check first if the default candidate is non-nil and only search via cl-position in that case? Secondly I think selectrum--get-full must be optimized to ensure that slowdown never happens!
So in other words - your fix is incomplete and the slowdown issue will bite us again in other scenarios since the fix does not to resolve the root cause.
I also think that selectrum--get-full should get optimized. Another thing I noticed is that for file completions we should generally only check for the default when the prompt equals the initial prompt.
Just realized that getting the position like we currently do for file completions is broken anyway, I will fix that later. Regarding the shortcut I think we can leave it there as this is how the UI should work currently, if we change that we can look at it again.
Does it make sense to change the short cut like this?
~
(or (not selectrum--default-candidate) selectrum-move-default-candidate)
~
Also should the selection of the default only happen when selectrum--is-initializing is non-nil?
I don't know. You tell me!
I would appreciate if you add a comment after you decided on how the logic should be.
I think it makes more sense because the selection is only a help to be able to press RET at the initial prompt. Trying to keep it selected after you provide input doesn't feel right to me.
Yes, but if the case does not match it will fall through to the default with the cl-position and you may end up with 0 again? Please carefully check each case and add comments why the cases to compute the index are how they are.
See 12c241a84898b7d3b5b3e260672d43475f00d221
For explaining comments see a17f3c9f4ed14c3d2e3b5ef300a14a39f49f14b1. @skeezix I hope your issue is fixed?
@minad On another note I noticed there are slowdown issues when using marginalia with tramp even though no annotations are shown (using marginalia-annotators-heavy).
Yes, that could happen when the file annotator accesses the slow tramp fs. The file annotator should maybe filter tramp. Or did you also observe it for other annotators?
Only for file completion, skipping for tramp might be good, the annotations also aren't shown is that a Selectrum issue or are they also not shown with default completion?
I don't know. Just try it :smile:
Right, I shouldn't be so lazy :laughing: I just tested and they aren't shown there, too.
I cannot confirm this. For me the file annotator works with tramp. And it does not feel particularly slow.
Oh, okay I will try with emacs -Q.
Hm, still slow for me, I notice it mostly when scrolling (keeping "C-n" pressed) it starts to stutter in this case for me.
Yes, it is not super fast, but that is expected. But even buffer switching and other things become slower. Over a slow connection Emacs with tramp is utterly unusable. I never use tramp with slow connections. It works well in a local network, but that's about it. I somehow think tramp is a misguided idea :shrug:
The stuttering case I described was with sudo, I don't use the heavy annotations so I'm not affected usually.
Okay, it is probably simply slow due to the overhead of tramp+sudo. We could filter it, but that's about all we can do. If someone interested creates a PR I would merge it.
Okay, I wasn't sure what the state with tramp and marginalia is, I searched the issue list and did not found anything, hence I asked you here. I guess if no one complaints it is fine :+1:
Regarding https://github.com/raxod502/selectrum/commit/a17f3c9f4ed14c3d2e3b5ef300a14a39f49f14b1 I'll try it tonight after chores are done, thanks!
I haven't looked over the selectrum code nor do I understand the completion mechanism, but I am curious as to what was causing the slo down; from the Emacs messages and tramp log, it sure looked like it was actually trying to Tramp _open_ all the IPs I'd recently visited; so questions are.. i) how does Selectrum figure out what IPs to be listing there? (thats such a neat idea, btw, hadn't conceived of that as something Selectrum could do at all :) .. and 2) why was Tramp seemingly trying to actually connect to/open all of them?
I live in Tramp mode (company internal network, from home vpn'd to the network of course due to covid), and Selectrum is one of my favorite things (esp with heavby marginalia, oh baby!) .. but just having Selectrum matching the text against recentf and bookmarks (say) would be a treat.
ie: The fact Emacs was hanging at the : part .. /ssh:,m hanging and generating lists of IPs for the selection list and trying to connect to them, blew my mind; I expect a slow down _once connected_, like trying to get the directory listing etc. (And recent Selectrum 3.1 made that _enormously_ faster, it was unusable with Selectrum previously, and yet now Selectrum + Tramp is fantastic); but this was not even at the point it shoudl be lookign for dir list or connecting, this is just trying to put in the username and hostname part of the file name, wherein Tramp shoudl reach out.
Anyway, if you guys have fixed it, thats super awesome, and I'll try it out soon.
The fact you guys pounced on this is remarkable! If theres a tip jar somewhere, let me know :)
Thanks, it is nice to hear that you like it! Regarding your question: In file completions when you insert a candidate with TAB or select it with RET we use substitute-in-file-name and completion--sifn-requote (see selectrum--get-full) to get the candidate path which is composed of some part of the minibuffer contents and the selected candidate. The problem was that this path computation was accidentally done on each completion candidate (see here). In your case the path computation on each candidate might have caused tramp to open connections for each of them (I'm actually not sure but I hope this was the case otherwise you might have hit another bug we aren't aware of, yet).
OKay, in a spare moment I just curl pulled selectrum.el over top of my current one (I'm using melpa 3.1, and like to stay on melpa for the easy upgrades); restarted Emacs to be safe, and still the problem.
C-x C-f /ssh:
^ as soon as the : is hit, Emacs is 'hung'
If I hit C-g a few times Selectrum will list:
ssh:foo@bar
ssh:10.1.2.3
ssh:10.1.2.4
...etc (various valid looking targets I've been to)
.. but contionues being 'hung'
Hit C-g spam a few more times to get right out and its okay back to buffer to work.
I effectively can't C-x C-f and put in /ssh: anymore, to even get to the part of entering /ssh:foo@somewhere .. soon as the colon is entered, it goes into Tramp-hell.
So this is at : time; is that Tramp grabbing that event and going off to check if ssh is present or something? is it Selectrum waking up? the two fighting?
But at a random guess, is /ssh: waking up Tramp or Selectrum, and Selectrum producing a list of IPs or something from
As a workaround, I've been adding servers to bookmarks (manually editing the bookmarks file) and then I can use bookmarks to get dired on a server, open a file, and then good to go.. opening another file, from that first file, Selectrum and Tramp cooperate on the dir listing nice and fast
But that /ssh: bit is brutal :)
(yes, I removed selectrum.elc when I pulled in the selectrum.el .. which I tried both the master current, and the one specifically mentioned above ...3c9) .. still hang at /ssh:
Mac OS Catalina fwiw .. I shall have to clone my .emacs/.emacs.d onto another box and see as well, if thats helpfull
What kind of debugging aid can I offer?
What Tramp/Emacs version are you using? And can you also post your full minibuffer completion setup and Tramp setup? For debugging you could eval the selectrum.el buffer and do M-x toggle-debug-on-quit, then trigger the bug and hit C-g which should give you backtrace.
Emacs 27.1
Tramp is latest melpa
emacs -Q -> no problem, no expansion occurs until finishing; so its Selectrum waking up at ":"?
(any way to disable Selectrum from doing this, until we get it fixed?)
Huge backtrace :O This is typing C-x C-f /ssh:
I was in ~/ at the time
read-from-minibuffer("Find file: " "~/" (keymap (9 . selectrum-insert-current-candidate) (10 . selectrum-submit-exact-input) (C-M-backspace . backward-kill-sexp) (27 keymap (113 . selectrum-cycle-display-style) (67108991 . backward-kill-sexp)) (remap keymap (previous-matching-history-element . selectrum-select-from-history) (kill-ring-save . selectrum-kill-ring-save) (end-of-buffer . selectrum-goto-end) (beginning-of-buffer . selectrum-goto-beginning) (minibuffer-beginning-of-buffer . selectrum-goto-beginning) (scroll-up-command . selectrum-next-page) (scroll-down-command . selectrum-previous-page) (exit-minibuffer . selectrum-select-current-candidate) (next-line-or-history-element . selectrum-next-candidate) (previous-line-or-history-element . selectrum-previous-candidate) (next-line . selectrum-next-candidate) (previous-line . selectrum-previous-candidate) (minibuffer-keyboard-quit . abort-recursive-edit) (keyboard-quit . abort-recursive-edit)) keymap (remap keymap (previous-matching-history-element . selectrum-select-from-history)) (18 . helm-minibuffer-history) (menu-bar keymap (minibuf "Minibuf" keymap (previous menu-item "Previous History Item" previous-history-element :help "Put previous minibuffer history element in the min...") (next menu-item "Next History Item" next-history-element :help "Put next minibuffer history element in the minibuf...") (isearch-backward menu-item "Isearch History Backward" isearch-backward :help "Incrementally search minibuffer history backward") (isearch-forward menu-item "Isearch History Forward" isearch-forward :help "Incrementally search minibuffer history forward") (return menu-item "Enter" exit-minibuffer :key-sequence "\15" :help "Terminate input and exit minibuffer") (quit menu-item "Quit" abort-recursive-edit :help "Abort input and exit minibuffer") "Minibuf")) (10 . exit-minibuffer) (13 . exit-minibuffer) (7 . abort-recursive-edit) (C-tab . file-cache-minibuffer-complete) (9 . self-insert-command) (XF86Back . previous-history-element) (up . previous-line-or-history-element) (prior . previous-history-element) (XF86Forward . next-history-element) (down . next-line-or-history-element) (next . next-history-element) (27 keymap (60 . minibuffer-beginning-of-buffer) (114 . previous-matching-history-element) (115 . next-matching-history-element) (112 . previous-history-element) (110 . next-history-element))) nil file-name-history "~/")
(progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history 'minibuffer-history) default-candidate))
(unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history 'minibuffer-history) default-candidate)) (remove-hook 'minibuffer-setup-hook hook))
(let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil (set ... ...) (set ... require-match) (if no-move-default-candidate ...) (selectrum--setup candidates ... buf))))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history 'minibuffer-history) default-candidate)) (remove-hook 'minibuffer-setup-hook hook)))
(progn (add-hook 'minibuffer-setup-hook hook) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil ... ... ... ...)))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history 'minibuffer-history) default-candidate)) (remove-hook 'minibuffer-setup-hook hook))))
(unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'...))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history 'minibuffer-history) default-candidate)) (remove-hook 'minibuffer-setup-hook hook)))) (remove-hook 'minibuffer-setup-hook hook))
(let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil (set ... t))))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook ... hook) (funcall ...))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (read-from-minibuffer prompt initial-input selectrum-minibuffer-map nil (or history ...) default-candidate)) (remove-hook 'minibuffer-setup-hook hook)))) (remove-hook 'minibuffer-setup-hook hook)))
(let* ((minibuffer-allow-text-properties t) (resize-mini-windows 'grow-only) (prompt (selectrum--remove-default-from-prompt prompt)) (icomplete-mode nil) (buf (current-buffer)) (res (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook ... hook) (funcall ...))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (let (...) (fset hook ...) (unwind-protect ... ...))) (remove-hook 'minibuffer-setup-hook hook))))) (cond (minibuffer-completion-table (let ((exit-string (default-value 'selectrum--last-input)) (default (default-value 'selectrum--default-candidate))) (if (and exit-string (string-empty-p exit-string) (equal res default)) default-candidate (substring-no-properties res)))) (t res)))
(progn (if (or may-modify-candidates (functionp candidates)) nil (setq candidates (copy-sequence candidates))) (let* ((minibuffer-allow-text-properties t) (resize-mini-windows 'grow-only) (prompt (selectrum--remove-default-from-prompt prompt)) (icomplete-mode nil) (buf (current-buffer)) (res (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil ... ...)) (unwind-protect (progn (add-hook ... hook) (let ... ... ...)) (remove-hook 'minibuffer-setup-hook hook))))) (cond (minibuffer-completion-table (let ((exit-string (default-value ...)) (default (default-value ...))) (if (and exit-string (string-empty-p exit-string) (equal res default)) default-candidate (substring-no-properties res)))) (t res))))
(progn (let ((--cl-keys-- args)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:default-candidate :initial-input :require-match :history :no-move-default-candidate :may-modify-candidates :minibuffer-completion-table :minibuffer-completion-predicate :allow-other-keys)) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ... args))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:default-candidate..." (car --cl-keys--)))))) (progn (if (or may-modify-candidates (functionp candidates)) nil (setq candidates (copy-sequence candidates))) (let* ((minibuffer-allow-text-properties t) (resize-mini-windows 'grow-only) (prompt (selectrum--remove-default-from-prompt prompt)) (icomplete-mode nil) (buf (current-buffer)) (res (let ((hook ...)) (fset hook #'...) (unwind-protect (progn ... ...) (remove-hook ... hook))))) (cond (minibuffer-completion-table (let ((exit-string ...) (default ...)) (if (and exit-string ... ...) default-candidate (substring-no-properties res)))) (t res)))))
(let* ((default-candidate (car (cdr (plist-member args ':default-candidate)))) (initial-input (car (cdr (plist-member args ':initial-input)))) (require-match (car (cdr (plist-member args ':require-match)))) (history (car (cdr (plist-member args ':history)))) (no-move-default-candidate (car (cdr (plist-member args ':no-move-default-candidate)))) (may-modify-candidates (car (cdr (plist-member args ':may-modify-candidates)))) (minibuffer-completion-table (car (cdr (plist-member args ':minibuffer-completion-table)))) (minibuffer-completion-predicate (car (cdr (plist-member args ':minibuffer-completion-predicate))))) (progn (let ((--cl-keys-- args)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '...) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:default-candidate..." (car --cl-keys--)))))) (progn (if (or may-modify-candidates (functionp candidates)) nil (setq candidates (copy-sequence candidates))) (let* ((minibuffer-allow-text-properties t) (resize-mini-windows 'grow-only) (prompt (selectrum--remove-default-from-prompt prompt)) (icomplete-mode nil) (buf (current-buffer)) (res (let (...) (fset hook ...) (unwind-protect ... ...)))) (cond (minibuffer-completion-table (let (... ...) (if ... default-candidate ...))) (t res))))))
selectrum--read("Find file: " (closure ((is-env-completion) (sortf . selectrum-default-candidate-preprocess-function) (msg . "Press \[selectrum-insert-current-candidate] to ref...") (last-dir . "/") (_inherit-input-method) (def . "~/") (hist . file-name-history) (initial-input . "~/") (require-match . confirm-after-completion) (predicate . file-exists-p) (collection . read-file-name-internal) (prompt . "Find file: ") t) (input) (let* ((path (substitute-in-file-name input)) (is-remote-path (file-remote-p path)) (is-connected (and is-remote-path (file-remote-p path nil t))) (dir (or (file-name-directory path) "")) (maybe-tramp (equal dir "/")) (matchstr (file-name-nondirectory path)) (cands (cond ((and ... ... is-remote-path) (prog1 nil ...)) ((string-prefix-p "$" matchstr) (setq is-env-completion t) (setq matchstr ...) (let* ... ... ...)) ((and ... ... ... ... ...) (set ... ...) selectrum--preprocessed-candidates) ((and ... ... ... ...) (setq is-env-completion nil) (set ... sortf) (set ... nil) (selectrum--partial-file-completions path collection predicate)) (t (setq is-env-completion nil) (set ... sortf) (set ... nil) (let ... ...))))) (setq last-dir dir) (list (cons 'input matchstr) (cons 'candidates cands)))) :default-candidate "~/" :initial-input "~/" :history file-name-history :require-match nil :may-modify-candidates t :minibuffer-completion-table read-file-name-internal :minibuffer-completion-predicate file-exists-p)
(progn (add-hook 'minibuffer-setup-hook hook t) (selectrum--read prompt coll :default-candidate (or (car-safe def) def) :initial-input (or (car-safe initial-input) initial-input) :history hist :require-match (eq require-match t) :may-modify-candidates t :minibuffer-completion-table collection :minibuffer-completion-predicate predicate))
(unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (selectrum--read prompt coll :default-candidate (or (car-safe def) def) :initial-input (or (car-safe initial-input) initial-input) :history hist :require-match (eq require-match t) :may-modify-candidates t :minibuffer-completion-table collection :minibuffer-completion-predicate predicate)) (remove-hook 'minibuffer-setup-hook hook))
(let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil (setq sortf selectrum-preprocess-candidates-function) (set ... t) (set-syntax-table selectrum--minibuffer-local-filename-syntax))))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (selectrum--read prompt coll :default-candidate (or (car-safe def) def) :initial-input (or (car-safe initial-input) initial-input) :history hist :require-match (eq require-match t) :may-modify-candidates t :minibuffer-completion-table collection :minibuffer-completion-predicate predicate)) (remove-hook 'minibuffer-setup-hook hook)))
(let* ((last-dir nil) (msg "Press \[selectrum-insert-current-candidate] to ref...") (sortf nil) (is-env-completion nil) (coll #'(lambda (input) (let* ((path ...) (is-remote-path ...) (is-connected ...) (dir ...) (maybe-tramp ...) (matchstr ...) (cands ...)) (setq last-dir dir) (list (cons ... matchstr) (cons ... cands)))))) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil ... ... ...)))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook t) (selectrum--read prompt coll :default-candidate (or (car-safe def) def) :initial-input (or (car-safe initial-input) initial-input) :history hist :require-match (eq require-match t) :may-modify-candidates t :minibuffer-completion-table collection :minibuffer-completion-predicate predicate)) (remove-hook 'minibuffer-setup-hook hook))))
selectrum--completing-read-file-name("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/" file-name-history "~/" nil)
apply(selectrum--completing-read-file-name ("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/" file-name-history "~/" nil))
(progn (add-hook 'minibuffer-setup-hook hook) (apply #'selectrum--completing-read-file-name args))
(unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (apply #'selectrum--completing-read-file-name args)) (remove-hook 'minibuffer-setup-hook hook))
(let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil (if virtual ...))))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (apply #'selectrum--completing-read-file-name args)) (remove-hook 'minibuffer-setup-hook hook)))
(let* ((default (if (consp default-filename) (car default-filename) default-filename)) (df (expand-file-name default)) (dd (expand-file-name default-directory)) (default-in-prompt-dir (equal (file-name-directory (directory-file-name df)) (file-name-directory dd))) (virtual (if (or (not default-in-prompt-dir) (not (file-exists-p default))) (progn (propertize (string-remove-prefix dd df) 'selectrum--candidate-full default))))) (if (equal df dd) nil (if default-in-prompt-dir (progn (setq default (file-relative-name default default-directory)))) (if (consp default-filename) (setcar default-filename default) (setq default-filename default)) (let* ((c (nthcdr 6 args))) (setcar c default-filename))) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'(lambda nil ...)))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (apply #'selectrum--completing-read-file-name args)) (remove-hook 'minibuffer-setup-hook hook))))
(if (not default-filename) (apply #'selectrum--completing-read-file-name args) (let* ((default (if (consp default-filename) (car default-filename) default-filename)) (df (expand-file-name default)) (dd (expand-file-name default-directory)) (default-in-prompt-dir (equal (file-name-directory (directory-file-name df)) (file-name-directory dd))) (virtual (if (or (not default-in-prompt-dir) (not (file-exists-p default))) (progn (propertize (string-remove-prefix dd df) 'selectrum--candidate-full default))))) (if (equal df dd) nil (if default-in-prompt-dir (progn (setq default (file-relative-name default default-directory)))) (if (consp default-filename) (setcar default-filename default) (setq default-filename default)) (let* ((c (nthcdr 6 args))) (setcar c default-filename))) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil (remove-hook 'minibuffer-setup-hook hook) (funcall #'...))) (unwind-protect (progn (add-hook 'minibuffer-setup-hook hook) (apply #'selectrum--completing-read-file-name args)) (remove-hook 'minibuffer-setup-hook hook)))))
(closure ((crf . selectrum-completing-read) (predicate) (initial) (mustmatch . confirm-after-completion) (default-filename . "~/") (dir) (prompt . "Find file: ") t) (&rest args) (setq completing-read-function crf) (if (not default-filename) (apply #'selectrum--completing-read-file-name args) (let* ((default (if (consp default-filename) (car default-filename) default-filename)) (df (expand-file-name default)) (dd (expand-file-name default-directory)) (default-in-prompt-dir (equal (file-name-directory ...) (file-name-directory dd))) (virtual (if (or ... ...) (progn ...)))) (if (equal df dd) nil (if default-in-prompt-dir (progn (setq default ...))) (if (consp default-filename) (setcar default-filename default) (setq default-filename default)) (let* ((c ...)) (setcar c default-filename))) (let ((hook (make-symbol "selectrum--minibuffer-setup"))) (fset hook #'(lambda nil ... ...)) (unwind-protect (progn (add-hook ... hook) (apply ... args)) (remove-hook 'minibuffer-setup-hook hook))))))("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/" file-name-history "~/" nil)
completing-read("Find file: " read-file-name-internal file-exists-p confirm-after-completion "~/" file-name-history "~/")
read-file-name-default("Find file: " nil "/Users/mit5893/" confirm-after-completion nil nil)
(let* ((crf completing-read-function) (completing-read-function #'(lambda (&rest args) (setq completing-read-function crf) (if (not default-filename) (apply #'selectrum--completing-read-file-name args) (let* (... ... ... ... ...) (if ... nil ... ... ...) (let ... ... ...)))))) (read-file-name-default prompt dir (concat (expand-file-name (or dir default-directory)) initial) mustmatch initial predicate))
selectrum-read-file-name("Find file: " nil "~/" confirm-after-completion nil nil)
#f(compiled-function (prompt &optional dir default-filename mustmatch initial predicate) "Read file name, prompting with PROMPT and completing in directory DIR.\nThe return value is not expanded---you must call expand-file-name' yourself.\n\nDIR is the directory to use for completing relative file names.\nIt should be an absolute directory name, or nil (which means the\ncurrent buffer's value ofdefault-directory').\n\nDEFAULT-FILENAME specifies the default file name to return if the\nuser exits the minibuffer with the same non-empty string inserted\nby this function. If DEFAULT-FILENAME is a string, that serves\nas the default. If DEFAULT-FILENAME is a list of strings, the\nfirst string is the default. If DEFAULT-FILENAME is omitted or\nnil, then if INITIAL is non-nil, the default is DIR combined with\nINITIAL; otherwise, if the current buffer is visiting a file,\nthat file serves as the default; otherwise, the default is simply\nthe string inserted into the minibuffer.\n\nIf the user exits with an empty minibuffer, return an empty\nstring. (This happens only if the user erases the pre-inserted\ncontents, or if insert-default-directory' is nil.)\n\nFourth arg MUSTMATCH can take the following values:\n- nil means that the user can exit with any input.\n- t means that the user is not allowed to exit unless\n the input is (or completes to) an existing file.\n-confirm' means that the user can exit with any input, but she needs\n to confirm her choice if the input is not an existing file.\n- confirm-after-completion' means that the user can exit with any\n input, but she needs to confirm her choice if she called\nminibuffer-complete' right before minibuffer-complete-and-exit'\n and the input is not an existing file.\n- anything else behaves like t except that typing RET does not exit if it\n does non-null completion.\n\nFifth arg INITIAL specifies text to start with.\n\nSixth arg PREDICATE, if non-nil, should be a function of one\nargument; then a file name is considered an acceptable completion\nalternative only if PREDICATE returns non-nil with the file name\nas its argument.\n\nIf this command was invoked with the mouse, use a graphical file\ndialog ifuse-dialog-box' is non-nil, and the window system or X\ntoolkit in use provides a file dialog box, and DIR is not a\nremote file. For graphical file dialogs, any of the special values\nof MUSTMATCH confirm' andconfirm-after-completion' are\ntreated as equivalent to nil. Some graphical file dialogs respect\na MUSTMATCH value of t, and some do not (or it only has a cosmetic\neffect, and does not actually prevent the user from entering a\nnon-existent file).\n\nSee also read-file-name-completion-ignore-case'\nandread-file-name-function'." #
ad-Advice-read-file-name(#f(compiled-function (prompt &optional dir default-filename mustmatch initial predicate) "Read file name, prompting with PROMPT and completing in directory DIR.\nThe return value is not expanded---you must call expand-file-name' yourself.\n\nDIR is the directory to use for completing relative file names.\nIt should be an absolute directory name, or nil (which means the\ncurrent buffer's value ofdefault-directory').\n\nDEFAULT-FILENAME specifies the default file name to return if the\nuser exits the minibuffer with the same non-empty string inserted\nby this function. If DEFAULT-FILENAME is a string, that serves\nas the default. If DEFAULT-FILENAME is a list of strings, the\nfirst string is the default. If DEFAULT-FILENAME is omitted or\nnil, then if INITIAL is non-nil, the default is DIR combined with\nINITIAL; otherwise, if the current buffer is visiting a file,\nthat file serves as the default; otherwise, the default is simply\nthe string inserted into the minibuffer.\n\nIf the user exits with an empty minibuffer, return an empty\nstring. (This happens only if the user erases the pre-inserted\ncontents, or if insert-default-directory' is nil.)\n\nFourth arg MUSTMATCH can take the following values:\n- nil means that the user can exit with any input.\n- t means that the user is not allowed to exit unless\n the input is (or completes to) an existing file.\n-confirm' means that the user can exit with any input, but she needs\n to confirm her choice if the input is not an existing file.\n- confirm-after-completion' means that the user can exit with any\n input, but she needs to confirm her choice if she called\nminibuffer-complete' right before minibuffer-complete-and-exit'\n and the input is not an existing file.\n- anything else behaves like t except that typing RET does not exit if it\n does non-null completion.\n\nFifth arg INITIAL specifies text to start with.\n\nSixth arg PREDICATE, if non-nil, should be a function of one\nargument; then a file name is considered an acceptable completion\nalternative only if PREDICATE returns non-nil with the file name\nas its argument.\n\nIf this command was invoked with the mouse, use a graphical file\ndialog ifuse-dialog-box' is non-nil, and the window system or X\ntoolkit in use provides a file dialog box, and DIR is not a\nremote file. For graphical file dialogs, any of the special values\nof MUSTMATCH confirm' andconfirm-after-completion' are\ntreated as equivalent to nil. Some graphical file dialogs respect\na MUSTMATCH value of t, and some do not (or it only has a cosmetic\neffect, and does not actually prevent the user from entering a\nnon-existent file).\n\nSee also read-file-name-completion-ignore-case'\nandread-file-name-function'." #
apply(ad-Advice-read-file-name #f(compiled-function (prompt &optional dir default-filename mustmatch initial predicate) "Read file name, prompting with PROMPT and completing in directory DIR.\nThe return value is not expanded---you must call expand-file-name' yourself.\n\nDIR is the directory to use for completing relative file names.\nIt should be an absolute directory name, or nil (which means the\ncurrent buffer's value ofdefault-directory').\n\nDEFAULT-FILENAME specifies the default file name to return if the\nuser exits the minibuffer with the same non-empty string inserted\nby this function. If DEFAULT-FILENAME is a string, that serves\nas the default. If DEFAULT-FILENAME is a list of strings, the\nfirst string is the default. If DEFAULT-FILENAME is omitted or\nnil, then if INITIAL is non-nil, the default is DIR combined with\nINITIAL; otherwise, if the current buffer is visiting a file,\nthat file serves as the default; otherwise, the default is simply\nthe string inserted into the minibuffer.\n\nIf the user exits with an empty minibuffer, return an empty\nstring. (This happens only if the user erases the pre-inserted\ncontents, or if insert-default-directory' is nil.)\n\nFourth arg MUSTMATCH can take the following values:\n- nil means that the user can exit with any input.\n- t means that the user is not allowed to exit unless\n the input is (or completes to) an existing file.\n-confirm' means that the user can exit with any input, but she needs\n to confirm her choice if the input is not an existing file.\n- confirm-after-completion' means that the user can exit with any\n input, but she needs to confirm her choice if she called\nminibuffer-complete' right before minibuffer-complete-and-exit'\n and the input is not an existing file.\n- anything else behaves like t except that typing RET does not exit if it\n does non-null completion.\n\nFifth arg INITIAL specifies text to start with.\n\nSixth arg PREDICATE, if non-nil, should be a function of one\nargument; then a file name is considered an acceptable completion\nalternative only if PREDICATE returns non-nil with the file name\nas its argument.\n\nIf this command was invoked with the mouse, use a graphical file\ndialog ifuse-dialog-box' is non-nil, and the window system or X\ntoolkit in use provides a file dialog box, and DIR is not a\nremote file. For graphical file dialogs, any of the special values\nof MUSTMATCH confirm' andconfirm-after-completion' are\ntreated as equivalent to nil. Some graphical file dialogs respect\na MUSTMATCH value of t, and some do not (or it only has a cosmetic\neffect, and does not actually prevent the user from entering a\nnon-existent file).\n\nSee also read-file-name-completion-ignore-case'\nandread-file-name-function'." #
read-file-name("Find file: " nil "~/" confirm-after-completion)
find-file-read-args("Find file: " confirm-after-completion)
byte-code("\300\301\302 \"\207" [find-file-read-args "Find file: " confirm-nonexistent-file-or-buffer] 3)
call-interactively(find-file nil nil)
command-execute(find-file)
Tramp setup is not much:
(when skeez/feature_docker_tramp
;; MELPA docker-tramp
;;
;; WOA
;; Tramp multihop: C-x C-f /ssh:you@remotehost|sudo:remotehost:/path/to/file RET
;; Tramp multihop through a docker at second stage: /plink:[email protected]|docker:root@ranokia_19.10.0-6b_0:/path/to/file
(use-package docker-tramp
:ensure t)
(push
(cons
"docker"
'((tramp-login-program "sudo docker")
(tramp-login-args (("exec" "-it") ("%h") ("/bin/bash")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-i") ("-c"))))
tramp-methods)
(defadvice tramp-completion-handle-file-name-all-completions
(around dotemacs-completion-docker activate)
"(tramp-completion-handle-file-name-all-completions \"\" \"/docker:\" returns
a list of active Docker container names, followed by colons."
(if (equal (ad-get-arg 1) "/docker:")
(let* ((dockernames-raw (shell-command-to-string "docker ps | awk '$NF != \"NAMES\" { print $NF \":\" }'"))
(dockernames (cl-remove-if-not
#'(lambda (dockerline) (string-match ":$" dockerline))
(split-string dockernames-raw "\n"))))
(setq ad-return-value dockernames))
ad-do-it))
)
;; try to speed up tramp..
(setq tramp-completion-reread-directory-timeout nil)
;; tramp: ignore version control on remotes
(setq vc-ignore-dir-regexp
(format "\(%s\)\|\(%s\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
Selectrum:
(selectrum-mode +1)
(add-hook 'comint-mode-hook
(defun my-comint-use-default-completion ()
(setq-local completion-in-region-function #'completion--in-region)))
;; set selectrum to use orderless
(setq selectrum-refine-candidates-function #'orderless-filter)
(setq selectrum-highlight-candidates-function #'orderless-highlight-matches)
(add-hook 'buffer-list-update-hook
(lambda ()
(unless (eq major-mode 'minibuffer-inactive-mode)
(setq completion-styles (if (derived-mode-p 'comint-mode) '(basic) '(orderless))))))
Sometimes when spamming C-g to break the hang, it'll show 'Tramp connecting to..." one of the IPs; so the hang is almost certainly somethign Selectrum is doing, that causes Tramp to be trying to open the connection(s)
@clemera I've had the same issue as @skeezix - I think the issue is selectrum + marginalia's heavy annotations, maybe it tries to retrieve some information about the remotes to display as annotations that is causing this hang.
If I emacs -Q and load just selectrum, or selectrum and marginalia without heavy annotations, it works okay, (setq marginalia-annotators '(marginalia-annotators-heavy nil)) and I get the hang.
@jdm204 Thanks, I opened a PR on the marginalia side here
I will close this as it the remaining problems are a Marginalia issue, see the followup PR here
Ah, very interesting!
I pulled latest Selectrum and Marginalia manually, and everything is working a treat again, plus the new bits. Whew!
Super bug-tracking, and super support.
Thanks so much guys, and looove Selectrum. Honestly, tinkering with my now-enormous .emacs has helped me stay sane during this last years global apocalypse :)
Most helpful comment
Ah, very interesting!
I pulled latest Selectrum and Marginalia manually, and everything is working a treat again, plus the new bits. Whew!
Super bug-tracking, and super support.
Thanks so much guys, and looove Selectrum. Honestly, tinkering with my now-enormous .emacs has helped me stay sane during this last years global apocalypse :)