Spacemacs
I started using vim in 2008. It was at my second job after college. I had been doing Windows C++/C# development using exclusively Visual Studio for my entire career at that point. My second position was as a PHP developer.
The environment wasn’t completely foreign - I had cut my teeth using Unix-based systems (even having installed Slackware at one point on my Clone 486DX2 back in the 90’s; from floppy). I had been using PHP as a hobby language for a while as well; but this was the first time I had been around programmers who had been doing it this way as part of their careers.
The first day, the lead developer (a jovial chap with a long white beard) dropped me into a shell, and fired up vim. Vi had always been a scary thing for me. I would occasionally get dropped into it on accident, and fumble around for a bit before opening up nano or joe. I had never seen a vi power user in action. His fingers flew over the keyboard, and he moved around the source code SO FAST. I was somewhat in awe. That was the day my whole coding paradigm was flipped upside down.
A year later I was the lead engineer, and one day a new guy joined our team. I fired up vim and walked him through the code, he followed along nodding away. Then, as I went to go and observe how he was coming along, a strange thing occurred. He wasn’t using vim. His fingers weren’t flying over the keyboard. He kept hitting his control key, and strange magic would occur on his terminal. Windows full of data would appear. He would start randomly editing parts of the screen and things would just happen.
Obviously some kind of witchcraft. While what he did had power, it seemed slow; no match for my screen and vim. I scoffed. What is this you call it? emacs you say? Only a fool would forsake my macro-ing power. He scoffed right back from his own lofty perch, as he would type and run SQL queries right in his editor, rendering it in a table. Oh, that? It’s nothing.
Black magic. I have utilities that can do that. A text editor should be a pristine place where text editing occurs. These bells and whistles were unnecessary, and what is all of this control key nonsense? I was having none of this!
So, life went on. A decade passed. Vim has been replaced by Idea (with vi keybindings of course) and Linux is now my desktop; not just what I ssh into over a terminal from Windows. A while back I was reading the writings of an old-beard, going on and on about org-mode. I thought; what is this? The old emacs black magic is still alive and kicking?
At the time, in my headstrong youth, I had been too dumb to understand what emacs was under the surface; it’s real secret. The secret is that emacs isn’t really a text editor at all. It’s an interactive lisp workspace, with a focus on manipulating and working with text. Just because one of those things just happens to be editing buried the lead for me.
After my research, I was deeply intrigued. How can I have this kind of power I wondered. It turns out it was just an apt call away. Not only was it so close, it has a very decent GUI interface; halfway between a terminal and an application. There was only one problem. It was emacs, and I have 15 years of muscle memory trained for vi.
I wasn’t going to let this stop me. In the intervening years, I have not been the only programmer to have this issue - it is apparently very common. So, bold programmers have taken and bridged the gap between the emacs camp and the vim camp; coming up with an emacs configuration dubbed evil (obviously, since one camp views the other as priests of a different text-editing god…). This had been mentioned to me back long ago, but as the emacs programmer scoffed at it, it faded into my past as emacs had at the time.
So, one camp decided to take evil and run with it. Ran it all the way down, discarding the control key in favor of the spacebar, and instead of operating in a single mode like emacs normally would, operates in dual-mode (edit/command) like vim. This variation, they dubbed spacemacs.
I did have to do some things to get my environment set up:
# Installing emacs
sudo apt install emacs
# Installing fonts
[ -d /usr/share/fonts/opentype ] || sudo mkdir /usr/share/fonts/opentype
sudo git clone https://github.com/adobe-fonts/source-code-pro.git /usr/share/fonts/opentype/scp
sudo fc-cache -f -v
# Install flycheck
sudo apt install elpa-flycheck
# Install spacemacs
git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d
A pretty painless process. With my configuration set, spacemacs launched without issue; installing all of its own package dependencies from the emacs package repositories ELPA and MELPA.
Great, so now I have another text editor. So what? What is this killer app, this org-mode?
So first you have to learn a bit about spacemacs that wasn’t completely obvious because I can be a little thick. You see in the documentation SPC. That means hit the spacebar. Duh. Also, to complete what is generally obvious, C- or Ctrl- is a control key combo; M- or Alt- is an alt key combo.
org-mode stands for Organization Mode. It is the mode that emacs switches to when it opens a .org file. In spacemacs, you will see that it says Org at the bottom in the status bar. To enable all of this, use SPC f e d to edit your .spacemacs configuration file. Here are the layers I use. There are a lot of layer options out there, so you can tune the plugins for what your common usecases are.
;; List of configuration layers to load.
dotspacemacs-configuration-layers
'(
;; ----------------------------------------------------------------
;; Example of useful layers you may want to use right away.
;; Uncomment some layer names and press `SPC f e R' (Vim style) or
;; `M-m f e R' (Emacs style) to install them.
;; ----------------------------------------------------------------
auto-completion
better-defaults
emacs-lisp
git
helm
html
ipython-notebook
;; lsp
java
javascript
kotlin
latex
markdown
multiple-cursors
org
python
(shell :variables shell-default-height 30 shell-default-position 'bottom)
shell-scripts
spell-checking
syntax-checking
themes-megapack
treemacs
version-control
yaml
)
Once you have your layers set up, you set up your user configuration towards the bottom of the file. Here is what mine looks like. You can see it has a slew of custom TODO items, defines a directory where my org files are stored, sets up my python virtual environment, and a few other things.
(defun dotspacemacs/user-config ()
"Configuration for user code:
This function is called at the very end of Spacemacs startup, after layer
configuration.
Put your configuration code here, except for variables that should be set
before packages are loaded."
(setq org-link-abbrev-alist '(("yt" . "https://www.youtube.com/watch?v=")))
(setq org-startup-with-inline-images t)
(setq org-link-elisp-confirm-function nil)
(setq org-directory "~/myorg/")
(setq org-default-notes-file (concat org-directory "1.notes.org"))
(setq org-agenda-files (directory-files org-directory nil "^[^.][0-9]*.*\.org$" nil))
(setq org-agenda-todo-ignore-with-date t)
(setq org-todo-keywords '((sequence "TODO" "LOW-PRIORITY" "STARTED" "BLOCKED" "RESTARTED"
"POSTPONE" "PUSH" "|"
"IGNORE" "DELEGATED" "FINISHED" "CANCELLED" "FAILED")))
(setq org-todo-keyword-faces '(("TODO" . "deep sky blue") ("LOW-PRIORITY" . "navajo white")
("STARTED" . "green") ("BLOCKED" . "tomato")
("RESTARTED" . "green yellow") ("IGNORE" . "gray")
("POSTPONED", "deep sky blue") ("PUSH", "deep sky blue")
("DELEGATED" . "goldenrod") ("FINISHED" . "cyan")
("CANCELLED" . "gray") ("FAILED" . "orange red")))
(with-eval-after-load 'org
(org-babel-do-load-languages
'org-babel-load-languages
'(
(python . t)
)
)
)
(add-hook 'python-mode-hook (lambda () (pyvenv-workon "venv")))
)
If you want to use a virtual environment like I do, the home directory is set in ~/.spacemacs.env $WORKON_HOME.
Once you have made all your edits, you can save a file by hitting :w just like in vim. To copy, you use y and paste is p. You can even record macros with q. Select lines with V, etc. All the commands that vim’mers are used to are available (that I have tried at least).
If you ever get stuck in emacs you can get out of whatever you are doing by hitting Ctrl-G. If you ever want to run any of the full spectrum of commands available, you can use Alt-X to enter them directly, or browse what is available.
In org-mode, you structure a document by using collapsable trees (TAB toggles collapse). Items in trees can then be annotated in several ways. To create an item, you use *. One * creates a first level, ** creates a second level under the first, etc. While on an item you can hold Shift, and left/right will change the status; up/down will change the priority. , d t can add a timestamp to the entry. , a n will generate an agenda view. If you put hours on the timestamp, it will break your agenda down by hours. You can use Shift-up/down to change a date while you have a cursor on a part of the date.
You can also make lists underneath a heading by using - If you make a [ ] in a list, you can check and uncheck using Ctrl-c Ctrl-c. If you have a list with checkboxes, and you add [/] in the heading and hit Ctrl-c Ctrl-c it will populate it with the number of completed/total items. Pretty clever.
You can also link files, or urls. To do that you use the form [[url/file path][displayname]]. You can create all sorts of fancy actions using namespace prefixes. For example [[shell:…]] will run something in a bash shell; [[elisp:…]] will run some lisp code.
* Daily Goals
** Plan
*** Create Weekly Plan
<2022-02-21 Mon 07:30>
** Exercise
*** Run
<2022-02-21 Mon 12:00>
** Writing
*** TODO [x0] Keep up with your journal
*** [0/1] Post on your blog
- [ ] Write post on Emacs
<2022-02-21 Mon 20:00>
Another fun feature of org-mode is you can embed code right in the file. I wrote a little weather report generator that I use to collect the weather from the NOAA. Ctrl-c Ctrl-c runs the code in the block, and it updates the labeled #+RESULTS.
;; -*- mode: org; org-activate-links: '(angle plain radio tag date footnote); -*-
#+TITLE: a. Weekly Weather Report
#+description: Thanks NOAA
* Weather Report
#+RESULTS: weather
|----------------------------------------------------------------|
| Washington's Birthday, February 21, 2022 |
|----------------------------------------------------------------|
| 70F - 33F |
| Partly Sunny then Slight Chance Drizzle, 12 to 20 mph S |
| Slight Chance T-storms then Chance Light Rain, 9 to 15 mph WSW |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Tuesday, February 22, 2022 |
|----------------------------------------------------------------|
| 34F - 12F |
| Mostly Sunny, 16 to 20 mph NW |
| Mostly Clear, 12 to 15 mph NNW |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Wednesday, February 23, 2022 |
|----------------------------------------------------------------|
| 27F - 19F |
| Mostly Sunny then Chance Light Snow, 13 mph NNE |
| Chance Light Snow, 10 mph NE |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Thursday, February 24, 2022 |
|----------------------------------------------------------------|
| 26F - 12F |
| Light Snow Likely, 10 to 14 mph NNE |
| Slight Chance Light Snow then Mostly Cloudy, 10 mph NNW |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Friday, February 25, 2022 |
|----------------------------------------------------------------|
| 29F - 10F |
| Mostly Sunny, 7 to 13 mph NNW |
| Partly Cloudy, 5 mph N |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Saturday, February 26, 2022 |
|----------------------------------------------------------------|
| 36F - 18F |
| Mostly Sunny, 2 to 8 mph S |
| Partly Cloudy, 6 mph SW |
|----------------------------------------------------------------|
|----------------------------------------------------------------|
| Sunday, February 27, 2022 |
|----------------------------------------------------------------|
| 43F - 16F |
| Sunny, 6 to 14 mph WNW |
| Mostly Clear, 7 mph N |
|----------------------------------------------------------------|
* IGNORE Python
#+name: weather
#+begin_src python :exports both :results value table :return data
# https://www.weather.gov/documentation/services-web-api
import json
import requests
import numpy as np
import pandas as pd
from datetime import datetime
api_url = 'https://api.weather.gov/gridpoints/EAX/43,19/forecast'
response = requests.get(api_url)
results = json.loads(response.text)
def to_day(datestr):
return datetime.strptime(datestr, "%Y-%m-%dT%H:%M:%S%z")
dataset = pd.DataFrame([[ r['number'], r['name'],
f"{r['temperature']}{r['temperatureUnit']}",
f"{r['windSpeed']} {r['windDirection']}",
r['shortForecast'],
to_day(r['startTime']), r['isDaytime']
] for r in results.get('properties').get('periods')
])
dataset['dateval'] = dataset[5].dt.date
fmt = lambda ds: [None, list(ds)] + [None] + ds.values.tolist() + [None]
a = dataset[dataset[6] == True][[1,2,3,4,5,'dateval']]
b = dataset[dataset[6] == False][[1,2,3,4,5,'dateval']]
aligned = pd.merge_ordered(a, b, how='outer', on='dateval', suffixes=['_m', '_e'])
aligned['name'] = np.where(aligned['1_m'].notna(), aligned['1_m'], aligned['1_e'])
aligned['day'] = np.where(aligned['5_m'].notna(), aligned['5_m'].dt.strftime('%B %d, %Y'), aligned['5_e'].dt.strftime('%B %d, %Y'))
aligned['name'] = aligned['name'] + ', ' + aligned['day']
aligned['temp'] = aligned[['2_m', '2_e']].fillna('?').agg(' - '.join, axis=1)
aligned['weather'] = aligned[['4_m', '3_m']].fillna('?').agg(', '.join, axis=1)
aligned['overnight'] = aligned[['4_e', '3_e']].fillna('?').agg(', '.join, axis=1)
aligned = aligned[['name', 'temp', 'weather', 'overnight']].set_index('name')
stacks = []
w = 1
s = aligned.shape[0]
data = []
for i in range(0, s, w):
data.extend(fmt(aligned[i:i+w].T))
#+end_src
So, I have to admit. I was wrong. Emacs is really cool. I still fire up vim if I’m in a terminal or a remote machine, but spacemacs is now the first thing I open in the morning. I use it for TODO lists, to organize my day, to build shopping lists that I then can sync to my devices (Check out the Orgzly app). It packs so much power and is so open-ended; it makes the perfect platform to just do stuff from. It is also so lightweight, portable, broadly supported, and free. In the short time I have been using it, it really has changed the way I live more than almost any other tool I have ever used.
The learning curve is a little steep. Getting caught up with how buffers work (SPC b b lists your open buffers), and the fact that files stay open, and may not be saved, windows sometimes just clobber eachother… It gives you all the rope you could need to hang yourself. Not to mention this is just scratching the very surface of the modules what you can integrate with emacs. There is a whole git management layer, projects, source editing and running, workspaces, so many links, commands, plugins. My god. If you keep good backups, and save often, you should be fine. Famous last words.
Emacs Command Cheatsheet
I found this somewhere, but keep it in one of my org documents.
- Switch Mode/Run command -
M-x mode-name - Undo -
C-/ - Redo -
C-? - Change case:
- Camel Case :
M-c - Upper Case :
M-u - Lower Case :
M-l
- Camel Case :
- Helm-projectile find file :
M-m p f - Helm-projectile-grep :
M-m p s g - Toggle Auto complete :
M-m t a - Neotree root directory :
M-m p t - Linum-relative :
M-m t r - Ace-jump mode :
M-m SPC - Helm-bookmarks :
M-m h b - Iedit mode :
M-<left>,M-<right>to navigate,C-;to select/deselct all for edit at once
- Expand Region
- Expand:
M-m v - Contract:
M-m V
- Expand:
- Winner mode:
- Undo :
C-c <left> - Redo :
C-c <right>
- Undo :
- Toggle Aggressive Indent Mode :
M-m t I - Open file in new buffer after
M-m p f:C-c o - Dired mode :
- Copy file :
C - Delete the file :
D - Rename the file :
R - Create a new directory :
+ - Reload directory listing :
g
- Copy file :
- Search :
- The last searched query :
C-s C-s - The string under the cursor :
C-s C-w
- The last searched query :
- Un-indent by 4 spaces :
C-u -4 C-x TAB - Open emacs dired mode:
M-m a d - Erase contents of buffer:
M-m b e - Replace contents of buffer with the contents of the clipboard:
M-m b P - Copy contents of the whole buffer:
M-m b Y - Open current file directory:
M-m f j - Rename current file:
M-m f R - Indent region/buffer:
M-m j = - Kill all buffers (of current project):
M-m p k - Reload spacemacs conf:
M-m f e R - Kill all buffers except the current one:
M-m b K - Go to conf file (~/.spacemacs):
M-m f e d - Toggle display fill-column(column 80):
M-m t f - Enable/Disable read-only mode
C-x C-q - Go one level up in directory:
C-x C-j - Indent/unindent region by n/-n spaces(n=4,8,… usually):
C-u <n> C-x TAB - Go to previous cursor position(before ace-jump): `M-m SPC ``
- Do ag (code search) inside project :
M-m s a p - Narrow to function :
M-m n f(M-m n wto exit) - Enable rainbow mode:
M-m t C c - Search selected region or current word through ag in project:
M-m s p - Highlight search results in another buffer (helm swoop):
M-m s s(M-m s sto exit) - Toggle current frame transparency:
M-m T T - Toggle non-matching lines for iedit mode:
C-'when in iedit mode (C-;) - Helm-resume background task:
M-m h l - Enter .spacemacs diff mode:
M-m f e D - Show kill ring history:
M-m r y - When in dired mode, press
?to display a list of commands. - Search within given buffer (helm-swoop mode):
M-m s s