0

So, I was wondering if I can somehow(with a keyboard shortcut) open a file using the default system dialog, the same way that the big open button does at the top of the window. I didn't find a way to set keyboard shortcut to it directly inside emacs, neither did I find a way to do it in emacs tutorial.

And I do know that there is a way to map the find-file command or whatever, but I would still prefer the default systems find-file dialog.

1 Answer 1

0

IIUC, you want to trigger through a key sequence the same command that is triggered when you click in the File menu item in the menu bar and then click on Open file... in the drop-down menu.

You can ask Emacs what command that is: do C-h k then click on the File menu and then click on Open file.... You will get a *Help* buffer that starts like this:

There were several key-sequences:

  <select-window> runs the command handle-select-window
  <menu-bar> <file> <open-file> runs the command menu-find-file-existing

They're all described below.
...

As you can see, the command is menu-find-file-existing. So you can bind that command to a key in the usual way:

(define-key global-map (kbd "C-c z") #'menu-find-file-existing)

and then invoke the command with C-c z.

However, that does not give you the graphical file dialog: it will give you the minibuffer dialog. In order to get the graphical file dialog, you will have to make the function think that it is being called through a mouse click. Here's a modified function that sets up the necessary environment that will make menu-find-file-existing think that it was called by clicking on the menu items:

(defun my/fake-menu-find-file-existing ()
  (interactive)
  (let ((use-dialog-box t)
         (use-file-dialog t)
         (last-nonmenu-event nil))
    (menu-find-file-existing)))

(define-key global-map (kbd "C-c z") #'my/fake-menu-find-file-existing)

Now C-c z (or whatever you choose to bind the function to) will bring up the graphical file dialog.

Note that we are lying to Emacs, which is never a safe thing to do. I think it's not harmful in this case, but there is no warranty: if it breaks, you get to keep the pieces.


Details: You might be interested in how I came up with the "lying" function above. I used C-h f to get the doc string of each function of interest and clicked on the file where the function is defined to examine its source code. I started with menu-find-file-existing and found out that it gets the filename by calling find-file-read-args. So I did the same things with find-file-read-args and found out it calls read-file-name, which calls read-find-file-default. This one was more complicated, so I had to read the code somewhat carefully to find out how it works. The outcome is that it calls next-read-file-uses-dialog-p, a predicate that is callable from Lisp, but is implemented in C, so it's part of the Emacs image that you get when you build it from source (it is in src/fileio.c in the Emacs source directory, which you can e.g. clone from Emacs's git repository). That function looks like this:

DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p,
       Snext_read_file_uses_dialog_p, 0, 0, 0,
       doc: /* Return t if a call to `read-file-name' will use a dialog.
The return value is only relevant for a call to `read-file-name' that happens
before any other event (mouse or keypress) is handled.  */)
  (void)
{
#if (defined USE_GTK || defined USE_MOTIF \
     || defined HAVE_NS || defined HAVE_NTGUI || defined HAVE_HAIKU)
  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
      && use_dialog_box
      && use_file_dialog
      && window_system_available (SELECTED_FRAME ()))
    return Qt;
#endif
  return Qnil;
}

It turns out that the variables it uses can be reached from Lisp as well, so that allowed me to set them up in a way that makes this function return t and that fools Emacs and makes it think that menu-find-file-existing was called by clicking on the menu.

Obviously, this is NOT something that you want to undertake lightly (and maybe not at all!): if the Emacs devs wanted it to be easy they would have provided an easier way (which may exist but I have not found out). I doubly emphasize therefore that there is no warranty: "if it breaks, you get to keep the pieces".

1
  • Thank you for the answer! It now works perfectly.
    – Stigl
    Commented Mar 4 at 20:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.