emacs 扩展 ido

scinart posted @ 2013年8月04日 23:47 in elisp with tags emacs ido , 4566 阅读

我用的是Emacs 24.2, (Windows操作系统不要鄙视我啊) 其他较高级的版本都理应类似。

如果你有同样的问题并且有好法,还望留言告知啊。

今天遇到一个问题是,在用ido-find-file的时候,这个文件适合用外部程序打开。(比如是个.doc什么的) 以前的做法是C-d进入文件夹,search那个文件,然后用我一个常见的

(w32-shell-execute 1 (dired-replace-in-string "/" "\\" (dired-get-filename)))

打开,然而今天我想为什么不能在C-x C-f的状态下用别的快捷键直接调用外部函数呢。

于是开始查。

C-x C-f下用\\[describe-mode]查看,为InactiveMinibuffer mode

再用\\[describe-bindings]查看,有以下等等

Major Mode Bindings:
key             binding
---             -------

C-@        ido-restrict-to-matches
C-a        ido-toggle-ignore
C-b        ido-magic-backward-char
C-d        ido-magic-delete-char
C-e        ido-edit-input
C-f        ido-magic-forward-char
......

 

算了,先看看RET干了啥吧。

RET runs the command ido-exit-minibuffer, which is an interactive
compiled Lisp function in `ido.el'.

(defun ido-exit-minibuffer ()
  "Exit minibuffer, but make sure we have a match if one is needed."
  (interactive)
  (if (and (or (not ido-require-match)
           (if (memq ido-require-match '(confirm confirm-after-completion))
           (if (or (eq ido-cur-item 'dir)
               (eq last-command this-command))
               t
             (setq ido-show-confirm-message t)
             nil))
               (ido-existing-item-p))
           (not ido-incomplete-regexp))
      (exit-minibuffer)))

and部分总是真,不管了,模仿出来了个能工作的就行。

exit-minibuffer is an interactive compiled Lisp function in
`minibuffer.el'.

(defun exit-minibuffer ()
  "Terminate this minibuffer argument."
  (interactive)
  (setq deactivate-mark nil)
  (throw 'exit nil))

我擦,这函数居然跟ido.el没干什么关系,还出了一个状况。我上哪接去啊?

没办法只能看C-x C-f干了啥了。

C-x C-f runs the command ido-find-file, which is an interactive
compiled Lisp function in `ido.el'.

(defun ido-find-file () ;; 注释省略
  (interactive) ;; 活都给ido-file-internal 来做了,还传进去了一个ido-default-file-method
  (ido-file-internal ido-default-file-method))

看看ido-file-internal干了些啥:

ido-file-internal is a Lisp function in `ido.el'.
(ido-file-internal METHOD &optional FALLBACK DEFAULT PROMPT ITEM
INITIAL SWITCH-CMD)
Not documented.

 中间edebug N步省略    line 2349:

(unless filename
    (setq ido-saved-vc-hb vc-handled-backends)
    (let ((minibuffer-completing-file-name t))

      ;; 就是从这儿读的minibuffer, 返回值是文件名,如果你输入的文件不存在也就返回你输入的文件名
      (setq filename (ido-read-internal item
                        (or prompt "Find file: ")
                        'ido-file-history
                        (and (eq method 'alt-file) buffer-file-name)
                        (confirm-nonexistent-file-or-buffer) initial))))

因为我不知道exit-minibuffer那个throw exit是怎么回事,所以我决定继续使用ido-file-internal接下来的代码

(cond
       ((eq ido-exit 'fallback)
    ;; Need to guard setting of default-directory here, since
    ;; we don't want to change directory of current buffer.
    (let ((default-directory ido-current-directory)
          (read-file-name-function nil))
      (setq this-command (or fallback 'find-file))
      (run-hook-with-args 'ido-before-fallback-functions this-command)
      (call-interactively this-command)))

...)

这是个大cond, 如果按回车,会符合最后一个条件,也就是打开文件。

但这里的精华是(在C-x C-f C-f时发现的)

(defun ido-fallback-command ()
  "Fallback to non-ido version of current command."
  (interactive)
  (let ((i (length ido-text)))
    (while (> i 0)
      (push (aref ido-text (setq i (1- i))) unread-command-events)))
  (setq ido-exit 'fallback)
  (exit-minibuffer))

即,在执行这个函数之后,之前那个cond就会落在第一个分支里,在这里执行fallback命令,默认是ido-default-file-method 但是由于源代码里是这样写的:(setq this-command (or fallback 'find-file) 而我没不都想改变默认是find-file 这一行为,看来把这段代码变一下还是相对活力的一种方式。

 

解决方案:在执行(or fallback 'find-file)之中加一次对外部函数的检查,以便我们在执行fallback的时候能执行任意我们想要的外部函数。

 

下面高亮的为变动部分。

---------------------------------------------------------------------

(defvar ido-fallback-function nil "The fallback function that will be explicitly check and can be externally modified
this variable is introduced to enhance ido-find-file functionality
search (cond ...  ((eq ido-exit 'fallback) ... )) to see where it's used.
2013-08-04 Sunday 19:35:45 by Scinart")

(defun ido-file-internal (method &optional fallback default prompt item initial switch-cmd)
  ;; Internal function for ido-find-file and friends
  (unless item
    (setq item 'file))
  (let ((ido-current-directory (ido-expand-directory default))
    (ido-context-switch-command switch-cmd)
    ido-directory-nonreadable ido-directory-too-big
    filename)

    (if (or (not ido-mode) (ido-is-slow-ftp-host))
    (setq filename t
          ido-exit 'fallback)
      (setq ido-directory-nonreadable
        (ido-nonreadable-directory-p ido-current-directory)
        ido-directory-too-big
        (and (not ido-directory-nonreadable)
         (ido-directory-too-big-p ido-current-directory))))

    (when (and (eq item 'file)
           (or ido-use-url-at-point ido-use-filename-at-point))
      (let (fn d)
    (require 'ffap)
    ;; Duplicate code from ffap-guesser as we want different
    ;; behavior for files and URLs.
    (cond
     ((with-no-warnings
        (and ido-use-url-at-point
         ffap-url-regexp
         (ffap-fixup-url (or (ffap-url-at-point)
                     (ffap-gopher-at-point)))))
      (setq ido-exit 'ffap
        filename t))

     ((and ido-use-filename-at-point
           (setq fn (with-no-warnings
              (if (eq ido-use-filename-at-point 'guess)
                  (ffap-guesser)
                (ffap-string-at-point))))
           (not (string-match "^http:/" fn))
           (let ((absolute-fn (expand-file-name fn)))
         (setq d (if (file-directory-p absolute-fn)
                 (file-name-as-directory absolute-fn)
               (file-name-directory absolute-fn))))
           (file-directory-p d))
      (setq ido-current-directory d)
      (setq initial (file-name-nondirectory fn))))))

    (let (ido-saved-vc-hb
      (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends))
      (ido-work-directory-index -1)
      (ido-work-file-index -1)
             (ido-find-literal nil))

      (unless filename
    (setq ido-saved-vc-hb vc-handled-backends)
    (let ((minibuffer-completing-file-name t))
      (setq filename (ido-read-internal item
                        (or prompt "Find file: ")
                        'ido-file-history
                        (and (eq method 'alt-file) buffer-file-name)
                        (confirm-nonexistent-file-or-buffer) initial))))

      ;; Choose the file name: either the text typed in, or the head
      ;; of the list of matches
      (cond
       ((eq ido-exit 'fallback)
    ;; Need to guard setting of default-directory here, since
    ;; we don't want to change directory of current buffer.
    (let ((default-directory ido-current-directory)
          (read-file-name-function nil))
      (setq this-command (or fallback ido-fallback-function 'find-file))
      (run-hook-with-args 'ido-before-fallback-functions this-command)
      (call-interactively this-command)
      (setq ido-fallback-function nil)))

       ((eq ido-exit 'switch-to-buffer)
    (ido-buffer-internal
     (if (memq method '(other-window other-frame)) method ido-default-buffer-method)
     nil nil nil ido-text))

       ((eq ido-exit 'insert-buffer)
    (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil ido-text 'ido-enter-insert-file))

       ((eq ido-exit 'dired)
    (dired (concat ido-current-directory (or ido-text ""))))

       ((eq ido-exit 'ffap)
    (find-file-at-point))

       ((eq method 'alt-file)
    (ido-record-work-file filename)
    (setq default-directory ido-current-directory)
    (ido-record-work-directory)
    (find-alternate-file filename))

       ((memq method '(dired list-directory))
    (if (equal filename ".")
        (setq filename ""))
    (let* ((dirname (ido-final-slash (concat ido-current-directory filename) t))
           (file (substring dirname 0 -1)))
      (cond
       ((file-directory-p dirname)
        (ido-record-command method dirname)
        (ido-record-work-directory dirname)
        (funcall method dirname))
       ((file-directory-p ido-current-directory)
        (cond
         ((file-exists-p file)
          (ido-record-command method ido-current-directory)
          (ido-record-work-directory)
          (funcall method ido-current-directory)
          (if (eq method 'dired)
          (with-no-warnings
            (dired-goto-file (expand-file-name file)))))
         ((string-match "[[*?]" filename)
          (setq dirname (concat ido-current-directory filename))
          (ido-record-command method dirname)
          (ido-record-work-directory)
          (funcall method dirname))
         ((y-or-n-p (format "Directory %s does not exist.  Create it? " filename))
          (ido-record-command method dirname)
          (ido-record-work-directory dirname)
          (make-directory-internal dirname)
          (funcall method dirname))
         (t
          ;; put make-directory command on history
          (ido-record-command 'make-directory dirname))))
       (t (error "No such directory")))))

       ((eq method 'write)
    (ido-record-work-file filename)
    (setq default-directory ido-current-directory)
    (setq filename (concat ido-current-directory filename))
    (ido-record-command 'write-file filename)
    (add-to-history 'file-name-history filename)
    (ido-record-work-directory)
    (write-file filename t))

       ((eq method 'read-only)
    (ido-record-work-file filename)
    (setq filename (concat ido-current-directory filename))
    (ido-record-command fallback filename)
    (ido-record-work-directory)
    (run-hook-with-args 'ido-before-fallback-functions fallback)
    (funcall fallback filename))

       ((eq method 'insert)
    (ido-record-work-file filename)
    (setq filename (concat ido-current-directory filename))
    (ido-record-command
     (if ido-find-literal 'insert-file-literally 'insert-file)
     filename)
    (add-to-history 'file-name-history filename)
    (ido-record-work-directory)
    (insert-file-1 filename
               (if ido-find-literal
               #'insert-file-contents-literally
             #'insert-file-contents)))

       (filename
    (ido-record-work-file filename)
    (setq filename (concat ido-current-directory filename))
    (ido-record-command 'find-file filename)
    (add-to-history 'file-name-history filename)
    (ido-record-work-directory)
    (ido-visit-buffer (find-file-noselect filename nil ido-find-literal) method))))))

(小提示,由于ido.el有已经编译过的文件,所以要么重新编译要么重新定义函数噢)

为了让这个外部函数工作还需要做以下工作

(add-hook 'ido-minibuffer-setup-hook 'ido-my-keys)
(defun ido-my-keys ()
  "My Keybindings for ido
especially for extending ido-find-file functionality
2013-08-04 Sunday 17:25:03"
  (define-key ido-completion-map (kbd "<return>") 'ido-exit-minibuffer) ;; for find-file
  (define-key ido-completion-map (kbd "RET") 'ido-magic-open-using-w32))

快捷键什么的都可以自己定义了,下面请看我如何自定义函数并与ido的minibuffer结果交互:

(defun ido-magic-open-using-w32 ()
  "This should be used when ido-minibuffer is active"
  (interactive)
;;   (let ((i (length ido-text)))
;;     (while (> i 0)
;;       (push (aref ido-text (setq i (1- i))) unread-command-events)))
  (setq ido-exit 'fallback)
  (setq ido-fallback-function
    '(lambda () (interactive)
       (let ((dir ido-current-directory)
         (file (car ido-matches)))
         (w32-shell-execute 1 (concat dir file)))))
  (exit-minibuffer))

其中 ido-current-directory是minibuffer返回文件的文件夹,ido-matches是minibuffer返回的文件名,我写的函数功能是用windows默认应用程序打开,关于其他的变量,请到这两个变量的附近自行查找,根据我的实验,有文档的大概都可以用。

结论:就为了一个外部函数与ido交互(还是与默认的ido-find-file交互而不是另起炉灶),费了我半天劲啊。
 

Avatar_small
seo service london 说:
2024年2月21日 22:50

Regular visits listed here are the easiest method to appreciate your energy, which is why why I am going to the website everyday, searching for new, interesting info. Many, thank you!

Avatar_small
주간토토 说:
2024年9月10日 16:49

This is the right blog for anyone who wants to find out about this topic. You realize so much its almost hard to argue with you (not that I actually would want…HaHa). You definitely put a new spin on a topic thats been written about for years. Great stuff, just great!

Avatar_small
먹튀개구리 说:
2024年9月10日 17:09

Decent data, profitable and phenomenal outline, as offer well done with smart thoughts and ideas, bunches of extraordinary data and motivation, both of which I require, on account of offer such an accommodating data her

Avatar_small
카지노세상 说:
2024年9月10日 17:13

I am incapable of reading articles online very often, but I’m happy I did today. It is very well written, and your points are well-expressed. I request you warmly, please, don’t ever stop writing.Do you want to buy the best Chromebook for artists?

Avatar_small
website 说:
2024年9月10日 17:34

It is perfect time to make some plans for the future and it is time to be happy. I've read this post and if I could I desire to suggest you some interesting things or suggestions. Perhaps you could write next articles referring to this article. I want to read more things about it! After reading your article I was amazed.

Avatar_small
먹튀타운 说:
2024年9月10日 17:36

Your article is what I've been looking for for a long time. I'm happy to find you like this. Could you visit my website if you have time? I'm sure you'll find a post of interest that you'll find interesting

Avatar_small
click here 说:
2024年9月10日 17:55

This is the right blog for anyone who wants to find out about this topic. You realize so much its almost hard to argue with you (not that I actually would want…HaHa). You definitely put a new spin on a topic thats been written about for years. Great stuff, just great!

Avatar_small
read more 说:
2024年9月10日 17:56

Usually I never comment on blogs but your article is so convincing that I never stop myself to say something about it. You’re doing a great job Man, Keep it up First of all let me tell you, you have got a great blog .I am interested in looking for more of such topics and would like to have further information

Avatar_small
totodiya 说:
2024年9月10日 17:59

 fascinating dialog is value remark. I feel that it is best to compose more on this matter, it may not be an unthinkable theme however generally people are insufficient to chat on such subjects

Avatar_small
get more info 说:
2024年9月10日 18:02

The article is about how one can go about buying fine jewellery. It details the several aspects that a person should look for when identifying finely crafted jewellery. The cost aspect of such a purchase is also given attention and one is guided about how to buy fine jewellery without paying too much

Avatar_small
click here 说:
2024年9月10日 18:03

I am so happy to read this. This is the kind of manual that needs to be given and not the random misinformation that’s at the other blogs. Appreciate your sharing this greatest doc

Avatar_small
website 说:
2024年9月10日 18:04

Our the purpose is to share the reviews about the latest Jackets,Coats and Vests also share the related Movies,Gaming, Casual,Faux Leather and Leather materials available

Avatar_small
get more info 说:
2024年9月10日 18:06

It is perfect time to make some plans for the future and it is time to be happy. I've read this post and if I could I desire to suggest you some interesting things or suggestions. Perhaps you could write next articles referring to this article. I want to read more things about it! After reading your article I was amazed.

Avatar_small
먹튀위젯 说:
2024年9月10日 18:07

Hello, I'm happy to see some great articles on your site. Would you like to come to my site later? My site also has posts, comments and communities similar to yours. Please visit and take a look

Avatar_small
information 说:
2024年9月10日 18:08

What a nice post! I'm so happy to read this. What you wrote was very helpful to me. Thank you. Actually, I run a site similar to you. If you have time, could you visit my site? Please leave your comments after reading what I wrote. If you do so, I will actively reflect your opinion. I think it will be a great help to run my site. Have a good day.

Avatar_small
good data 说:
2024年9月10日 18:10

 really like this post,and i parent that they having a ton of a laugh to peruse this post,they might take a respectable website to make an information,thanks for sharing it to me. First-rate job for publishing this type of useful internet website online. Your internet log isn’t only useful but it's miles moreover clearly creative too "`i like viewing net web sites which recognise the price of handing over the incredible beneficial useful resource freed from rate. I honestly cherished studying your posting. Thanks! 

Avatar_small
메이저놀이터 说:
2024年9月10日 18:12

That is a beneficial viewpoint, however isn’t make every sence whatsoever dealing with which mather. Any method thanks in addition to i had make an effort to share your current post straight into delicius but it surely is apparently an issue using your websites is it possible to you should recheck this. many thanks again . I enjoy your personal style of writing. 

Avatar_small
evokorea 说:
2024年9月10日 18:13

It is perfect time to make some plans for the future and it is time to be happy. I've read this post and if I could I desire to suggest you some interesting things or suggestions. Perhaps you could write next articles referring to this article. I want to read more things about it! After reading your article I was amazed.

Avatar_small
Learn more 说:
2024年9月10日 18:36

I am aware that people like you, are naturally intuitive, resourceful and already have the ability to heal yourself and transform into the person you want to be, you just need assistance to tap into your own resources.

Avatar_small
information 说:
2024年9月10日 18:58

Hello, I'm happy to see some great articles on your site. Would you like to come to my site later? My site also has posts, comments and communities similar to yours. Please visit and take a look

Avatar_small
Find out 说:
2024年9月10日 19:16

I am aware that people like you, are naturally intuitive, resourceful and already have the ability to heal yourself and transform into the person you want to be, you just need assistance to tap into your own resources.

Avatar_small
Find out 说:
2024年9月10日 19:21

I am aware that people like you, are naturally intuitive, resourceful and already have the ability to heal yourself and transform into the person you want to be, you just need assistance to tap into your own resources.

Avatar_small
here 说:
2024年9月10日 19:36

I found this is an informative and interesting post so i think so it is very useful and knowledgeable. I would like to thank you for the efforts you have made in writing this article.

Avatar_small
good data 说:
2024年9月10日 20:01

Hello there, You’ve done an incredible job. I will definitely digg it and personally recommend to my friends. I’m confident they’ll be benefited from this website.| First of all let me tell you, you have got a great blog .I am interested in looking for more of such topics and would like to have further information


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter