Up until very recently, I was primarily a user of nano for editing text. I still believe that for most uses, nano is powerful enough yet simple enough to be a very useful editor.

Recently I have switched to using GNU emacs (from the terminal). I wrestled with it for a while to get it to behave the way I wanted (which is a weird amalgam of nano behaviour, and various other influences).

My primary uses for a text editor are to edit Haskell, C++, and LaTeX (with a little Rain). These pages are for me to put up my configuration files for nano and emacs in case anyone else finds them useful.

I realise this code is probably nasty and hacky and awful. It does have two main things going for it: it works, and I know how it works. Feel free to take it and adapt as you want for your own purposes.

Emacs -- Haskell

Getting emacs to behave nicely on Haskell code was difficult. There is a Haskell mode for emacs (available in the Debian and Gentoo package managers, as well as many more), which I make use of, but I have overridden the indentation as I didn't like either of the default indentation modes. I wanted something very similar to the default nano behaviour of just copying the indentation from the previous line automatically, without having to press tab at all. So the indentation mode I have uses the indent from the line before, except where it spots a "where" or "do", in which case it adds two spaces or indents to the same level of the thing after the do, respectively.

The other thing I did, to curb my normal behaviour of making lines as wide as my window happens to display, was to get emacs' auto-fill mode to work properly on Haskell code. In comments, it does as you'd expect, but it also works on code, automatically wrapping the code to two spaces further in than the parent line. It doesn't behave properly with wrapping strings just yet, but otherwise it seems to work fine for me.

Here are the sections of the config file relevant to Haskell:

;; A function used to change the behaviour of return.  If you press it at
;; the start of a line, it will just move the code down a line.  If you
;; press it anywhere else, you get automatic indentation.
(defun neil-ret()
  (if (bolp) (newline) (newline-and-indent))
(add-hook 'haskell-mode-hook (lambda () (local-set-key (kbd "RET") 'neil-ret)))

;; Turn off the other two Haskell indentation modes
(remove-hook 'haskell-mode-hook 'turn-on-haskell-indent)
(remove-hook 'haskell-mode-hook 'turn-on-haskell-simple-indent)

(defun neil-haskell-indent ()
  "Haksell indentation."
      (setq start-of-cur-line (point))
      (forward-line -1)
      ;; If the line above is blank, go one further back but no more:
      (when (eolp) (forward-line -1))
      (setq start-of-prev-line (point))
      (skip-chars-forward "[:space:]" start-of-cur-line)
      (setq start-of-prev-text (point))
      (setq prev-line-text (buffer-substring start-of-prev-text start-of-cur-line))
    (when (/= start-of-prev-text start-of-cur-line)
      (insert-char ?\s (- start-of-prev-text start-of-prev-line))
    (when (string-match "^where" prev-line-text)
      (insert-char ?\s 2)
    (when (string-match "[^[:alpha:]]+do[[:space:]]" prev-line-text)
      (insert-char ?\s (string-match "[^[:space:]]" prev-line-text (+ 2 (string-match "do" prev-line-text))))
    (when (string-match "^--" prev-line-text)
        (insert-char ?- 2)
        (insert-char ?\s 1)
(add-hook 'haskell-mode-hook (lambda () (setq indent-line-function 'neil-haskell-indent)))

(defun neil-auto-fill () "blah" (interactive)
  (when (> (current-column) (current-fill-column))
      (setq start-of-auto-fill-line (point))
      ;; Horrible way to do this, I know:
        (skip-chars-forward "[:space:]" start-of-auto-fill-line)
        (setq line-is-comment-1 (following-char))
        (setq line-is-comment-2 (following-char))
      ;; Don't insert the two spaces when we're in a comment:
      (when (not (and (= line-is-comment-1 ?-) (= line-is-comment-2 ?-)))
        (insert-char ?\s 2)
(add-hook 'haskell-mode-hook (lambda () (setq auto-fill-function 'neil-auto-fill)))

;; Set the fill column to be a bit before 80:
(setq-default fill-column 74)

(add-hook 'haskell-mode-hook 'turn-on-auto-fill)
;; Stop line-feed from auto-filling:
(add-hook 'haskell-mode-hook (lambda () (set-char-table-range auto-fill-chars 10 nil)))
Emacs -- General

This part of the configuration file is a mixture of my general preferences, and getting Emacs to behave quite like nano. I also include all of cycle-buffer.el in my .emacs file, as it is easier than installing it on all the machines I run emacs on. I imagine to some emacs users the rebindings may seem nasty, but it suits the way I work.

;; Duplicate it
(defun duplicate()
 "Duplicate a line."
 (let (
       (beg (line-beginning-position))
       (end (line-end-position)))
   (copy-region-as-kill beg end)
   (forward-line 1)
   (forward-line -1)))
(global-set-key (kbd "C-c w") 'duplicate)

;; Displays the current marked region, like nano:

;; Always display the column number:
(setq column-number-mode t)

;; Bind Ctrl-O to save file (like nano, but you don't need to press return
;; afterwards)
(global-set-key (kbd "C-o") 'save-buffer)

;; Bind Ctrl-_ to go to file (exactly like nano)
(global-set-key (kbd "C-_") 'goto-line)

;; A handy macro for dealing with the listings package in LaTeX.
;; It puts the current word inside \lstinline|..|
(fset 'mark-lstinline "\C-[b\\lstinline|\C-[f|")
(add-hook 'latex-mode-hook (lambda () (local-set-key (kbd "C-c m") 'mark-lstinline)))

;; Try to get the scroll behaviour in emacs to be less annoying
;; (and more like nano)
(setq scroll-preserve-screen-position t)
(setq scroll-conservatively 5)

;; Turn off the menu bar (I seem to be able to use emacs fine, without
;; ever knowing how to use the menu bar, so turn it off)
(menu-bar-mode 0)

;; I find it annoying that emacs always asks you relative to the directory
;; the current file is in.  I always want to insert based on the
;; (external) working directory that I loaded emacs from.  This hack gets
;; that behaviour, and I bind it to the insert key (like nano)
(defun neil-insert () "Insert from starting directory" (interactive)
  (setq default-directory (concat (getenv "PWD") "/"))
  (call-interactively 'find-file)
(global-set-key (kbd "") 'neil-insert)

;; Load in the cycle-buffer module:
(autoload 'cycle-buffer "cycle-buffer" "Cycle forward." t)
(autoload 'cycle-buffer-backward "cycle-buffer" "Cycle backward." t)
(autoload 'cycle-buffer-permissive "cycle-buffer" "Cycle forward allowing *buffers*." t)
(autoload 'cycle-buffer-backward-permissive "cycle-buffer" "Cycle backward allowing *buffers*." t)
(autoload 'cycle-buffer-toggle-interesting "cycle-buffer" "Toggle if this
    buffer will be considered." t)

;; I decided to not use Esc-< like nano, as it's quite far to reach.
;; Instead I chose Alt-Leftarrow and Alt-Rightarrow.  I use Alt-Leftarrow
;; more, so I made that go forwards (which is usually the direction you
;; want to go.
(global-set-key (kbd "<A-right>") 'cycle-buffer-backward)
(global-set-key (kbd "<A-left>") 'cycle-buffer)
;; The above shortcuts don't seem to work when I'm connected via PuTTY.
;; These lines seem to bind the same commands to Alt-Leftarrow as above:
(global-set-key (kbd "ESC <right>") 'cycle-buffer-backward)
(global-set-key (kbd "ESC <left>") 'cycle-buffer)

;; I bind Ctrl-Space (two shortcuts; one for Linux, one for via PuTTY)
;; to auto-complete, like Visual Studio used to be.  Ctrl-Space is easier
;; than TAB in my opinion.
(global-set-key (kbd "C-SPC") 'dabbrev-expand)
(global-set-key (kbd "C-@") 'dabbrev-expand)

;; Use Ctrl-^ (Ctrl-6) to set the mark, like in nano.  Especially
;; necessary since Ctrl-Space usually does this, but I just rebound it above!
(global-set-key (kbd "C-^") 'set-mark-command)

;; The End key seems to be messed up through PuTTY, but this fixes it:
(global-set-key (kbd "<select>") 'end-of-line)
Emacs -- Wishlist

It seems to me that the difficulty with emacs is not wishing that it had an extra feature, but just puzzling out how to program that feature. Here is my list of things I'd like to make emacs do. If you know how, let me know!