Home

Awesome

Emacs for You (Emfy)

This project provides a tiny init.el file to set up Emacs quickly. This document provides a detailed description of how to set it up and get started with Emacs.

View Source Mastodon

Further this project also provides a tiny convenience command named em to start Emacs server and edit files using Emacs server. This helps in using Emacs efficiently. This script and its usage is explained in detail later in the Emacs Server and Emacs Launcher sections. Here is how the Emacs environment is going to look after setting up this project:

Screenshot of Emacs

If you are already comfortable with Emacs and only want to understand the content of init.el or em, you can skip ahead directly to the Line-by-Line Explanation section that describes every line of these files in detail.

Contents

Who Is This For?

Are you an absolute beginner to Emacs? Are you so new to Emacs that you do not even have the ~/.emacs.d/ directory on your file system? Have you come across recommendations to use starter kits like Doom Emacs, Spacemacs, etc. but then you wondered if you could use vanilla Emacs and customise it slowly to suit your needs without having to sacrifice your productivity in the initial days of using Emacs? Do you also want your Emacs to look sleek from day zero? If you answered "yes" to most of these questions, then this project is for you.

The init.el file in this project provides a quick way to get started with setting up your Emacs environment. This document explains how to do so in a step-by-step manner. This document also explains the content of init.el and em in a line-by-line manner.

Note that many customisations in the Emacs initialisation file available in this project are a result of the author's preferences. They may or may not match others' preferences. They may or may not suit your taste and requirements. Wherever applicable, the pros and cons of each customisation and possible alternatives are discussed in this document. You are encouraged to read the line-by-line explanation that comes later in this document, understand each customisation, and modify the initialisation file to suit your needs.

Features

This project provides a file named init.el that offers the following features:

Additionally, this project also provides a convenience command named em that is a thin wrapper around the emacs and emacsclient commands. It offers the following features:

All of these features along with every line of code that enables these features are explained in the sections below.

Get Started

This section helps you to set up Emfy quickly and see what the end result looks like. Perform the following steps to get started:

  1. Install Emacs 28.1 or later.

    On macOS, enter the following command if you have Homebrew:

    brew install --cask emacs
    

    On Debian, Ubuntu, or another Debian-based Linux system, enter the following command:

    sudo apt-get install emacs
    

    For other environments, visit https://www.gnu.org/software/emacs/ to see how to install Emacs.

  2. Copy the Emacs initialisation file init.el provided here to your home directory. Here is an example curl command that does this:

    mkdir ~/.emacs.d
    curl -L https://github.com/susam/emfy/raw/main/init.el >> ~/.emacs.d/init.el
    

    Here is another alternative that copies the initialisation file to an XDG-compatible location as follows:

    mkdir -p ~/.config/emacs
    curl -L https://github.com/susam/emfy/raw/main/init.el >> ~/.config/emacs/init.el
    

    Some Emacs users who have been using Emacs for a long time like to keep the initialisation file at its traditional location illustrated below:

    curl -L https://github.com/susam/emfy/raw/main/init.el >> ~/.emacs
    

    Emacs can automatically load the Emacs initialisation file from any of the paths used above. See section The Emacs Initialisation File of the Emacs manual for more details about this.

  3. Copy the Emacs launcher script em provided here to some directory that belongs to your PATH variable. For example, here are a few commands that download this script and place it in the /usr/local/bin/ directory:

    curl -L https://github.com/susam/emfy/raw/main/em > /tmp/em
    sudo mv /tmp/em /usr/local/bin/em
    chmod +x /usr/local/bin/em
    

    The usefulness of this launcher script will be explained in the section Emacs Launcher later.

  4. Install packages configured in Emfy:

    emacs --eval '(progn (install-packages) (kill-emacs))'
    

    We will see how this command works later in the section Install Packages.

    On macOS, you may receive the following error message in a dialog box: '“Emacs.app” can’t be opened because Apple cannot check it for malicious software.' To resolve this issue, go to Apple menu > System Preferences > Security & Privacy > General and click "Open Anyway".

  5. Start Emacs:

    emacs
    

Now that your environment is setup, read the next section to learn how to use this environment in more detail.

Step-by-Step Usage

Use Emacs

Emacs is a very powerful and extensible editor. It comes with over 10,000 built-in commands. A small section like this can barely scratch the surface of Emacs. Yet, this section makes a modest attempt at getting you started with Emacs and then provides more resources to learn further. Perform the following steps to get started:

  1. Start Emacs:

    emacs
    
  2. Within Emacs, enter the following command to open a file, say, hello.txt:

    C-x C-f hello.txt RET
    

    A new buffer to edit hello.txt is created. If a file with that name already exists on your file system, then it loads the content of the file into the buffer.

    Note that in the Emacs world (and elsewhere too), the notation C- denotes the <kbd>ctrl</kbd> modifier key. Thus C-x denotes <kbd>ctrl</kbd>+<kbd>x</kbd>.

    The notation RET denotes the <kbd>enter</kbd> or <kbd>return</kbd> key.

    Typing consecutive C- key sequences can be optimised by pressing and holding down the <kbd>ctrl</kbd> key, then typing the other keys, and then releasing the <kbd>ctrl</kbd> key. For example, to type C-x C-f, first press and hold down <kbd>ctrl</kbd>, then type <kbd>x</kbd>, then type <kbd>f</kbd>, and then release <kbd>ctrl</kbd>. In other words, think of C-x C-f as C-(x f). This shortcut works for other modifier keys too.

  3. Now type some text into the buffer. Type out at least 3-4 words. We will need it for the next two steps.

  4. Move backward by one word with the following key sequence:

    M-b
    

    The notation M- denotes the meta modifier key. The above command can be typed with <kbd>alt</kbd>+<kbd>b</kbd> or <kbd>option</kbd>+<kbd>b</kbd> or <kbd>esc</kbd> <kbd>b</kbd>.

    If you face any issue with the <kbd>alt</kbd> key or the <kbd>option</kbd> key, read Emacs Wiki: Meta Key Problems.

  5. Now move forward by one word with the following key sequence:

    M-f
    
  6. The C-g key sequence cancels the current command. This can be used when you mistype a command and want to start over or if you type a command partially, then change your mind and then you want to cancel the partially typed command. Try out these examples:

    C-x C-f C-g
    
    C-x C-g
    
  7. Save the buffer to a file on the file system with this command:

    C-x C-s
    
  8. Quit Emacs:

    C-x C-c
    

Now you know how to start Emacs, open a file, save it, and quit. Improve your Emacs knowledge further by taking the Emacs tutorial that comes along with Emacs. In Emacs, type C-h t to start the tutorial.

The key bindings to perform various operations like creating file, saving file, quitting the editor, etc. may look arcane at first, but repeated usage of the key bindings develops muscle memory soon and after having used them for a few days, one does not even have to think about them. The fingers do what the mind wants effortlessly due to muscle memory.

While you are getting used to the Emacs key bindings, keep this GNU Emacs Reference Card handy. Also, if you are using it in GUI mode, then the menu options can be quite helpful.

Use Paredit

Paredit helps in keeping parentheses balanced and also in performing structured editing of S-expressions in Lisp code. It provides a powerful set of commands to manipulate S-expressions in various ways. Perform the following steps to get started with Paredit:

  1. Run Emacs:

    emacs
    
  2. Open an Emacs Lisp source file:

    C-x C-f foo.el
    
  3. Type the following code only:

    (defun square (x
    

    At this point, Paredit should have inserted the two closing parentheses automatically. The code should look like this:

    (defun square (x))
                    -
    

    The cursor should be situated just after the parameter x. The underbar shows where the cursor should be.

  4. Type the closing parentheses now. Yes, type it even if the closing parenthesis is already present. The cursor should now skip over the first closing parenthesis like this:

    (defun square (x))
                     -
    

    Of course, there was no need to type the closing parenthesis because it was already present but typing it out to skip over it is more efficient than moving over it with movement commands. This is, in fact, a very nifty feature of Paredit. We can enter code with the same keystrokes as we would without Paredit.

  5. Now type <kbd>enter</kbd> to insert a newline just before the last parenthesis. A newline is inserted like this:

    (defun square (x)
      )
      -
    
  6. Now type only this:

    (* x x
    

    Again, Paredit would insert the closing parenthesis automatically. The code should look like this now:

    (defun square (x)
      (* x x))
            -
    

There is a lot more to Paredit than this. To learn more, see The Animated Guide to Paredit.

Note: While many Lisp programmers find Paredit very convenient and powerful while manipulating S-expressions in Lisp code, there are a few people who do not like Paredit because they find the Paredit behaviour intrusive. See the Opinion References section for more discussion on this topic.

Evaluate Emacs Lisp Code

The previous section shows how to write some Emacs Lisp code and how Paredit helps in keeping the parentheses balanced. In this section, we will see how to execute some Emacs Lisp code.

  1. Run Emacs:

    emacs
    
  2. Open an Emacs Lisp source file:

    C-x C-f foo.el
    
  3. Enter the following code:

    (defun square (x)
      (* x x))
    
  4. With the cursor placed right after the last closing parenthesis, type C-x C-e. The name of the function defined should appear in the echo area at the bottom. This confirms that the function has been defined.

  5. Now add the following code to the Emacs Lisp source file:

    (square 5)
    
  6. Once again, with the cursor placed right after the last closing parenthesis, type C-x C-e. The result should appear in the echo area at the bottom.

Use Rainbow Delimiters

There is not much to learn about using Rainbow Delimiters. In the previous sections, you must have seen that as you type nested parentheses, each parenthesis is highlighted with a different colour. That is done by Rainbow Delimiters. It colours each parenthesis according to its nesting depth level.

Note: Not everyone likes Rainbow Delimiters. Some people find parentheses in multiple colours distracting. See the Opinion References section for more discussion on this topic.

Useful Terms

In this section, we clearly describe a few terms that we use later in this document.

There are many other peculiar terms found in the world of Emacs such as the term point to refer to the current location of the cursor, the term kill to cut text, the term yank to paste text, etc. but we will not discuss them here for the sake of brevity. The meanings of most such terms become obvious from the context when you encounter them. The terms described above should be sufficient to understand the line-by-line explanation presented in the next section.

Line-by-Line Explanation

This section explains the init.el file provided here line-by-line.

Tweak UI

The first few lines in our init.el merely tweak the Emacs user interface. These are of course not essential for using Emacs. However, many new Emacs users often ask how to customise the user interface to add a good colour scheme and make it look minimal, so this section indulges a little in customising the user interface.

Here is a line-by-line explanation of the UI tweaks in init.el:

Dark Theme

In this section, we will choose a dark theme for Emacs. If you do not like dark themes, you might want to stick with the default theme, choose another theme, or skip this section.

Personal note: I see that many recent colour themes choose a dim colour for comments in code. Such colour themes intend to underemphasise the comments. I think comments play an important role in code meant to be read by humans and should be emphasised appropriately. That's why I have chosen tangerine yellow for comments. This makes the comments are easily readable.

Line Numbers

Enable line numbers in modes for configuration, programming, and text with the following loop:

(dolist (hook '(prog-mode-hook conf-mode-hook text-mode-hook))
  (add-hook hook 'display-line-numbers-mode))

Every buffer has a major mode which determines the editing behaviour, syntax highlighting, etc. of the buffer. To see the current major mode, type M-: major-mode RET. The name of the current major mode is also always displayed in the mode line at the bottom.

The add-hook calls in the loop above ensure that display-line-numbers-mode is enabled automatically when certain major modes become active. In particular, this ensures that line numbers are enabled while editing configuration files, program files, or text files. For instance, when editing a C program (say with C-x C-f foo.c RET), the above hook enables line numbers for the buffer for the C program file. This happens because while editing C program files, the major mode named c-mode is activated and c-mode is derived from prog-mode.

The above loop also ensures that this feature does not get enabled while working with other types of buffers. For example, if we start a terminal emulator with M-x ansi-term RET, this feature does not get enabled because the terminal emulator buffer has the major mode named term-mode which is not derived from any of the three modes mentioned above. Displaying line numbers in such a mode can be distracting, so we keep line numbers disabled in such modes.

Highlight Parentheses

The following points describe how we enable highlighting of parentheses:

Minibuffer Completion

Enable automatic minibuffer completion:

(fido-vertical-mode)

To test this out, perform the following exercises:

In the steps above, note how it is not necessary to type out the filename or buffer name or command accurately. We can enter our input partially and Fido will automatically find matches for it.

Show Stray Whitespace

While writing text files, it can often be useful to quickly spot any trailing whitespace at the end of lines or unnecessary trailing new lines at the end of the file. The next few points describe how we highlight stray whitespace and newlines.

Require Final Newline

It is good practice to terminate text files with a newline. For many types of files, such as files with extensions .c, .el, .json, .lisp, .org, .py, .txt, etc., Emacs inserts a terminating newline automatically when we save the file with C-x C-s. Emacs achieves this by ensuring that the major modes for these files set the variable require-final-newline to t by default. However, there are many other types of files, such as files with extensions .ini, .yaml, etc. for which Emacs does not insert a terminating newline automatically. We now ensure that Emacs always inserts a terminating newline for all types of files with the following call:

(setq require-final-newline t)

Many tools on Unix and Linux systems expect text files to be terminated with a newline. For example, in a crontab entry, if the final line is not followed by a terminating newline, it is ignored. Similarly, wc -l does not count the final line if it is not followed by a terminating newline. That is why, in the above step we configure Emacs to ensure that it always inserts a terminating newline before saving a file.

Single Space for Sentence Spacing

Emacs uses the convention of treating a full stop followed by two spaces as end of sentence. However, many people these days seem to prefer ending sentences with a full stop followed by a single space. This section explains how to configure Emacs to treat a full stop followed by a single space as end of sentence.

If you like the convention of having two spaces after full stop, you should remove the code discussed below from your Emacs initialisation file and then skip this section. If you are unable to make up your mind about whether you should end sentences with one space or two spaces, read the final paragraph of this section for some discussion about it.

We can configure Emacs to treat a sentence-terminating character (like a full stop, question mark, etc.) followed by a single space as end of sentence with the following code:

(setq sentence-end-double-space nil)

This little setting has significant consequences while editing and moving around text files. We will discuss two such consequences now with two tiny experiments:

Experiment A: Moving By Sentences: To check the default behaviour, first comment out the above line of Emacs Lisp code in the Emacs initialisation file, save the file, and restart Emacs. Now copy the following text:

Lorem ipsum dolor sit amet, consectetur adipiscing elit donec. Porttitor id lacus non consequat.

Then open a new text buffer in Emacs with C-x C-f foo.txt RET and paste the copied text with C-y. Then type C-a to go to the beginning of the line. Finally, type M-e to move to the end of the sentence. Without sentence-end-double-space set to nil, typing M-e moves the cursor all the way to the end of the line (i.e., after the second full stop). It ignores the first full stop as end of sentence because it is followed by one space whereas Emacs expects two spaces at the end of a sentence.

Now to verify that the above line of Emacs Lisp code works as expected, uncomment it again to enable it, save the file, restart Emacs, and then perform the above experiment again. With sentence-end-double-space set to nil, typing M-e moves the cursor to the end of the of first sentence (i.e., after the first full stop). This is what we normally expect these days.

Experiment B: Filling Paragraphs: While writing text files, it is customary to limit the length of each line to a certain maximum length. In Emacs, the key sequence M-q invokes the fill-paragraph command that works on the current paragraph and reformats it such that each line is as long as possible without exceeding 70 characters in length.

To check the default behaviour, first comment out the above line of Emacs Lisp code in the Emacs initialisation file, save the file, and restart Emacs. Then create the same text buffer as the one in the previous experiment. Now place the cursor anywhere on text and type M-q to reformat it as a paragraph. Without sentence-end-double-space set to nil, typing M-q reformats the paragraph as follows:

Lorem ipsum dolor sit amet, consectetur adipiscing elit
donec. Porttitor id lacus non consequat.

Now to verify that the above line of Emacs Lisp code works as expected, uncomment it again to enable it, save the file, then restart Emacs, and then perform the above experiment again. With sentence-end-double-space set to nil, typing M-q reformats the paragraphs as follows:

Lorem ipsum dolor sit amet, consectetur adipiscing elit donec.
Porttitor id lacus non consequat.

We see that without sentence-end-double-space set to nil, Emacs refuses to insert a hard linebreak after the string donec., so it moves the entire word to the next line. This is a result of following the convention of double spaces at the end of a sentence. This convention prevents inadvertently placing a hard linebreak within an abbreviation. Since many people prefer ending a sentence with a single space, we would like the text above to be reformatted as shown in the last example above. Setting sentence-end-double-space to nil achieves this.

While the step above explains how to configure Emacs to treat a full stop followed by a single space as the end of sentence, it is worth mentioning here that the number of spaces that must follow the end of a sentence is a very controversial matter. Many people prefer two spaces between sentences while many others prefer a single space instead. Section Sentences of the Emacs manual recommends putting two spaces at the end of a sentence because it helps the Emacs commands that operate on sentences distinguish between dots that end a sentence and those that do not. The author of this project uses two spaces to end sentences. Also, see the Opinion References section for more discussion on this topic. In case, you want to follow the convention of two spaces at the end of a sentence, omit the above line of Emacs Lisp from your Emacs initialisation file.

Indentation

The following point shows how to configure Emacs to insert spaces, not tabs, for indenting code.

Keep Working Directory Tidy

Emacs creates a number of temporary files to ensure that we do not inadvertently lose our work while editing files. However, these files can clutter our working directories. This section shows some ways to keep the current working directory tidy by asking Emacs to manage these files at a different location.

Custom Command and Key Sequences

In this section we will see how to make our own custom command.

Emacs Server

Many users prefer to run a single instance of Emacs and do all their editing activities via this single instance. It is possible to use Emacs alone for all file browsing needs and never use the terminal again. Despite the sophisticated terminal and file browsing capabilities of Emacs, some users still like to use a traditional terminal to move around a file system, find files, and edit them. This practice may become inconvenient quite soon because it would lead to the creation of too many Emacs frames (desktop-level windows) and processes. This section explains how to create a single Emacs server, a single Emacs frame, and edit all your files in this frame via the server even while you are browsing files in the terminal. You don't need this section if you use Emacs for all your file browsing needs but if you don't, this section may be useful. Let us now see how we start the Emacs server in our Emacs initialisation file.

When Emacs starts for the first time with the above lines of Emacs Lisp code in its initialisation file, it starts an Emacs server. Now the following commands can be used on a terminal to edit files:

With this setup, the Emacs server quits automatically when we close the first Emacs instance that started the Emacs server. Running the emacs command or starting Emacs via another method after that would start the Emacs server again.

It is worth noting here that there are other ways to start the Emacs server and to use the emacsclient command. See section Using Emacs as a Server and section emacsclient Options of the Emacs manual for more details.

Install Packages

The following points describe how we automate the installation of Emacs packages we need:

The code discussed above creates a new command named install-packages that we can execute anytime with M-x install-packages RET.

You can also add new packages to the list used in the dolist call, type C-M-x to evaluate the install-packages function again, so that this command is now updated according to your latest code, and then run M-x install-packages RET to install the new packages.

Having understood this section, step 4 of the Get Started section should now make sense. The command we used there was:

emacs --eval '(progn (install-packages) (kill-emacs))'

This command simply runs Emacs (with your Emacs initialisation file) and evaluates an Emacs Lisp expression that runs the install-packages function followed by kill-emacs. As a result, this command installs the packages configured in the code discussed above and quits Emacs.

Alternative: If you know enough Emacs already, you might notice that this project does not use the use-package package. The use-package package allows us to install and configure packages declaratively such that the configuration of each package is neatly contained within one use-package expression. The author of this project has been using Emacs long before use-package existed and prefers a more traditional method of installing and configuring packages using package.el and with-eval-after-load. However, if you want to explore installing and configuring packages declaratively, please take a look at the use-package User Manual.

Configure Paredit

This section describes how to enable Paredit. Paredit helps in keeping parentheses balanced and in performing structured editing of S-expressions. Some Emacs Lisp programmers find it useful while some do not.

In case you decide not to use Paredit, you may skip this section. In that case, you might also want to remove this package from the dolist loop discussed in the previous section.

We enable Paredit in various modes pertaining to Lisp programming with the following Emacs Lisp code:

(when (fboundp 'paredit-mode)
  (dolist (hook '(emacs-lisp-mode-hook
                  eval-expression-minibuffer-setup-hook
                  ielm-mode-hook
                  lisp-interaction-mode-hook
                  lisp-mode-hook))
    (add-hook hook 'enable-paredit-mode)))

Here is an explanation of the above code:

By default, Paredit overrides the behaviour of the RET key such that a newline is inserted whenever we press RET key. Unfortunately, this behaviour is problematic in the eval-expression minibuffer and IELM where we want to evaluate the expression we have entered when we type RET. Therefore, we disable the overriding behaviour of Paredit using the following code:

(with-eval-after-load 'paredit
  (define-key paredit-mode-map (kbd "RET") nil))

The above code ensures that whenever Paredit is loaded, the RET key binding in its keymap is set to nil, so that Paredit does not override the default behaviour of the RET key.

Configure Rainbow Delimiters

This section describes how to enable rainbow delimiters and configure it. Rainbow Delimiters colour nested parentheses with different colours according to the depth level of each parenthesis. Some people find it useful and some do not.

If you decide not to use Rainbow Delimiters, you may skip this section. In that case, you might also want to remove this package from the dolist loop discussed in the previous section.

We enable Paredit in various modes pertaining to Lisp programming with the following Emacs Lisp code:

(when (fboundp 'rainbow-delimiters-mode)
  (dolist (hook '(emacs-lisp-mode-hook
                  ielm-mode-hook
                  lisp-interaction-mode-hook
                  lisp-mode-hook))
    (add-hook hook 'rainbow-delimiters-mode)))

Here is an explanation of the above code:

In the discussion above, you may have noticed that we did not enable Rainbow Delimiters for eval-expression minibuffer. That is because eval-expression minibuffer does not support syntax highlightng. Therefore enabling Rainbow Delimiters in it has no effect. See https://github.com/Fanael/rainbow-delimiters/issues/57 for more details.

The default colours that Rainbow Delimiters chooses for the nested parentheses are too subtle to easily recognise the matching pair of parentheses. The following Emacs Lisp code makes the parentheses more colourful:

(with-eval-after-load 'rainbow-delimiters
  (set-face-foreground 'rainbow-delimiters-depth-1-face "#c66")  ; red
  (set-face-foreground 'rainbow-delimiters-depth-2-face "#6c6")  ; green
  (set-face-foreground 'rainbow-delimiters-depth-3-face "#69f")  ; blue
  (set-face-foreground 'rainbow-delimiters-depth-4-face "#cc6")  ; yellow
  (set-face-foreground 'rainbow-delimiters-depth-5-face "#6cc")  ; cyan
  (set-face-foreground 'rainbow-delimiters-depth-6-face "#c6c")  ; magenta
  (set-face-foreground 'rainbow-delimiters-depth-7-face "#ccc")  ; light gray
  (set-face-foreground 'rainbow-delimiters-depth-8-face "#999")  ; medium gray
  (set-face-foreground 'rainbow-delimiters-depth-9-face "#666")) ; dark gray

The colours chosen above make matching pairs of parentheses easier to recognise.

End of File

The final line of code in the file is:

(provide 'init)

The above line is not really necessary for the Emacs initialisation file. The provide function call declares a feature that an Emacs package provides, so provide calls like the one above are typically found in Emacs packages. Here, we simply declare that this Emacs initialisation file provides a feature named init, only for the sake of completeness.

Other Emacs Lisp programs can test whether a feature is availabe using the featurep function. For example, Paredit provides the feature named paredit. To test if this feature is available, type M-: (featurep 'paredit) RET.

Similarly, to test if the init feature declared above is available, type M-: (featurep 'init) RET

Emacs Launcher

In the Emacs Server section, we saw how our Emacs initialisation file ensures that an Emacs server is started when we run emacs for the first time. Once Emacs server has started, we can edit new files from the terminal using the emacsclient command. This section describes a script named em that can automatically decide whether to run emacs or emacsclient depending on the situation.

As mentioned in the previous section, you don't need this section if you use Emacs for all your file browsing needs but if you don't, this section may be useful. Further, it is worth mentioning that this script solves a very specific problem of using a single command named em to both launch a new Emacs server as well as to open existing files in an existing Emacs frame via the existing Emacs server. If you have this specific problem, you may find this script helpful. However, if you do not have this problem or if you have a different problem to solve, it would be useful to understand how emacsclient works and read the related documentation mentioned in the previous section and then modify this script or write your own shell script, shell alias, or shell function that solves your problems.

The em script should be already present on the system if the steps in the Get Started section were followed. The third step there installs this script to /usr/local/bin/em. Now we discuss every line of this script in detail.

Now that we know what the em script does, let us see the various ways of using this script as a command:

That's it! Only two things to remember from this section: start Emacs with em and edit files with em foo.txt, em foo.txt bar.txt, etc.

Opinion References

Channels

The following channels are available for asking questions, seeking help and receiving updates regarding this project:

You are welcome to follow or subscribe to one or more of these channels to receive updates and ask questions about this project.

License

This is free and open source software. You can use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of it, under the terms of the MIT License. See LICENSE.md for details.

This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied. See LICENSE.md for details.

See Also