A Space Menu for Lem

SPC

This can be added to your ~/.lem/init.lisp to add a space menu to lem. It's similar in spirit to the space menu from Spacemacs. It is much smaller, but it can be used as a starting point for your own space menu.

;; SPC b
(defvar *space-b-keymap*
  (make-keymap :name '*space-b-keymap*)
  "buffer menu")
(define-keys *space-b-keymap*
  ("b" 'lem-core/commands/window:select-buffer)
  ("d" 'lem-core/commands/window:kill-buffer)
  ("n" 'lem-core/commands/window:next-buffer)
  ("p" 'lem-core/commands/window:previous-buffer)
  ("r" 'lem-core/commands/file:revert-buffer))
;; SPC f
(defvar *space-f-keymap*
  (make-keymap :name '*space-f-keymap*)
  "file menu")
(define-keys *space-f-keymap*
  ("f" 'lem-core/commands/file:find-file)
  ("F" 'lem-core/commands/file:find-file-recursively)
  ("t" 'lem/filer::filer))
;; SPC g
(defvar *space-g-keymap*
  (make-keymap :name '*space-g-keymap*)
  "git menu")
(define-keys *space-g-keymap*
  ("s" 'lem/legit::legit-status))
;; SPC h
(defvar *space-h-keymap*
  (make-keymap :name '*space-h-keymap*)
  "help menu")
(define-keys *space-h-keymap*
  ("a" 'lem-lisp-mode/internal:lisp-apropos-all)
  ("b" 'lem-core/commands/help::describe-bindings)
  ("f" 'lem-lisp-mode/internal:lisp-describe-symbol)
  ("k" 'lem-core/commands/help::describe-key)
  ("m" 'lem-core/commands/help::describe-mode))
;; SPC j
(defvar *space-j-keymap*
  (make-keymap :name '*space-j-keymap*)
  "jump menu")
(define-keys *space-j-keymap*
  ("i" 'lem/detective:detective-all))
;; SPC p
(defvar *space-p-keymap*
  (make-keymap :name '*space-p-keymap*)
  "project menu")
(define-keys *space-p-keymap*
  ("f" 'lem-core/commands/project:project-find-file)
  ("p" 'lem-core/commands/project:project-switch)
  ("g" 'lem/grep::project-grep)
  ("s" 'lem-core/commands/project:project-save)
  ("t" 'lem/filer::filer)
  ("u" 'lem-core/commands/project:project-unsave))
;; SPC t
(defvar *space-t-keymap*
  (make-keymap :name '*space-t-keymap*)
  "toggle menu")
(define-keys *space-t-keymap*
  ("f" 'lem-core/commands/frame:toggle-frame-fullscreen)
  ("n" 'lem/line-numbers:toggle-line-numbers)
  ("p" 'lem/show-paren::toggle-show-paren)
  ("s" 'lem-core::list-color-themes)
  ("w" 'lem-core/commands/window::toggle-line-wrap))
;; SPC w
(defvar *space-w-keymap*
  (make-keymap :name '*space-w-keymap*)
  "window menu")
(define-keys *space-w-keymap*
  ("0" 'lem-core/commands/window:delete-active-window)
  ("1" 'lem-core/commands/window:delete-other-windows)
  ("h" 'lem-core/commands/window:window-move-left)
  ("j" 'lem-core/commands/window:window-move-down)
  ("k" 'lem-core/commands/window:window-move-up)
  ("l" 'lem-core/commands/window:window-move-right)
  ("n" 'lem-core/commands/window:next-window)
  ("p" 'lem-core/commands/window:previous-window)
  ("-" 'lem-core/commands/window:split-active-window-vertically)
  ("/" 'lem-core/commands/window:split-active-window-horizontally))
;; SPC
(defvar *space-keymap*
  (make-keymap :name '*space-keymap*)
  "The root keymap for the space menu.")
(define-keys *space-keymap*
  ("b" *space-b-keymap*)
  ("f" *space-f-keymap*)
  ("g" *space-g-keymap*)
  ("h" *space-h-keymap*)
  ("j" *space-j-keymap*)
  ("p" *space-p-keymap*)
  ("t" *space-t-keymap*)
  ("w" *space-w-keymap*)
  ("'" 'lem-terminal/terminal-mode::terminal)
  ("Space" 'lem-core/commands/other:execute-command))
(define-key lem-vi-mode:*normal-keymap* "Space" *space-keymap*) ; leader
(define-key lem-vi-mode:*insert-keymap* "M-m" *space-keymap*)   ; alternative leader

Keybindings

Key Menu
b buffer
f file
g git
h help
j jump
p project
t toggle
w window
Key Binding
SPC b b select-buffer
SPC b d kill-buffer
SPC b n next-buffer
SPC b p previous-buffer
SPC b r revert-buffer
SPC f f find-file
SPC f F find-file-recursively
SPC f t filer
SPC g s legit-status
SPC h a apropos-all
SPC h b describe-bindings
SPC h f describe-symbol
SPC h k describe-key
SPC h m describe-mode
SPC j i detective-all
SPC p f project-find-file
SPC p p project-switch
SPC p g project-grep
SPC p s project-save
SPC p t filer
SPC p u project-unsave
SPC t f toggle-frame-fullscreen
SPC t n toggle-line-numbers
SPC t p toggle-show-parens
SPC t s list-color-themes
SPC t w toggle-line-wrap
SPC w 0 delete-active-window
SPC w 1 delete-other-windows
SPC w h window-move-left
SPC w j window-move-down
SPC w k window-move-up
SPC w l window-move-right
SPC w n next-window
SPC w p previous-window
SPC w - split-active-window-vertically
SPC w / split-active-window-horizontally
SPC ' terminal
SPC SPC M-x

Other Keybindings

Frames Are Like Browser Tabs

It's a bit unfortunate that Emacs uses the word "window" to mean "pane", and "frame" to mean "window" in contemporary parlance. Lem seemed to use the words "window" and "frame" the same way Emacs did at first. However, upon closer inspection, frames in Lem are more like tabs than independent windows.

In light of this, here are some bindings that make use of your pre-existing muscle memory from tab management in web browsers. Ctrl-Shift-N will create a new frame which is kind of like a tab in Lem, and Ctrl-PgUp and Ctrl-PgDn will move between frames. This should feel familiar. (I sometimes think I should put it on Ctrl-Shift-T, but N feels better to my hands.)

1
2
3
4
(define-keys *global-keymap*
  ("C-N" 'lem/frame-multiplexer:frame-multiplexer-create-with-new-buffer-list)
  ("C-PageDown" 'lem/frame-multiplexer:frame-multiplexer-next)
  ("C-PageUp" 'lem/frame-multiplexer:frame-multiplexer-prev))

Note that this is only useful for the sdl2 version of Lem. If you're running the ncurses Lem in a terminal, these keybindings are probably already taken by the terminal itself.

Pasting

I often Shift-Insert to paste particularly while using Emacs. This lets me continue to lean on that muscle memory while using Lem. Although I use vi-paste-after, it works as expected in emacs-mode too.

Outside of Emacs, I often use Ctrl-Shift-V to paste too. I'm going to make them both available to me in Lem.

1
2
3
(define-keys *global-keymap*
  ("Shift-Insert" 'lem-vi-mode/commands:vi-paste-after)
  ("C-V" 'lem-vi-mode/commands:vi-paste-after))

Again, these bindings are only useful in sdl2. In the terminal, these keys are probably already bound to the terminal itself, and Lem will never see them.

C-h Bindings Like Emacs

Coming from Emacs, I expected to find some bindings off of C-h that would help me introspect Lem. By scanning through M-x's completions, I saw that similar functions existed, but they weren't bound to anything as far as I could tell. If you were looking for some familiar keybindings off of C-h like I was, try putting this in your ~/.lem/init.lisp.

1
2
3
4
5
6
(define-keys *global-keymap*
  ("C-h a" 'lem-lisp-mode/internal:lisp-apropos-all)
  ("C-h b" 'lem-core/commands/help::describe-bindings)
  ("C-h f" 'lem-lisp-mode/internal:lisp-describe-symbol)
  ("C-h k" 'lem-core/commands/help::describe-key)
  ("C-h m" 'lem-core/commands/help::describe-mode))

It's not exactly the same as Emacs, but it's close enough in spirit. I think this will help people coming from Emacs learn how to use Lem.

Common Lisp REPL History

In the REPL, it took me a while before I discovered that the keys for navigating the REPL history were on M-p and M-n. I prefer using arrow keys instead.

1
2
3
(define-keys lem/listener-mode:*listener-mode-keymap*
  ("Up" 'lem/listener-mode:listener-previous-input)
  ("Down" 'lem/listener-mode:listener-next-input))
Edit

Pub: 31 Aug 2024 11:27 UTC

Edit: 03 Oct 2024 07:12 UTC

Views: 10594