Emacs as a programming IDE

Marie-Hélène Burle

November 14, 2023


I am not trying to start an editor war here

https://cube-drone.com

Particularly as there are now excellent IDEs for Python, Julia, and R without Emacs learning curve (think VS Code, RStudio, or JupyterLab)

Why I still use (and love) Emacs

Bookmarking

Fully customizable

Kbd for everything

Org mode (org tables!)

Organization of windows

Search and replace with regexp

Macros

Emacs everywhere (emails, Slack, Telegram with mu4e, emacs-slack, telega)

Helm

Searching in buffer

Navigating open buffers and recent files

Navigating file sections

Selecting from kill ring

Moving in mark ring

Looking at active modes

Completion

company-mode

Undoing/redoing with undo-tree

Linear systems: classic undo/redo


flowchart TD
   1((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Have some file

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make some edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make more edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make more edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Can undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current---3((" "))---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Undo some more

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Can redo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))-.-4((" ")):::lost
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4


Make new edits

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4


Can still undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" ")):::current---3((" "))-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4


Can still undo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" ")):::current-.-4((" ")):::lost
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4


And can redo

Linear systems: classic undo/redo


flowchart TD
   1((" "))---2((" "))---3((" "))-.-4((" ")):::lost
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px
   classDef lost stroke-dasharray: 3 4


But some edits are forever lost

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1)):::current
   classDef current stroke: #f96, stroke-width: 2px

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2)):::current
   classDef current stroke: #f96, stroke-width: 2px


Make some edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3)):::current
   classDef current stroke: #f96, stroke-width: 2px


Make more edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4)):::current
   classDef current stroke: #f96, stroke-width: 2px


Make more edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3)):::current
   classDef current stroke: #f96, stroke-width: 2px


The first undo adds a new point to the chain of edits

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2)):::current
   classDef current stroke: #f96, stroke-width: 2px


More undoing keeps adding points to the chain

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3)):::current
   classDef current stroke: #f96, stroke-width: 2px


There is no redo: you stop undoing, then start again to undo the undo

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3))---8((5)):::current
   classDef current stroke: #f96, stroke-width: 2px


You can make new edits

Nothing ever gets lost, but you might get headaches

Example: let’s go back to the starting point

Linear systems: Emacs

%%{init: { 'flowchart': {'rankSpacing':15} } }%%
flowchart TD
   1((1))---2((2))---3((3))---4((4))---5((3))---6((2))---7((3))---8((5))---9((3))---10((2))---11((3))---12((4))---13((3))---14((2))---15((1)):::current
   classDef current stroke: #f96, stroke-width: 2px

Non linear system: undo-tree


flowchart TD
   1((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make some edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" ")):::current---3((" "))---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" ")):::current---4((" "))
   classDef current stroke: #f96, stroke-width: 2px


Redo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" "))
   3((" "))---5((" ")):::current
   classDef current stroke: #f96, stroke-width: 2px


Make new edits

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" "))
   3((" ")):::current---5((" "))
   classDef current stroke: #f96, stroke-width: 2px


Undo

Non linear system: undo-tree


flowchart TD
   1((" "))---2((" "))---3((" "))---4((" ")):::current
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px


Switch branch and redo the old version

Non linear system: undo-tree


flowchart TD
   1((" ")):::current---2((" "))---3((" "))---4((" "))
   3((" "))---5((" "))
   classDef current stroke: #f96, stroke-width: 2px


Nothing gets lost and it is more sane to navigate the history

Emacs with Python

Emacs comes with a Python mode that provides syntax highlighting. For a full IDE experience, there are multiple options, the most popular of which being the elpy package

Code from matplotlib

Emacs with R

R is—as Emacs—GNU software and has been integrated with Emacs via the ESS (Emacs Speaks Statistics) package for a very long time

Emacs with Julia

The julia-mode package provides syntax highlighting and the julia-repl package implements a fully functional Julia REPL, optionally with the emacs-libvterm package

Code from Beautiful Makie

ESS also provides an IDE for Julia, but it does not allow for the funky Julia-specific REPL

Another sophisticated option is to use julia-mode with the julia-snail package