Lem
GitHubDiscord Matrix Toggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Usage

The documentation is in progress. You can find a list of available keys and commands in keybindings, and you can get this list in Lem itself with M-x documentation-describe-bindings (new in Lem 2.1).

Lem Manual for Users

Lem has Emacs-like keybindings, as well as a vi emulation (M-x vi-mode).

So, to open a file, press C-x C-f (you get the file selection dialog shown above). To save it, it’s C-x C-s. To save many buffers at once, use C-x s.

To switch windows (aka splits of a screen): C-x o (‘o’ letter) and M-o. To make a window fullscreen: C-x 1. To split it vertically: C-x 3 and horizontally: C-x 2. To make the current window disappear: C-x 0 (zero).

To switch buffers: C-x b.

To run an interactive command by name: M-x (alt-x).

To show the context menu: Shift-F10.

Quit Lem with C-x C-c.

See this Emacs & Slime cheatsheet to find more: https://lispcookbook.github.io/cl-cookbook/emacs-ide.html#appendix

Opening files

As said above, the shortcut to open a file is C-x C-f (aka M-x find-file). This presents a dialog to choose a file, with autocompletion, starting at the buffer’s directory. We can also search for files in a project or recursively in subdirectories.

You can open a file in another “window”, aka if Lem’s screen is split in two, open the file in the other screen. Use C-x 4 f (M-x find-file-other-window). This splits the screen vertically if needed.

You can then resize the windows. Look for the “shrink-” and “grow-” commands.

Filer - project explorer

This feature was added in Lem 2.1

The shortcut C-x d opens a project explorer on the left side. Another keypress closes the Filer.

Lem Filer on the left window

Find file in project

Project related commands were added in Lem 2.1

Use M-x project-find-file to choose a file among the list of all files pertaining to the current project. This command is bound to C-x p f.

A project is recognized by typical files or directories. For example, a directory containing a .git/ subdirectory or a .project, .projectile, .ignore, configure.ac or Makefile file is considered the root of a project. The actual list is a bit longer, it should “just work”.

When you call the project-find-file command, Lem looks at the buffer’s working directory if it recognizes a project root. If not, it goes up one directory and looks again, and continually until finding a project root. It stops at the home directory.

If no project root was found, Lem uses the buffer’s directory.

There are also the commands:

CommandKey-combinationFunction
project-kill-buffersC-x p Kdelete all this project’s buffers
project-rootdisplay the project root
project-find-file-next-windowC-x 4 p fopen a file in another window
project-root-directoryC-x p dopen the project root with Lem’s directory-mode
project-root-directory-next-windowopen the project root in another window

These commands allow to switch between projects:

CommandKey-combinationFunction
project-saveC-x p ssave the current project. This populates the text file on (lem-home)/history/projects.
project-switchC-x p pchoose a saved project and find a file in it
project-unsaveC-x p uremove a project from the history

Configuration:

  • for project-kill-buffers:
    • if *delete-repl-buffer* is non t, we don’t delete the REPL buffer.
    • if *delete-last-buffer* is non nil, we will delete the last buffer. This would cause Lem to exit.

The filer (C-x d, see above) opens the project root.

The project’s file chooser will try to use the fdfind program to list the project files. In that case, common development directories such as .git/ and node_modules/ will be excluded. Read more below.

Find file recursively

find-file-recursively was added in Lem 2.1

The command find-file-recursively is not bound to a key by default. This command opens a selection prompt and lists all files under the buffer’s directory, recursively, letting you choose and open a file deep in the directory tree quickly.

Note: contrary to project-find-file, it starts the search at the buffer’s directory, not at the project root.

The method to search all files recursively is configurable. Lem first tries with any of these external programs: fd, fdfind (which is fd installed from Debian repositories) and find (the Unix find). If none of these programs exist, it falls back to a Lisp version.

fd is an external tool, that is fast and that filters out some directories by default: “node_modules/”, “.git/” and such. The Lisp method doesn’t exclude them.

But what happens if you call this command on your HOME, or in a directory with lots and lots of files? The command has a 5 seconds timeout (by default). After that time, the process is aborted and Lem uses the simpler find-file command.

Configuration

You can bind the command to a keybinding:

(lem:define-key lem:*global-keymap* "C-x F" 'lem-core/commands/file:find-file-recursively)

The variables and methods are inside the Lisp package :lem-core/commands/file.

You can change the order of the finder programs:

;; these must be keywords, not strings.
(setf *find-programs* (list :fdfind :fd :find :lisp))

or choose the one to use:

(setf *find-program* :lisp)

You can change the timeout:

(setf *find-program-timeout* 5)

and change the behaviour of the methods that return the list of files and directories. They are written as CLOS generic methods specializing on the *find-program* keyword, so you can use :before, :around or :after qualifiers.

(defmethod get-files-recursively :around ((finder (eql :lisp)))
  (let ((results (call-next-method)))
     (do-something-with-the-results)))

Buffers, windows and workspaces management

Switching buffers

To switch buffers, use C-x Left/Right arrow (aka M-x previous-buffer and next-buffer).

To choose a buffer interactively, use C-x b (aka M-x list-buffers). You are presented a completion window. Type some text to start narrowing the buffers list matching your entry. But that’s not all.

You can also use Space to select or deselect entries, then use a right click to choose an action to apply on the selected buffers. Default actions are to kill the selected buffers, or to save them.

Creating new buffers

A buffer contains some text to display, but is not necessarily tied to a file.

Try using the C-x b command and typing the name of a buffer that doesn’t exist. Lem will ask confirmation to create it. If you confirm, you’ll get a buffer that is not tied to a file on your filesystem. You can write whatever you want, as well as enable a major mode (M-x lisp-mode, M-x markdown-mode…). You’ll note that the command C-x C-s (save-current-buffer) doesn’t work, saying “No file name”. This is correct, no file is associated to this buffer. To save this buffer to a new file, use C-x C-w (M-x write-file). It asks for a filename, and saves the buffer to disk.

Windows

A Lem “screen” can be divided into multiple windows.

To split your screen vertically and have two vertical windows, use C-x 3. To do so horizontally, use C-x 2. You can divide your screen into any number of windows you like.

To widen the current window, use C-x 1 (delete-other-windows). This deletes other windows, but not their buffers.

To make the current window disappear, use C-x 0 (a zero) (delete-active-window).

To switch windows (aka splits of a screen), use C-x o (‘o’ letter) or M-o.

To switch to the previously active window, use M-x switch-to-last-focused-window, which is not bound to a key by default.

These other commands are not bound to a key:

CommandKey-combinationFunction
window-move-down/upGo to the window at the bottom / at the top
window-move-left/rightGo to the window at the left / at the right

Tabs

Lem has a rudimentary support for tabs.

Activate the tab bar with M-x toggle-tabbar. This shows a tab for every buffer.

On the GUI version of Lem, you can click on them.

Workspaces

Lem has a frame multiplexer, aka “workspaces” or “screen manager”.

This feature allows to create many workspaces, or screen configurations, on the same Lem instance. We can create a new workspace, open buffers and arrange the window as we like (split vertically, horizontally…), and switch to another workspace where the window arrangement and the displayed buffers are different.

The frame multiplexer bindings start with C-z:

CommandKey-combinationFunction
frame-multiplexer-create-with-new-buffer-listC-z ccreate a new workspace
frame-multiplexer-nextC-z ngo to the next workspace
frame-multiplexer-prevC-z pgo to the previous workspace
frame-multiplexer-deleteC-z ddelete the current workspace
toggle-frame-multiplexerenable or disable (and loose) all workspaces

The frame multiplexer is enabled by default. It shows a buffer indicator on the top left corner of the editor.

You can disable it with M-x toggle-frame-multiplexer.

Well, if you want to be sure, add this in your Lem init file (~/.lem/init.lisp or ~/.config/lem/init.lisp since Lem 2.2):

 (remove-hook *after-init-hook* 'lem/frame-multiplexer::enable-frame-multiplexer)

vi and emacs modes

Use M-x vi-mode and M-x emacs-mode.

You can also start Lem in any given mode, see the configuration section.

Auto-completion (abbrev)

Lem has a system of abbreviation that permits to auto-complete any text that was previously entered in any text buffer.

By default, abbrev is bound to M-/

In vi’s insert-mode, it is also bound to C-p.

There is also the command abbrev-with-popup-window that shows the list of completion candidates. It is not bound by default. We can bind it to a key:

;; C-n is originally bound to next-line.
(define-key *global-keymap* "C-n" 'lem/abbrev:abbrev-with-pop-up-window)

and in vi-mode:

;; C-n is originally bound to next-line.
(define-key lem-vi-mode:*insert-keymap* "C-n" 'lem/abbrev:abbrev-with-pop-up-window)

Describe keys

To know what function is bound to a key binding, use C-x ? (M-x describe-key).

Describe and list available bindings

To see the available key bindings in the current keymap, use M-x describe-bindings.

You can use M-x describe-mode to understand in which mode the editor is in the current buffer.

You can do more and list all Lem’s existing keybindings with M-x documentation-describe-bindings. It inspects Lem and lists keybindings, grouped by modes:

  • move, edit, mark, word, S-expressions, file, buffer, window, multiple-cursors, process, help, font and other.

Note: this command was added in Lem 2.1.

grep

M-x grep

this presents the results in a two-panes window. You can edit lines in the results buffer, changes are reflected immediately on the files, and updated on the right side. You can use search and replace M-x query-replace in the results buffer.

multiple cursors

Use M-C (Alt and capital c), M-x add-cursors-to-next-line to add a cursor to the next line.

Lem will recognize some forms of links, specifically URLs and links to files, and will write them with a special face attribute (in my case, an underscore). You can open such a link with the command M-x open-link (not bound to a key by default).

  • URL: opens your web browser
  • file (the link must start with file://): Lem opens the file.

Misc

Try:

  • M-x toggle-line-numbers
    • or (lem/line-numbers:toggle-line-numbers)
    • use (setf lem/line-numbers:*relative-line* t) to use relative line numbers (added after Lem 2.1)
  • M-x toggle-read-only
    • (lem-core/commands/buffer:toggle-read-only)
  • M-x toggle-auto-save
    • (lem/auto-save:toggle-auto-save)
  • M-x toggle-frame-fullscreen

Set a transparent background with this line in your init file:

(sdl2-ffi.functions:sdl-set-window-opacity (lem-sdl2::display-window lem-sdl2::*display*) 0.9)