Month: April 2016

Quickly move a file to the current directory

Often I’ll download a file in my browser, and then want to move that file to the directory in which I am working in emacs. I wrote a little helper function to streamline this, called bjm/move-file-here, given below or at this github gist. Call the function and it will prompt you with a list of files in your starting directory (defaulting to ~/downloads, but configurable with bjm/move-file-here-start-dir) sorted to have the most recent first. The chosen file will then be moved to the current directory if you are in dired, or else the directory of the current buffer.

The function needs the packages dash.el and swiper installed. Here is the code – comments are welcome.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; move file here                                                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'dash)
(require 'swiper)

;; start directory
(defvar bjm/move-file-here-start-dir (expand-file-name "~/downloads"))

(defun bjm/move-file-here ()
  "Move file from somewhere else to here.
The file is taken from a start directory set by `bjm/move-file-here-start-dir' and moved to the current directory if invoked in dired, or else the directory containing current buffer. The user is presented with a list of files in the start directory, from which to select the file to move, sorted by most recent first."
  (interactive)
  (let (file-list target-dir file-list-sorted start-file start-file-full)
    ;; clean directories from list but keep times
    (setq file-list
          (-remove (lambda (x) (nth 1 x))
                   (directory-files-and-attributes bjm/move-file-here-start-dir)))

    ;; get target directory
    ;; http://ergoemacs.org/emacs/emacs_copy_file_path.html
    (setq target-dir
          (if (equal major-mode 'dired-mode)
              (expand-file-name default-directory)
            (if (null (buffer-file-name))
                (user-error "ERROR: current buffer is not associated with a file.")
              (file-name-directory (buffer-file-name)))))

  ;; sort list by most recent
  ;;http://stackoverflow.com/questions/26514437/emacs-sort-list-of-directories-files-by-modification-date
  (setq file-list-sorted
        (mapcar #'car
                (sort file-list
                      #'(lambda (x y) (time-less-p (nth 6 y) (nth 6 x))))))

  ;; use ivy to select start-file
  (setq start-file (ivy-read
                    (concat "Move selected file to " target-dir ":")
                    file-list-sorted
                    :re-builder #'ivy--regex
                    :sort nil
                    :initial-input nil))

  ;; add full path to start file and end-file
  (setq start-file-full
        (expand-file-name start-file bjm/move-file-here-start-dir))
  (setq end-file
        (expand-file-name (file-name-nondirectory start-file) target-dir))
  (rename-file start-file-full end-file)
  (message "moved %s to %s" start-file-full end-file)))
Advertisement

Undo-send and schedule email in mu4e

Note that this package has been superseded by the superior mu4e-send-delay.

One of the things I missed when I switched from thunderbird to mu4e was the ability to undo sent emails. I’m sure I’m not the only one that has spotted a glaring error, or a CC’d person that shouldn’t be CC’d the moment after I hit send! Of course you can’t truly undo a sent email, but if you buffer emails for a short period of time before actually sending them then you can retrieve them and edit or cancel them before sending again. This is what the send later extension in thunderbird does, and also the “undo send” function in gmail.

I looked into whether something like this existed for mu4e, I found gnus-delay, but it turned out not to work in mu4e. However it did not take too much effort to modify it to work, and hence mu4e-delay was born. Credit to the authors of gnus-delay who wrote most of the code this is based on.

Once you initialise the package, you can use C-c C-l (mnemonic l for send later) in place of C-c C-c to send mail. This moves the mail to the drafts folder and adds a header keyword specifying the time at which a mail should be sent, defaulting to 2 minutes in the future. A timer runs every minute (default) checking all mails in the drafts folder and sending those that are due. If you wish to “undo send” just find it in the drafts folder and then edit it to remove the delay header and save it. This will prevent it from being sent until you re-send (or delay) it.

The package also provides the function mu4e-delay-add-delay-header which can be called interactively to add any date and time to the delay header keyword, scheduling an email for an arbitrary point in the future.

The mail is sent with smtpmail or sendmail/postfix depending on which you have configured with send-mail-function. Since smtpmail causes emacs to freeze while mail is sent, you are strongly encouraged to use postfix (or similar) to handle your email sending.

A known limitation of mu4e-delay is that attachments are not sent properly when the mail is delayed. I’ve not worked out why this is yet (suggestions welcome!). The package checks to see if you have an attachment and warns you about this. With attachments you currently need you use C-c C-c to send as normal.

I’ll finish with a word of caution. Emails are important and I’d hate you to get into trouble because something went wrong an email did not get sent. I strongly recommend (at least at first) setting the variables mu4e-delay-bcc-address to bcc all outgoing mail to a spare email address so you can check things are being sent correctly. You can also set mu4e-delay-backup-directory to backup all delayed mail to a given directory rather than deleting it. I have used this package for several months without problems, but be careful!

To install the package, download it from github and put the mu4e-delay.el file somewhere on your system and then add the following to your init.el file

(add-to-list 'load-path "/path/to/directory")
(require 'mu4e-delay)

I’m keeping this package off MELPA for now until I get feedback that other people are using it without problems, so please let me know in the comments or on github whether it is working for you (or not).

My other articles on mu4e are collected here.

Using postfix instead of smtpmail to send email in mu4e

The standard setup for mu4e uses smtpmail to actually send the messages. This works fine for the most part, but by default it does not run asynchronously, so emacs pauses when a mail is sent. Usually this is very brief, but for messages with large attachments it can be very noticeable. This was particularly annoying to me when I started developing a package to add a two minute delay to all outgoing mail to give an “undo send” functionality (I’ll post more about this package soon). When the two minute timer finished and the mail was sent, I would be working on something else, and emacs would hang briefly, which was a bit annoying.

It is possible to configure mu4e to send the mail asynchronously, but apparently this can be unreliable. A better solution is to run your own mail server to handle outgoing mail. This is supported in mu4e, and mu4e hands off the mail to the server to send, so it happens instantly from the user’s point of view, regardless of the size of the mail. Another benefit is that mail sent while you are offline is handled automatically; the server queues the mail and then sends it when you reconnect.

I am using OS X Yosemite, and setting up a mail server was quite easy. The postfix mail server is installed by default on OS X, so it was just a matter of configuring it to work with my gmail account. I followed these helpful instructions, noting the advice in the comments that for Yosemite, the extra line

smtp_sasl_mechanism_filter = login

is needed.

Now we tell mu4e to use postfix to handle sending mail by adding the following to our emacs config file:

;;send mail using postfix
(setq send-mail-function 'sendmail-send-it)
(setq message-send-mail-function 'message-send-mail-with-sendmail)

(Note the references to “sendmail” are because this was the name of one of the original mail servers on unix/linux. Postfix is a more modern mail server that is compatible with sendmail.)

This should be all you need to switch to using postfix to send your mail. Some useful commands (to run at the command line, not using M-x in emacs) are

sudo postfix start
sudo postfix stop

to start and stop the server, and

mailq

to list the current queue of unsent mail. This will generally be empty, but if you have been offline you might see some mails in there. They should send automatically once the server notices you are back online, but if not, use

mailq -q

to send all mail in the queue. See the man pages for more functionality.

So there you are. This might not be for everyone, but if you don’t mind fiddling with some config files, I highly recommend moving over to postfix for sending your mail.

Super-efficient movement using avy

One of the revelations I came to after a while of using emacs is that you can use searching (or swiping) to efficiently move to another place in the visible buffer. In other words, you can see the place that you want the cursor to be so you do a search for a word close to that position to move the cursor there – not because you want to find that word.

The package avy gives an even more efficient way to do this. There are a few options, but with the configuration below, I look at the place I want the cursor to be, hit M-s and type the first character of a word close to that position, and then the short string that appears in order to select the word that I want and the cursor jumps there. Once you get used to it, it almost feels like you can move the cursor just by looking where you want it to go!

In the animation below I want to move the cursor to the start of the word “formed” near the bottom of the window, so I hit M-s and then f. avy then overlays letter combinations on all words starting f and I type “la” to move to the word I want.

avy.gif

Here is my configuration code for avy

(use-package avy
  :ensure t
  :bind (("M-s" . avy-goto-word-1)))

Use Emacs as a two-paned FTP client

I’ve written before about using sunrise commander for two-paned dired allowing an intuitive way to copy files between directories. You can also use sunrise to connect to an ftp server. For example in sunrise commander I hit j to go to a new directory and enter /username@ftp.mysite.com: which prompts me for my password and then connects to the top level directory of my site. Note that the syntax is important – in this case I don’t need to specify I am using an ftp connection since the host name starts with ftp, but the trailing colon is needed to specify the top level directory. The full syntax is described in the manual.

Now you can have the local directory in the left pane and the remote directory in the right pane, and copy files back and forth. Of course the same approach can be used to connect to an ftp server in normal dired, but I find the two-paned view of sunrise commander particularly intuitive here.