2014-01-06 25 views
7

我越來越多地使用emacs shell模式,並且有一些我希望可以改進的地方:改變目錄時的完成。我很樂意使用idoprojectile-find-diremacs shell:用ido更改目錄

我的工作流程

截至今天我盡我所能外emacs的外殼,用emacs儘可能(訪問與IDO文件,項目與projectile查找文件的權力,探索裏面的樹,...)。

我不會經常光臨。當我在另一個項目中工作時,我打開另一個shell緩衝區。但是,當我必須做的時候,我真的很想念ido或shell工具(它工作正常,但沒有完整的界面,這對zsh很好,而且不像ido的使用可能是https://github.com/clvv/fasd)。

如何在elisp中連線?

我知道我們可以給ido-completing-read列表;

在shell中,輸入cd ../<TAB>會打開一個新的* Completions *緩衝區。它使用comint-dynamic-completion,但如何在elisp列表中獲取該列表,而不是在緩衝區中?

  • 是否可以將完成列表連接到ido? (或彈或頭盔或其他)
  • 如果您鏈接我準確的文件我將不勝感激過(有很多,很難知道什麼對我是非常有用的)
  • 或根本的解決方案存在了嗎?

謝謝!

編輯:這裏是另一種很好的方法,cd到最近訪問過的目錄,與胎兒酒精中毒綜合症公用事業和IDO完成:https://gitlab.com/emacs-stuff/fasd-shell/blob/master/README.org

another SO question

ps:eshell對某些shell腳本不能很好地工作,我想保持shell模式。

+0

在問候你的PS ,如果你沒有很多shell腳本,像我一樣,我運行M-&async-shell-command。 – nymo

回答

3

試試這個,它是一個快速和骯髒的黑客攻擊,可能在某些情況下失敗,但應該一般工作。也請原諒我的elisp

(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)))) 

殼擊中<tab>會提示使用IDO如果當前輸入的命令是cd可用的目錄,否則將退回到默認完成,退出按C-RET

+0

哇,這絕對是太棒了!謝謝,並祝賀,我會仔細研究你的elisp。有一件事:你認爲用RET選擇第一個目錄後,ido會不斷詢問下面的子目錄嗎?我們可以用C-j完成選擇。深入不止一個目標會更容易。 – Ehvince

+0

你應該繼續努力,並使其易於使用(ELPA包?),這絕對是值得的,它非常方便。 – Ehvince

+0

嗨,我很高興它幫助你。關於在用戶選擇一個目錄後立即詢問關於下面的子目錄,這似乎是棘手的實施,我試着讓你知道我設法實現它 – 2014-01-20 15:31:25