【问题标题】:emacs shell: change directory with idoemacs shell:使用 ido 更改目录
【发布时间】:2014-01-06 15:13:15
【问题描述】:

我越来越多地使用 emacs shell-mode,还有一些我希望可以改进的地方:更改目录时的补全。我很乐意为此使用 idoprojectile-find-dir

我的工作流程

截至今天,我尽我所能在 emacs 的 shell 之外,尽可能地使用 emacs 的功能(使用 ido 访问文件,使用 projectile 在项目中查找文件,探索里面的树干枯了,……)。

我不经常CD。当我在另一个项目中工作时,我会打开另一个 shell 缓冲区。但是当我不得不这样做时,我真的很想念 ido 或 fasd shell 实用程序(它可以工作,但没有它的完成接口,这对 zsh 来说很棒,而且它不如使用 ido 强大是https://github.com/clvv/fasd)。

如何在 elisp 中连接它?

我知道我们可以给ido-completing-read一个名单;

在 shell 中,输入 cd ../<TAB> 会打开一个新的 *Completions* 缓冲区。它使用comint-dynamic-completion,但如何在 elisp 列表中获取该列表,而不是在缓冲区中?

  • 是否可以将该完成列表连接到 ido 中? (或弹丸或头盔或其他)
  • 如果您将我链接到准确的文档,我也将不胜感激(有很多,很难知道什么对我有用)
  • 或者是否存在解决方案?

谢谢!

编辑:这是另一个使用 fasd 实用程序和 ido 完成 cd 到最近访问过的目录的好方法:https://gitlab.com/emacs-stuff/fasd-shell/blob/master/README.org

another SO question

ps:eshell 不适用于某些 shell 脚本,我想保持 shell 模式。

【问题讨论】:

  • 关于你的 PS,如果你没有很多 shell 脚本,就像我一样,我会运行 M-& for async-shell-command。

标签: emacs elisp


【解决方案1】:

试试这个,这是一个快速而肮脏的黑客,在某些情况下可能会失败,但应该可以正常工作。也请原谅我的省略号

(require 'ido)
(require 'cl-lib)
(require 'shell)

(defvar my-dir-selected nil "Flag to indicate that user has selected the directory")

(defun my-filter-cd-input (current-input)
  "Takes current user input for `cd' the a list
    whose car is the 'maximum possible directory path'
    and cdr is remaining string.

    Examples:
    '~/.emacs.d/in => ('~./emacs.d/' 'in')
    '/home/gue' => ('/home/' 'gue')
    '~/../' => ('~/../' '')"
  (let* ((unquoted-input (shell-unquote-argument current-input))
     (components (split-string unquoted-input "/"))
         (directory-parts (butlast components))
         (possible-prefix (car (last components))))
    (list (if (string= possible-prefix "")
              unquoted-input
            (concat (mapconcat 'identity directory-parts "/")
                    (when directory-parts "/")))
          possible-prefix)))

(defun my-complete-directory-name (directory current-input)
  "Prompts user for directories in `directory', `current-input'
    is the string entered by the user till now"
  (let* ((filtered-input (my-filter-cd-input current-input))
         (directory-path (car filtered-input))
         (partial-input (cadr filtered-input))
         (directory-choices (mapcar 'file-name-nondirectory
                                    (condition-case nil
                                        (cl-remove-if-not 'file-directory-p
                                                          (directory-files (concat directory directory-path) t))
                                      ('file-error (list)))))
         (selected-name (ido-completing-read "Directory: "
                                             directory-choices
                                             nil nil partial-input)))
    (comint-delete-input)
    (insert (concat "cd " 
            (shell-quote-argument (concat directory-path selected-name "/"))))))

(defun my-prompt-for-dir-or-fallback ()
  "If current shell command is `cd' prompt for directory
    using ido otherwise fallback to normal completion"
  (interactive)
  (let* ((user-input (buffer-substring-no-properties (comint-line-beginning-position)
                                                     (point-max))))
    (if (and (>= (length user-input) 3)
             (string= (substring user-input 0 3) "cd "))
        (progn 
          (setq my-dir-selected nil)
          (while (not my-dir-selected)
            (my-complete-directory-name default-directory 
                    (buffer-substring-no-properties (+ (comint-line-beginning-position) 3) 
                                    (point-max))))
          (comint-send-input))
      (call-interactively 'completion-at-point))))

(define-key shell-mode-map (kbd "<tab>") 'my-prompt-for-dir-or-fallback)

(add-hook 'ido-setup-hook 'ido-my-keys)

(defun ido-my-keys ()
  "Add my keybindings for ido."
  (define-key ido-completion-map (kbd "<C-return>") (lambda ()
                                                        (interactive)
                                                        (setq my-dir-selected t)
                                                        (ido-exit-minibuffer))))

如果当前输入的命令是cd,在shell中点击&lt;tab&gt;将提示使用ido提供的目录,否则将退回到默认完成,退出按C-RET

【讨论】:

  • 哇,这真是太棒了!谢谢,恭喜,我会仔细研究你的elisp。但是有一件事:您认为在使用 RET 选择第一个目录后,ido 会一直要求以下子目录吗?我们可以用 C-j 完成选择。深入一个目录会更容易。
  • 你应该继续努力让它易于使用(ELPA 包?),它绝对值得,它非常方便。
  • 您好,很高兴它对您有所帮助。关于让 ido 在用户选择一个目录后立即询问以下子目录,这似乎很难实现,我试着让你知道我设法实现它
  • 嗨@Ehvince,抱歉耽搁了,我做了一些更改,现在ido会在使用RET选择目录后继续询问子目录,完成选择按C-RET
  • 这太惊人了。恭喜。延迟原谅你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
相关资源
最近更新 更多