08 Apr

Intelligence of a “non-intelligent” editor

I use Emacs as my main editor. There are still times when I start Eclipse or a similar IDE because I have a complicated run configuration set up for my old projects and I haven’t yet had time to migrate it. Some of my coworkers often speak about the power of an IDE or say something similar to “Why don’t you use a more intelligent IDE?”

But during my Emacs journey (going on for about a year now) I figured out why you don’t need too much intelligence. Please, don’t argue with me about Emacs being the most intelligent – I know it is (in a way), but the “intelligence” differs a lot comparing to IDEs like PyCharm or Eclipse or VisualStudio. They use complex parsers and state machines to try to figure out what are you trying to type and offer you the exact methods or object fields you might need. They are also great for learning a new language. Offering such a functionality with Emacs is more outsourced. For Python I use Jedi, for Ruby Rope and for JavaScript tern (which is amazing!).  But most of the time auto-complete-mode offers the best auto completion. It look’s up for words in your buffers (open files) and that pretty much covers 90% of your needs.

And all those integrations come to Emacs naturally. Emacs is nothing more than a lisp interpreter serving as an editor. The language is a bit strange for beginners but when you get to know it there is almost no limit to what feature you can extend or create. I use emacs for IRC (erc), versioning (magit), note taking (org-mode), file system managing (dired+) etc. At the moment I am even evaluating if I can replace my mail client with it. So you can always count on the fact that there probably isn’t a programming language or development procedure you could not do with Emacs.
I have three interesting examples to support my hypothesis.

The first one is projectile, one of my favorite Emacs extensions. It enables you a simple project support without any project configuration files (you can have them but they are not needed). When you open a file, projectile checks if it is under version control (git, mercurial). If it is, the project root becomes the directory under version control. Simple but efficient. Now you can search trough your project files or switch projects or find a file in a project.

snapshot2

The second example would be ibuffer with ibuffer-vc extension.  ibuffer is a emacs major mode that lists all buffers (opened files). With the extension, the buffers are grouped by their version control system project. Again: simple, but efficient.

snapshot1

The third example two of my own hacks (own customization) for python editing mode. I use both Python 2.7 and Python 3.4 and depend on virtualenv. I use syntax checking using the flymakes extension but the extension uses the default system python version which can get pretty annoying. Also, on some projects I use tabs as the default indendation and on others spaces but Emacs Python configuration is global. How to fix this, you ask? I implemented two simple hacks (I’m not really fond of them but they serve my needs). Before you say anything against hacking let me remind you that you probably tweaked your operating system because you hated the defaults. That’s hacking.

Spaces or tabs using projectile:

(setq py-spaces-projects '("project1" "project2"))

(setq auto-mode-alist (append '(("/*.\.py$" . python-mode)) auto-mode-alist))
(require 'projectile)

(defun python-mode-config ()
  (hook-mark-todo)
  (if (member (projectile-project-name) py-spaces-projects)
      (spaces-py-settings)
	(tabs-py-settings)))

(add-hook 'python-mode-hook 'python-mode-config)

(defun tabs-py-settings ()
  (interactive)
  (message "python: tabs")
  (setq indent-tabs-mode t)
  (setq python-indent 4)
  (setq tab-width 4))
(defun spaces-py-settings ()
  (interactive)
  (message "python: spaces")
  (setq indent-tabs-mode nil)
  (setq python-indent 4))

Syntax checking using virtualenv and projectile

This code is simple. If we are in a project and an virtual environment for that project exists (the names must mach, which in my case usually do) the code check if there is pyflakes installed. If it is, the pyflakes of the virtual environment is used, else the global one is (Python 2.7).

(defun virtualenv-flymake ()
  (defvar virtualenv-exec (concat "~/.virtualenvs/" (projectile-project-name) "/bin/pyflakes"))
  (if (file-exists-p virtualenv-exec)
      (setq flymake-python-pyflakes-executable virtualenv-exec)
	(setq flymake-python-pyflakes-executable "pyflakes"))
  (flymake-python-pyflakes-load))
(add-hook 'python-mode-hook 'virtualenv-flymake)

I am pretty much certain that all that code could be prettier or there is even a extension that solves my problem but I haven’t found a better solution yet (did not even bother much, these just work for me).