LionyxML/emacs-solo

A Pure Emacs (no external packages) IDE like configuration.

588

stars

720

commits

Emacs Lisp

primary language

Sep 10, 2026

updated

config
configuration
emacs
Browse cluster: Configuration file parsing and management

README

#+AUTHOR: Rahul Martim Juliato
#+EMAIL: rahul.juliato@gmail.com
#+OPTIONS: toc: nil

#+HTML: <p align="center">
#+HTML:   <img src="https://github.com/LionyxML/emacs-solo/releases/download/assets/emacs-solo-logo.png" alt="Project Logo" width="300"/>
#+HTML:   <br/>
#+HTML:   <img src="https://img.shields.io/badge/Emacs-31%2B-green.svg" alt="Emacs 31+"/>
#+HTML:   <img src="https://img.shields.io/badge/License-GPLv3-blue.svg" alt="GPLv3 License"/>
#+HTML: </p>

#+HTML: <p align="center">
#+HTML:   A <em>fast</em>, <em>powerful</em> and <em>modular</em> Emacs configuration that favors built-in functionality over third-party packages.
#+HTML: </p>

#+HTML: <p align="center">
#+HTML:   <a href="#obligatory-screenshots"><strong>Screenshots</strong></a> ·
#+HTML:   <a href="#as-seen-on-system-crafters"><strong>System Crafters Demo</strong></a> ·
#+HTML:   <a href="#minimum-emacs-version"><strong>Emacs Version</strong></a> ·
#+HTML:   <a href="#optional-dependencies"><strong>Optional Dependencies</strong></a> ·
#+HTML:   <a href="#installation"><strong>Installation</strong></a> ·
#+HTML:   <a href="#disclaimer"><strong>Disclaimer</strong></a> ·
#+HTML:   <a href="#how-do-i"><strong>FAQ</strong></a>
#+HTML: </p>

#+HTML: <hr />

* Emacs Solo

This is what you see as soon as you start Emacs:


#+BEGIN_SRC elisp
  ███████╗███╗   ███╗ █████╗  ██████╗███████╗    ███████╗ ██████╗ ██╗      ██████╗
  ██╔════╝████╗ ████║██╔══██╗██╔════╝██╔════╝    ██╔════╝██╔═══██╗██║     ██╔═══██╗
  █████╗  ██╔████╔██║███████║██║     ███████╗    ███████╗██║   ██║██║     ██║   ██║
  ██╔══╝  ██║╚██╔╝██║██╔══██║██║     ╚════██║    ╚════██║██║   ██║██║     ██║   ██║
  ███████╗██║ ╚═╝ ██║██║  ██║╚██████╗███████║    ███████║╚██████╔╝███████╗╚██████╔╝
  ╚══════╝╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝

    Loading time : 0.172725 seconds
    Packages     : 0
#+END_SRC


Emacs Solo is a configuration I use when I want to go back to the
roots and challenge myself by using Emacs with only built-in features.


It aims to be minimalist, at least in spirit. Yes, there are over 3000
lines of code, but most of that comes from organizing things cleanly
and building small, reusable modules. Compared to full-featured
distributions, it's still lean and focused.


The configuration favors Emacs built-ins, configured my way. But when
something essential is missing (like margin git gutters), a small,
hacky workaround is always added.

** Obligatory Screenshots

*** Overall View:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-01-overall.png]]

#+html:<details open>
#+html:<summary><h3>More screenshots here...</h3></summary>

*** iComplete (in buffer completion) + Flymake + Gutter:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-02-icomplete-flymake-gutter.png]]

*** Help Variable:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-03-help-var.png]]

*** iComplete Vertical:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-04-icomplete-vertical.png]]

*** Eshell:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-05-eshell.png]]

*** Dired + Gutter:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-06-dired-with-gutter.png]]

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-07-dired-with-gutter-2.png]]

*** Well behaved mode-line:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-08-mode-line.png]]

*** In Emacs Solo you find configurations for:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-09-single-init-file-with-sections.png]]

*** Emacs Solo also has a lot of extra mini-packages built-in:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-10-single-init-file-with-sections-2.png]]

You can use =C-c d= or =M-x container-menu RET= to open a podman / docker
container manager.

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-12-container-management.png]]


Or you can use =C-c G= or =M-x gh-menu RET= to open a =gh= (github cli) UI:

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-13-gh-1.png]]

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-13-gh-2.png]]


Emacs Solo also ships with some very cool themes!

We've got:

**** Crafters
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-crafters.png]]

**** Catppuccin
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-catppuccin.png]]

**** GITS
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-gits.png]]

**** Matrix
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-matrix.png]]

And much more!

#+html:</details>

** As seen on System Crafters!

Also, check out the full demo of =Emacs Solo= in action, as seen on
the System Crafters channel. In this video, David Wilson explores and
learns from the configuration, showing how different settings and
approaches are applied to create a more efficient and personalized
Emacs setup.

[[https://www.youtube.com/live/j_2QkCcf8zE?si=e8qvIFdyuV9j7d_y&t=1433][file:http://img.youtube.com/vi/j_2QkCcf8zE/0.jpg]]

** Minimum Emacs Version

Emacs Solo always requires the latest stable release of Emacs, which
is currently: =31.1=

However, some bleeding-edge features may be tested as well. For those,
you’ll need to compile Emacs from the master branch. I do my best to
mark these features with the =EMACS-32= tag.

** Optional Dependencies

It is recommended you have these programs in your system:

- =ripgrep= (rg)

  This provides quicker project grep and xref navigation.

  If you opt to use regular =grep=, reset the customization of variable
  =grep-command=.


- =ghostscript=

  This is necessary if you want to be able to use =doc-view= to see
  documents like PDFs.


- =gls=

  MacOS comes with an implementation of =ls= that misses some nice
  switches from the gnu implementation (=gls= on homebrew). If you opt
  to use MacOS default =ls= you might need to change the
  =dired-listing-switches= variable.


- =curl=

  Only needed if you'd like to upload text/images directly to 0x0.st
  site from Emacs Solo, by using either =emacs-solo/0x0-upload-text= or
  =emacs-solo/0x0-upload-file=.

  Also used for =emacs-solo-weather=, =emacs-solo-rate= and
  =emacs-solo-how-in= (cheat.sh queries).


- =wget=

  If present on the system, emacs-solo =newsticker= config uses it
  instead of the internal fetcher.


- =mpv=

  Only needed if you'd like to play videos directly from news in
  =newsticker=, play music from dired with dired music player =C-c m=,
  play something from a m3u file with =M-x m3u-visualizer-open-buffer=,
  listen to online radio with =C-c r=, or play YouTube results from
  =emacs-solo-yt=.


- =rsync=

  Only needed if you'd like to use =emacs-solo/dired-rsync-copy=.


- =ollama=

  Only needed if you'd like to use =emacs-solo/ollama-run-model=.


- =gemini-cli=

  Only needed if you'd like to use =emacs-solo/gemini-chat=.

- =claude=

  Only needed if you'd like to use =emacs-solo/claude-chat=.


- =khard=

  Only needed if you'd like to use =emacs-solo/khard-...= functions.


- =yt-dlp=

  Only needed if you'd like to use =youtube-search-async= from
  =emacs-solo-yt=.


- =gh= (GitHub CLI)

  Only needed if you'd like to use the GitHub interface from
  =emacs-solo-gh= (PRs, issues, notifications).


- =docker= / =podman=

  Only needed if you'd like to use the container management UI from
  =emacs-solo-container=.


- =biome= / =prettier= / =shfmt=

  Only needed if you'd like to use the format-on-save feature from
  =emacs-solo-formatter=.  The formatter is resolved per-project
  (local install preferred over global).


- =eslint=

  Only needed if you'd like to use the Flymake ESLint backend from
  =emacs-solo-flymake-eslint=.


- =languagetool=

  Only needed if you'd like to use the Flymake LanguageTool backend
  (grammar/spelling on prose) from =emacs-solo-flymake-languagetool=.

  Toggle it per buffer with =C-c ! C-t=, or set
  =emacs-solo-enable-flymake-languagetool= to =t= to have it on from the
  start in =text-mode= buffers.  =C-c ! L= picks a language, =C-c ! C-l=
  cycles the favorites.


- =rassumfrassum=

  Only needed if you'd like to use multiple LSP servers per buffer.


In order to proper copy/paste from terminals (TUI), you need:

- =pbcopy/pbpaste= (macOS)
- =clip.exe/powershell.exe= (WSL)
- =wl-copy/wl-paste= (Linux / FreeBSD with Wayland)
- =xclip= (Linux / FreeBSD with Xorg)

** Installation

Clone this repository into a directory of your liking and run Emacs
with:

#+BEGIN_SRC sh
  emacs --init-directory=YOUR_DIR
#+END_SRC

You can also simply copy *init.el*, *early-init.el* and the *lisp/*
directory into any folder and issue the same command as above.

And that's it, happy hacking! 🐂

** Project Structure

The configuration is split into two layers:

- =init.el= / =early-init.el= — core configuration using Emacs built-ins.
- =lisp/= — self-contained modules loaded via =require= at the end of
  =init.el=.

** Load Order & Where to Put Your Changes

Emacs Solo loads in a fixed sequence. There are three optional files
you can drop into your =user-emacs-directory= (the same folder as
=init.el=) to extend it *without ever editing the tracked files*, so you
stay easy to update:

#+BEGIN_SRC text
  ╔═══════════════╗      ╔═══════════════════════╗
  ║ early-init.el ║ ───▶ ║ private-early-init.el ║
  ╚═══════════════╝      ╚═══════════════════════╝
   ✗ DON'T TOUCH          ✎ TOUCH (yours, optional)
   tracked / upstream     early overrides: frame, fonts,
   loads custom-vars.el   default-frame-alist, GC, flash colors
	  │
	  ▼
  ╔═══════════════╗      ╔═══════════════════════╗
  ║    init.el    ║ ───▶ ║      private.el       ║
  ╚═══════════════╝      ╚═══════════════════════╝
   ✗ DON'T TOUCH          ✎ TOUCH (yours, optional)
   tracked / upstream     everything else: keybindings,
   reloads custom-vars,   commands, mail/IRC/weather flows,
   requires lisp/*        overrides... (loaded 0.5s idle after start)

  ───▶ loads      ✗ stays updatable, leave alone      ✎ edit freely
#+END_SRC

Rule of thumb: *never edit the =✗= files* (=early-init.el=, =init.el=,
=lisp/*=) — leaving them untouched is what keeps you conflict-free when
pulling upstream. Put your own code in the =✎= files instead.

Pick the file by *when* your code needs to run:

- =custom-vars.el= — settings written by =M-x customize=. Managed for you;
  you normally don't edit it by hand.

- =private-early-init.el= — runs at the *end of* =early-init.el=, before any
  package or UI is set up. Use it only for things that must happen
  early: frame parameters, fonts, =default-frame-alist=, the
  flash-of-light colors, GC tweaks. Keep it small.

- =private.el= — runs *after* startup (lazily, on first idle). This is
  the right place for almost everything: keybindings, custom commands,
  mail/IRC/weather flows, use-package for some 3rd party package
  you might need, etc.

All three are loaded with =noerror= / =file-exists-p= guards, so they are
*entirely optional* — absent files are silently skipped. Add only what
you need and pull from upstream without conflicts.

** Disclaimer

I’m happy to share this configuration with a catchy name, and I’d be
genuinely delighted if you find it useful. 🙂

However, this is *not* intended to be a distribution. This means I may
not cover every user's needs, nor will I accept every contribution
that pushes it in that direction. I use this configuration daily for
both personal and professional work, and like any custom setup, it
reflects my own preferences.

For example, this config does not include Python-specific settings,
whether for Eglot or Tree-sitter. Since this is a real working setup
and I’m not currently using Python, its absence might seem like an
oversight.

If you'd like to add your own modifications while staying up to date
with Emacs Solo, simply create a =private.el= file in the same directory
as =init.el=. A hook is already in place to load this private file after
Emacs initializes.

Of course, you can also fork it! (please do 😊)

** How do I...
A FAQ-like section of common questions on how to do X with only Emacs Solo.
#+html:<details open>
#+html:<summary><h3>So, how do I...</h3></summary>
*** 1.) Copy the current word under cursor?
The usual answer is *M-b* to go back to the beginning of the
word. *C-M-SPC* to expand the selection to the end of the word and *M-w*.

*Custom Emacs Solo Solution*: Use the isearch way to search a word (it has
better completion than C-M-SPC), like *M-s M-.* you can now just *M-w*.

*** 2.) Edit multiple search entries at once?

#+BEGIN_SRC text
  Original problem: I usually consult-outline, then embark-collect and wgrep...
#+END_SRC

You can start by using *occur*, or using *isearch* and then moving to occur.

Next start the edit mode of the occur buffer with *e*.

Make your changes, apply it with *C-c C-c*

From Emacs 30.1 onward you can also use the combo:
=replace-regexp-as-diff= for replacements in a single buffer,
=multi-replace-regexp-as-diff= for multiple buffers, and
=dired-do-replace-regexp-as-diff= to perform replace-regexp-as-diff

*** 3.) Edit multiple search entries between several files at once?

#+BEGIN_SRC text
  Original problem: I usually consult-grep, then use embark collect and wgrep...
#+END_SRC

Open dired on the root folder of where you search will happen. Mark
some files and or folders with *m*.

Use =dired-do-query-replace-regexp= or in a dired buffer hit =Q=.

Confirm it all or one by one, use *?* to check the options.

From Emacs 30.1 onward you can also use the combo:
=replace-regexp-as-diff= for replacements in a single buffer,
=multi-replace-regexp-as-diff= for multiple buffers, and
=dired-do-replace-regexp-as-diff= to perform replace-regexp-as-diff

*** 4.) Read news, like with elfeed?

You have two built-in options on Emacs.
- =M-x gnus=
- =M-x newsticker-treeview=

*** 5.) How do I see logs and their diffs?

=C-x v L= on a file inside your version controlled file. And over the
line you have the commit, press =d= for diffing.

If you wanna diff a range, mark the lines starting with =C-SPC= on the
first line of the range, and again =C-SPC= in the last line of the range
(the content of what you want must be selected, if the cursor is on
first column of the line it won't be included), now use =d= to diff.

*** 6.) How do I revert a hunk?
=C-x v == will open the diff panel for the current file, restrict it to
the hunk you'd like to revert with =r=, revert the direction of the diff
with =R= and apply the diff with =C-c C-a=.

From Emacs 31, we also have =C-c M-r= (=diff-revert-and-kill=), when on
buffers generated by =C-x v == and =C-x v D=.

*** 7.) Use (neo)vi(m) keybindings (aka Evil keybindings)?

Emacs comes with =viper= which is a =vi= emulator. This means a lot of
modern editing capabilities are missing.

Take a look at the =use-package Emacs Solo-viper-extensions= section of the
=init.el= file. Emacs Solo extends viper mode to include a bunch of more
modern =evil-like= bindings.

Just give it a try ;) =M-x viper-mode=

*** 8.) Temporarily highlight some word?

Use the powers of =highlight-regexp=! Over a word you want to make
highlighted use =M-s h .=

You can repeat it to other words and Emacs will handle different
colors for you.

To remove a highlight use =M-s h u= and select the highlighted regexp on
the list.

Find out about more options regarding highlighting with =M-s h ?=.

*** 9.) Know what is changed when closing Emacs or several files?

It is a common thing trying to close Emacs with =C-x C-c= just to find
out one of your buffers has some modification and now Emacs asks if
you'd like to save, override, etc.

Emacs Solo provides the extra option =d=, which will generate a diff of
the current file being asked to take action, so you can see if saving
is needed.

*** 10.) Show/Hide (toggle) hidden files in Dired?

Use =dired-omit-mode=, which you can toggle with =C-x M-o=. Notice that
this mode uses the regular expression defined in the =dired-omit-files=
variable. Emacs Solo already customizes this to ignore files matching
=^\\.=

*** 11.) Open multiple terms/shells?

Ever felt the need of some =multi-term= package on Emacs? Well, you
don't really need it, at least not with the internal implementations
of terminals and =eshell=.

Just use the =C-u= universal argument command before calling your
term/shell, like: =C-u M-x eshell= or =C-u C-x p e= or =C-u M-x term=, and
so on.

Now you have another instance of your term to work with, repeat this
pattern if you need more instances.

*** 12.) How do I select a single hunk out of many?

From Emacs 31, we have after =C-x v == a new =C-c RET n=
(=diff-delete-other-hunks=) option to do so.

*** 13.) How do I edit commit messages?

From =C-x v L=, you can press =e= and you'll be editing the commit
message. This is available from Emacs 31 onward.

*** 14.) How do I amend commits?

From =C-x v v=, you can press =C-c C-e= and you'll be on 'amend' mode.

*** 15.) Zoom fonts

Only the current buffer:

=C-x C--=
=C-x C-+= / =C-x C-==
=C-x C-0=


The whole interface:

=C-x C-M--=
=C-x C-M-+= / =C-x C-M-=
=C-x C-M-0=

*** 16.) Visit an URL

With =global-goto-address-mode= turned on, you can =C-c RET= over a link
to open it on your default browser.

=C-u C-c RET= will open it on the secondary browser, recommended:

Emacs Solo defaults:

#+BEGIN_SRC emacs-lisp
(setq global-goto-address-mode t)
(setq browse-url-secondary-browser-function 'eww-browse-url)
#+END_SRC

*** 17.) Increase/Decrease the resolution of PDFs

The =doc-view-resolution= variable is the way to go.

*** 18.) Open an URL under point

Given =global-goto-address-mode= is set to =t=, we can =C-c RET= to url
under point. This will use your system default browser.

If you'd like to use =EWW= and never leave Emacs, simply set
=browse-url-secondary-browser-function= to ='eww-browse-url=. This way you
can =C-u C-c RET=.

*** 19.) Open a file when path is under point

Use =C-x f= and then =M-n= to get the path under point fed to =file-find=.

*** 20.) Kill buffer and close window

Usually =C-x k= kills a buffer, but it keeps the window opened. If you
wish to kill and close window, use =C-x 4 0= (=kill-buffer-and-window=).

*** 21.) Attach multiple files in message-mode?

When on =gnus= and composing a message, if you'd like to attach multiple
files using dired, just split with dired =C-x 4 d=, use =M-x
turn-on-gnus-dired-mode RET=, mark files with =m= and use =C-c RET C-a= to
populate your composing buffer.

*** 22.) Use multiple LSP servers per buffer?

For this you need to use an external LSP multiplexer, so Eglot can
connect to it. Eglot's author made his own implementation of such a
program: [[https://github.com/joaotavora/rassumfrassum]].

Basically =C-u M-x eglot= and enter =rass -- server1 [options] -- server2
[options] --...=.

You can read more about it in this blogpost:
[[https://www.rahuljuliato.com/posts/eglot-rassumfrassum]].


#+html:</details>

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

Contributors

LionyxML

716 commits

sunng87

2 commits

charjr

1 commits

jpachecoxyz

1 commits

LionyxML/emacs-solo

A Pure Emacs (no external packages) IDE like configuration.

588

stars

720

commits

Emacs Lisp

primary language

Sep 10, 2026

updated

config
configuration
emacs
Browse cluster: Configuration file parsing and management

README

#+AUTHOR: Rahul Martim Juliato
#+EMAIL: rahul.juliato@gmail.com
#+OPTIONS: toc: nil

#+HTML: <p align="center">
#+HTML:   <img src="https://github.com/LionyxML/emacs-solo/releases/download/assets/emacs-solo-logo.png" alt="Project Logo" width="300"/>
#+HTML:   <br/>
#+HTML:   <img src="https://img.shields.io/badge/Emacs-31%2B-green.svg" alt="Emacs 31+"/>
#+HTML:   <img src="https://img.shields.io/badge/License-GPLv3-blue.svg" alt="GPLv3 License"/>
#+HTML: </p>

#+HTML: <p align="center">
#+HTML:   A <em>fast</em>, <em>powerful</em> and <em>modular</em> Emacs configuration that favors built-in functionality over third-party packages.
#+HTML: </p>

#+HTML: <p align="center">
#+HTML:   <a href="#obligatory-screenshots"><strong>Screenshots</strong></a> ·
#+HTML:   <a href="#as-seen-on-system-crafters"><strong>System Crafters Demo</strong></a> ·
#+HTML:   <a href="#minimum-emacs-version"><strong>Emacs Version</strong></a> ·
#+HTML:   <a href="#optional-dependencies"><strong>Optional Dependencies</strong></a> ·
#+HTML:   <a href="#installation"><strong>Installation</strong></a> ·
#+HTML:   <a href="#disclaimer"><strong>Disclaimer</strong></a> ·
#+HTML:   <a href="#how-do-i"><strong>FAQ</strong></a>
#+HTML: </p>

#+HTML: <hr />

* Emacs Solo

This is what you see as soon as you start Emacs:


#+BEGIN_SRC elisp
  ███████╗███╗   ███╗ █████╗  ██████╗███████╗    ███████╗ ██████╗ ██╗      ██████╗
  ██╔════╝████╗ ████║██╔══██╗██╔════╝██╔════╝    ██╔════╝██╔═══██╗██║     ██╔═══██╗
  █████╗  ██╔████╔██║███████║██║     ███████╗    ███████╗██║   ██║██║     ██║   ██║
  ██╔══╝  ██║╚██╔╝██║██╔══██║██║     ╚════██║    ╚════██║██║   ██║██║     ██║   ██║
  ███████╗██║ ╚═╝ ██║██║  ██║╚██████╗███████║    ███████║╚██████╔╝███████╗╚██████╔╝
  ╚══════╝╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝

    Loading time : 0.172725 seconds
    Packages     : 0
#+END_SRC


Emacs Solo is a configuration I use when I want to go back to the
roots and challenge myself by using Emacs with only built-in features.


It aims to be minimalist, at least in spirit. Yes, there are over 3000
lines of code, but most of that comes from organizing things cleanly
and building small, reusable modules. Compared to full-featured
distributions, it's still lean and focused.


The configuration favors Emacs built-ins, configured my way. But when
something essential is missing (like margin git gutters), a small,
hacky workaround is always added.

** Obligatory Screenshots

*** Overall View:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-01-overall.png]]

#+html:<details open>
#+html:<summary><h3>More screenshots here...</h3></summary>

*** iComplete (in buffer completion) + Flymake + Gutter:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-02-icomplete-flymake-gutter.png]]

*** Help Variable:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-03-help-var.png]]

*** iComplete Vertical:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-04-icomplete-vertical.png]]

*** Eshell:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-05-eshell.png]]

*** Dired + Gutter:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-06-dired-with-gutter.png]]

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-07-dired-with-gutter-2.png]]

*** Well behaved mode-line:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-08-mode-line.png]]

*** In Emacs Solo you find configurations for:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-09-single-init-file-with-sections.png]]

*** Emacs Solo also has a lot of extra mini-packages built-in:
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-10-single-init-file-with-sections-2.png]]

You can use =C-c d= or =M-x container-menu RET= to open a podman / docker
container manager.

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-12-container-management.png]]


Or you can use =C-c G= or =M-x gh-menu RET= to open a =gh= (github cli) UI:

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-13-gh-1.png]]

   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-13-gh-2.png]]


Emacs Solo also ships with some very cool themes!

We've got:

**** Crafters
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-crafters.png]]

**** Catppuccin
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-catppuccin.png]]

**** GITS
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-gits.png]]

**** Matrix
   [[https://github.com/LionyxML/emacs-solo/releases/download/assets/demo-14-tema-matrix.png]]

And much more!

#+html:</details>

** As seen on System Crafters!

Also, check out the full demo of =Emacs Solo= in action, as seen on
the System Crafters channel. In this video, David Wilson explores and
learns from the configuration, showing how different settings and
approaches are applied to create a more efficient and personalized
Emacs setup.

[[https://www.youtube.com/live/j_2QkCcf8zE?si=e8qvIFdyuV9j7d_y&t=1433][file:http://img.youtube.com/vi/j_2QkCcf8zE/0.jpg]]

** Minimum Emacs Version

Emacs Solo always requires the latest stable release of Emacs, which
is currently: =31.1=

However, some bleeding-edge features may be tested as well. For those,
you’ll need to compile Emacs from the master branch. I do my best to
mark these features with the =EMACS-32= tag.

** Optional Dependencies

It is recommended you have these programs in your system:

- =ripgrep= (rg)

  This provides quicker project grep and xref navigation.

  If you opt to use regular =grep=, reset the customization of variable
  =grep-command=.


- =ghostscript=

  This is necessary if you want to be able to use =doc-view= to see
  documents like PDFs.


- =gls=

  MacOS comes with an implementation of =ls= that misses some nice
  switches from the gnu implementation (=gls= on homebrew). If you opt
  to use MacOS default =ls= you might need to change the
  =dired-listing-switches= variable.


- =curl=

  Only needed if you'd like to upload text/images directly to 0x0.st
  site from Emacs Solo, by using either =emacs-solo/0x0-upload-text= or
  =emacs-solo/0x0-upload-file=.

  Also used for =emacs-solo-weather=, =emacs-solo-rate= and
  =emacs-solo-how-in= (cheat.sh queries).


- =wget=

  If present on the system, emacs-solo =newsticker= config uses it
  instead of the internal fetcher.


- =mpv=

  Only needed if you'd like to play videos directly from news in
  =newsticker=, play music from dired with dired music player =C-c m=,
  play something from a m3u file with =M-x m3u-visualizer-open-buffer=,
  listen to online radio with =C-c r=, or play YouTube results from
  =emacs-solo-yt=.


- =rsync=

  Only needed if you'd like to use =emacs-solo/dired-rsync-copy=.


- =ollama=

  Only needed if you'd like to use =emacs-solo/ollama-run-model=.


- =gemini-cli=

  Only needed if you'd like to use =emacs-solo/gemini-chat=.

- =claude=

  Only needed if you'd like to use =emacs-solo/claude-chat=.


- =khard=

  Only needed if you'd like to use =emacs-solo/khard-...= functions.


- =yt-dlp=

  Only needed if you'd like to use =youtube-search-async= from
  =emacs-solo-yt=.


- =gh= (GitHub CLI)

  Only needed if you'd like to use the GitHub interface from
  =emacs-solo-gh= (PRs, issues, notifications).


- =docker= / =podman=

  Only needed if you'd like to use the container management UI from
  =emacs-solo-container=.


- =biome= / =prettier= / =shfmt=

  Only needed if you'd like to use the format-on-save feature from
  =emacs-solo-formatter=.  The formatter is resolved per-project
  (local install preferred over global).


- =eslint=

  Only needed if you'd like to use the Flymake ESLint backend from
  =emacs-solo-flymake-eslint=.


- =languagetool=

  Only needed if you'd like to use the Flymake LanguageTool backend
  (grammar/spelling on prose) from =emacs-solo-flymake-languagetool=.

  Toggle it per buffer with =C-c ! C-t=, or set
  =emacs-solo-enable-flymake-languagetool= to =t= to have it on from the
  start in =text-mode= buffers.  =C-c ! L= picks a language, =C-c ! C-l=
  cycles the favorites.


- =rassumfrassum=

  Only needed if you'd like to use multiple LSP servers per buffer.


In order to proper copy/paste from terminals (TUI), you need:

- =pbcopy/pbpaste= (macOS)
- =clip.exe/powershell.exe= (WSL)
- =wl-copy/wl-paste= (Linux / FreeBSD with Wayland)
- =xclip= (Linux / FreeBSD with Xorg)

** Installation

Clone this repository into a directory of your liking and run Emacs
with:

#+BEGIN_SRC sh
  emacs --init-directory=YOUR_DIR
#+END_SRC

You can also simply copy *init.el*, *early-init.el* and the *lisp/*
directory into any folder and issue the same command as above.

And that's it, happy hacking! 🐂

** Project Structure

The configuration is split into two layers:

- =init.el= / =early-init.el= — core configuration using Emacs built-ins.
- =lisp/= — self-contained modules loaded via =require= at the end of
  =init.el=.

** Load Order & Where to Put Your Changes

Emacs Solo loads in a fixed sequence. There are three optional files
you can drop into your =user-emacs-directory= (the same folder as
=init.el=) to extend it *without ever editing the tracked files*, so you
stay easy to update:

#+BEGIN_SRC text
  ╔═══════════════╗      ╔═══════════════════════╗
  ║ early-init.el ║ ───▶ ║ private-early-init.el ║
  ╚═══════════════╝      ╚═══════════════════════╝
   ✗ DON'T TOUCH          ✎ TOUCH (yours, optional)
   tracked / upstream     early overrides: frame, fonts,
   loads custom-vars.el   default-frame-alist, GC, flash colors
	  │
	  ▼
  ╔═══════════════╗      ╔═══════════════════════╗
  ║    init.el    ║ ───▶ ║      private.el       ║
  ╚═══════════════╝      ╚═══════════════════════╝
   ✗ DON'T TOUCH          ✎ TOUCH (yours, optional)
   tracked / upstream     everything else: keybindings,
   reloads custom-vars,   commands, mail/IRC/weather flows,
   requires lisp/*        overrides... (loaded 0.5s idle after start)

  ───▶ loads      ✗ stays updatable, leave alone      ✎ edit freely
#+END_SRC

Rule of thumb: *never edit the =✗= files* (=early-init.el=, =init.el=,
=lisp/*=) — leaving them untouched is what keeps you conflict-free when
pulling upstream. Put your own code in the =✎= files instead.

Pick the file by *when* your code needs to run:

- =custom-vars.el= — settings written by =M-x customize=. Managed for you;
  you normally don't edit it by hand.

- =private-early-init.el= — runs at the *end of* =early-init.el=, before any
  package or UI is set up. Use it only for things that must happen
  early: frame parameters, fonts, =default-frame-alist=, the
  flash-of-light colors, GC tweaks. Keep it small.

- =private.el= — runs *after* startup (lazily, on first idle). This is
  the right place for almost everything: keybindings, custom commands,
  mail/IRC/weather flows, use-package for some 3rd party package
  you might need, etc.

All three are loaded with =noerror= / =file-exists-p= guards, so they are
*entirely optional* — absent files are silently skipped. Add only what
you need and pull from upstream without conflicts.

** Disclaimer

I’m happy to share this configuration with a catchy name, and I’d be
genuinely delighted if you find it useful. 🙂

However, this is *not* intended to be a distribution. This means I may
not cover every user's needs, nor will I accept every contribution
that pushes it in that direction. I use this configuration daily for
both personal and professional work, and like any custom setup, it
reflects my own preferences.

For example, this config does not include Python-specific settings,
whether for Eglot or Tree-sitter. Since this is a real working setup
and I’m not currently using Python, its absence might seem like an
oversight.

If you'd like to add your own modifications while staying up to date
with Emacs Solo, simply create a =private.el= file in the same directory
as =init.el=. A hook is already in place to load this private file after
Emacs initializes.

Of course, you can also fork it! (please do 😊)

** How do I...
A FAQ-like section of common questions on how to do X with only Emacs Solo.
#+html:<details open>
#+html:<summary><h3>So, how do I...</h3></summary>
*** 1.) Copy the current word under cursor?
The usual answer is *M-b* to go back to the beginning of the
word. *C-M-SPC* to expand the selection to the end of the word and *M-w*.

*Custom Emacs Solo Solution*: Use the isearch way to search a word (it has
better completion than C-M-SPC), like *M-s M-.* you can now just *M-w*.

*** 2.) Edit multiple search entries at once?

#+BEGIN_SRC text
  Original problem: I usually consult-outline, then embark-collect and wgrep...
#+END_SRC

You can start by using *occur*, or using *isearch* and then moving to occur.

Next start the edit mode of the occur buffer with *e*.

Make your changes, apply it with *C-c C-c*

From Emacs 30.1 onward you can also use the combo:
=replace-regexp-as-diff= for replacements in a single buffer,
=multi-replace-regexp-as-diff= for multiple buffers, and
=dired-do-replace-regexp-as-diff= to perform replace-regexp-as-diff

*** 3.) Edit multiple search entries between several files at once?

#+BEGIN_SRC text
  Original problem: I usually consult-grep, then use embark collect and wgrep...
#+END_SRC

Open dired on the root folder of where you search will happen. Mark
some files and or folders with *m*.

Use =dired-do-query-replace-regexp= or in a dired buffer hit =Q=.

Confirm it all or one by one, use *?* to check the options.

From Emacs 30.1 onward you can also use the combo:
=replace-regexp-as-diff= for replacements in a single buffer,
=multi-replace-regexp-as-diff= for multiple buffers, and
=dired-do-replace-regexp-as-diff= to perform replace-regexp-as-diff

*** 4.) Read news, like with elfeed?

You have two built-in options on Emacs.
- =M-x gnus=
- =M-x newsticker-treeview=

*** 5.) How do I see logs and their diffs?

=C-x v L= on a file inside your version controlled file. And over the
line you have the commit, press =d= for diffing.

If you wanna diff a range, mark the lines starting with =C-SPC= on the
first line of the range, and again =C-SPC= in the last line of the range
(the content of what you want must be selected, if the cursor is on
first column of the line it won't be included), now use =d= to diff.

*** 6.) How do I revert a hunk?
=C-x v == will open the diff panel for the current file, restrict it to
the hunk you'd like to revert with =r=, revert the direction of the diff
with =R= and apply the diff with =C-c C-a=.

From Emacs 31, we also have =C-c M-r= (=diff-revert-and-kill=), when on
buffers generated by =C-x v == and =C-x v D=.

*** 7.) Use (neo)vi(m) keybindings (aka Evil keybindings)?

Emacs comes with =viper= which is a =vi= emulator. This means a lot of
modern editing capabilities are missing.

Take a look at the =use-package Emacs Solo-viper-extensions= section of the
=init.el= file. Emacs Solo extends viper mode to include a bunch of more
modern =evil-like= bindings.

Just give it a try ;) =M-x viper-mode=

*** 8.) Temporarily highlight some word?

Use the powers of =highlight-regexp=! Over a word you want to make
highlighted use =M-s h .=

You can repeat it to other words and Emacs will handle different
colors for you.

To remove a highlight use =M-s h u= and select the highlighted regexp on
the list.

Find out about more options regarding highlighting with =M-s h ?=.

*** 9.) Know what is changed when closing Emacs or several files?

It is a common thing trying to close Emacs with =C-x C-c= just to find
out one of your buffers has some modification and now Emacs asks if
you'd like to save, override, etc.

Emacs Solo provides the extra option =d=, which will generate a diff of
the current file being asked to take action, so you can see if saving
is needed.

*** 10.) Show/Hide (toggle) hidden files in Dired?

Use =dired-omit-mode=, which you can toggle with =C-x M-o=. Notice that
this mode uses the regular expression defined in the =dired-omit-files=
variable. Emacs Solo already customizes this to ignore files matching
=^\\.=

*** 11.) Open multiple terms/shells?

Ever felt the need of some =multi-term= package on Emacs? Well, you
don't really need it, at least not with the internal implementations
of terminals and =eshell=.

Just use the =C-u= universal argument command before calling your
term/shell, like: =C-u M-x eshell= or =C-u C-x p e= or =C-u M-x term=, and
so on.

Now you have another instance of your term to work with, repeat this
pattern if you need more instances.

*** 12.) How do I select a single hunk out of many?

From Emacs 31, we have after =C-x v == a new =C-c RET n=
(=diff-delete-other-hunks=) option to do so.

*** 13.) How do I edit commit messages?

From =C-x v L=, you can press =e= and you'll be editing the commit
message. This is available from Emacs 31 onward.

*** 14.) How do I amend commits?

From =C-x v v=, you can press =C-c C-e= and you'll be on 'amend' mode.

*** 15.) Zoom fonts

Only the current buffer:

=C-x C--=
=C-x C-+= / =C-x C-==
=C-x C-0=


The whole interface:

=C-x C-M--=
=C-x C-M-+= / =C-x C-M-=
=C-x C-M-0=

*** 16.) Visit an URL

With =global-goto-address-mode= turned on, you can =C-c RET= over a link
to open it on your default browser.

=C-u C-c RET= will open it on the secondary browser, recommended:

Emacs Solo defaults:

#+BEGIN_SRC emacs-lisp
(setq global-goto-address-mode t)
(setq browse-url-secondary-browser-function 'eww-browse-url)
#+END_SRC

*** 17.) Increase/Decrease the resolution of PDFs

The =doc-view-resolution= variable is the way to go.

*** 18.) Open an URL under point

Given =global-goto-address-mode= is set to =t=, we can =C-c RET= to url
under point. This will use your system default browser.

If you'd like to use =EWW= and never leave Emacs, simply set
=browse-url-secondary-browser-function= to ='eww-browse-url=. This way you
can =C-u C-c RET=.

*** 19.) Open a file when path is under point

Use =C-x f= and then =M-n= to get the path under point fed to =file-find=.

*** 20.) Kill buffer and close window

Usually =C-x k= kills a buffer, but it keeps the window opened. If you
wish to kill and close window, use =C-x 4 0= (=kill-buffer-and-window=).

*** 21.) Attach multiple files in message-mode?

When on =gnus= and composing a message, if you'd like to attach multiple
files using dired, just split with dired =C-x 4 d=, use =M-x
turn-on-gnus-dired-mode RET=, mark files with =m= and use =C-c RET C-a= to
populate your composing buffer.

*** 22.) Use multiple LSP servers per buffer?

For this you need to use an external LSP multiplexer, so Eglot can
connect to it. Eglot's author made his own implementation of such a
program: [[https://github.com/joaotavora/rassumfrassum]].

Basically =C-u M-x eglot= and enter =rass -- server1 [options] -- server2
[options] --...=.

You can read more about it in this blogpost:
[[https://www.rahuljuliato.com/posts/eglot-rassumfrassum]].


#+html:</details>

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

See what people are saying

Contributors

LionyxML

716 commits

sunng87

2 commits

charjr

1 commits

jpachecoxyz

1 commits

Languages

Emacs Lisp

100.0%