diff --git a/lib/spack/spack/util/editor.py b/lib/spack/spack/util/editor.py
index ce990b6603711b1433f229405fa653c255d17747..8d9ee2f04bdd423fb95acaa488e0ef3ce52324ef 100644
--- a/lib/spack/spack/util/editor.py
+++ b/lib/spack/spack/util/editor.py
@@ -5,31 +5,37 @@
 
 """Module for finding the user's preferred text editor.
 
-Defines one variable: ``editor``, which is a
-``spack.util.executable.Executable`` object that can be called to invoke
-the editor.
-
-If no ``editor`` is found, an ``EnvironmentError`` is raised when
-``editor`` is invoked.
+Defines one function, editor(), which invokes the editor defined by the
+user's VISUAL environment variable if set. We fall back to the editor
+defined by the EDITOR environment variable if VISUAL is not set or the
+specified editor fails (e.g. no DISPLAY for a graphical editor). If
+neither variable is set, we fall back to one of several common editors,
+raising an EnvironmentError if we are unable to find one.
 """
+import copy
 import os
 
 from spack.util.executable import Executable, which
 
-# Set up the user's editor
-# $EDITOR environment variable has the highest precedence
-editor = os.environ.get('EDITOR')
+_visual_exe\
+    = Executable(os.environ['VISUAL']) if 'VISUAL' in os.environ else None
+_editor_exe\
+    = Executable(os.environ['EDITOR']) \
+    if 'EDITOR' in os.environ else which('vim', 'vi', 'emacs', 'nano')
+
 
-# if editor is not set, use some sensible defaults
-if editor is not None:
-    editor = Executable(editor)
-else:
-    editor = which('vim', 'vi', 'emacs', 'nano')
+# Invoke the user's editor.
+def editor(*args, **kwargs):
+    if _visual_exe:
+        visual_kwargs = copy.copy(kwargs)
+        visual_kwargs['fail_on_error'] = False
+        _visual_exe(*args, **visual_kwargs)
+        if _visual_exe.returncode == 0:
+            return  # Otherwise, fall back to EDITOR.
 
-# If there is no editor, only raise an error if we actually try to use it.
-if not editor:
-    def editor_not_found(*args, **kwargs):
+    if _editor_exe:
+        _editor_exe(*args, **kwargs)
+    else:
         raise EnvironmentError(
-            'No text editor found! Please set the EDITOR environment variable '
-            'to your preferred text editor.')
-    editor = editor_not_found
+            'No text editor found! Please set the VISUAL and/or EDITOR '
+            'environment variable(s) to your preferred text editor.')