FG42/docs/videos.org

14 KiB

How to build an editor with Emacs Lisp

DONE Episode 1 - Introduction

CLOSED: [2022-01-09 Sun 19:03]

What is it all about?

  • Create an editor, development environment and Window Manager (yeah window manager) and …
  • GNU/Emacs is amazing
  • Spread the joy
  • Guide for contributors
  • A guide for people who wants to learn some Lisp

The Plan

  • Parallel video series to How to build a compiler with LLVM and MLIR
  • Git branches
  • No live coding
  • Start from Emacs and Jump to FG42
  • Feel free to contribute

FG42 and a bit of history

DONE Episode 2 - Survive on the first day

CLOSED: [2022-02-11 Fri 10:28]

Why bother?

Why GNU/Emacs?

People might say because of

  • Org-mode
  • LSP support
  • Support for many many languages
  • It's lightweight
  • Tons of plugins

I'd say

  • Coz it's a lisp environment with an editor attached to it
  • Lisp is the difference

    • It's super easy to extend/hack emacs
    • In compare to other editors
  • You can do pretty much whatever your like in ELisp
  • It's like a framework for building an editor

FAQ

What is the difference between Doom, Spacemacs, FG42 and …?

Different editors based on Emacs

Which one should I use?

How to install Emacs packages?

UI Basics & Basic Concepts

  • Window
  • Frame
  • Mode line
  • Buffers
  • Mini buffer/Echo area
  • Point
  • Major mode
  • Minor mode

Basic Keybindings

How to read key bindings? Here is an example C-x M-e 4, it means press x key while holding Control and then press e key while pressing down Alt and finally press 4.

  • Emacs tutorial C-h t (or https://www.gnu.org/software/emacs/tour/)
  • Quit emacs C-x C-c
  • Abort C-g
  • Get Help C-h family

    • C-h f
    • C-h v
    • C-h m
    • C-h k
    • C-h a
  • Run a command (function) M-x
  • Visit a file C-x C-f
  • Search in Buffer C-s
  • Save buffer C-x C-s
  • Select region C-SPC
  • Copy M-w
  • Cut(killing) C-w
  • Paste(yanking) C-y
  • Kill buffer C-x k
  • Switch buffer C-x b
  • Undo C-/
  • Eval expression C-x C-e
  • describe-mode

Lisp basics

  • Expressions everywhere
  • Code a data structure
  • Almost everything in Lisp evaluates to themselves except:

    • lists
    • Symbols
  • Lisp laws:

    1. Everything in Lisp is an expression and evaluation of an expression means replacing it with its value
    2. Almost everything in Lisp evaluates to themselves except:

      • Lists
      • Symbols
      • Quotes
    3. List evaluation

DONE Episode 3 - Lisp Basics

CLOSED: [2022-03-12 Sat 18:38]

FAQ:

  • How to install Emacs?

    • Just make sure to have Emacs >= 27.1
  • What's the routine to use Emacs ?

    • Don't use Emacs like how you use other Editors.
    • There is no limits(Almost).
  • How evaluate forms?

    • C-x C-e at the end of any expression and anywhere
    • ielm
    • Batch mode

So Fare:

Lisp rules:

  1. Lisp is made of Expressions and they evaluate to a value.
  2. All the expression types evaluates to themselves with some exceptions.
  3. List evaluation

We will continue with Lisp basics for few episodes

Variables

  • How to define variables and constants
  • Set the value of a variable
  • Global and local scope
  • Lexical bindings vs Dynamic bindings

    • -*- lexical-binding: t; -*-

Functions

  • How to define functions
  • vs macros
  • vs special forms

DONE Episode 4 - Conditionals

CLOSED: [2022-04-09 Sat 11:24]

What we learned so far

what is true and what's not

Let & prog family

Conditional special forms

  • if
  • when
  • unless
  • cond

Useful forms and functions

  • eq
  • equal
  • and
  • not
  • or

Type Predicts

type-of

DONE Episode 5 - Lists

CLOSED: [2022-05-18 Wed 12:40]

What is a list?

  • Not a primitive type
  • A linked list made out of cons cells

Cons Cells

  • A container for pairs
  • CAR
  • CDR (could-er)
digraph {
    graph [bgcolor=transparent]
    fontcolor="gray80"
    node [color=gray80 shape="box", fontcolor="gray80"]
    edge [color=gray80]
    rankdir = "LR"

    subgraph cluster_0 {
        label="Cell"
        color="gray80"

        graph [bgcolor=transparent, fontcolor="gray80"]
        node [color=gray80 shape="box", fontcolor="gray80"]
        a0[label="car: 'head"]
        b0[label="cdr: 'tail"]
    }
}

/tmp/cons.svg

  (setq x1 (cons 'head 'tail))
  (car x1)
  (cdr x1)

  '(head . tail)
  (cons 2 nil)
  (cons 1 x1)
digraph {
    graph [bgcolor=transparent]
    fontcolor="gray80"
    node [color=gray80 shape="box", fontcolor="gray80"]
    edge [color=gray80]
    rankdir = "LR"

    subgraph cluster_0 {
        label="Cell"
        color="gray80"
        graph [bgcolor=transparent, fontcolor="gray80"]
        node [color=gray80 shape="box", fontcolor="gray80"]
        a0[label="car: 1"]
        b0[label="cdr: "]
    }
    subgraph cluster_1 {
        label="Cell"
        color="gray80"
        node [color=gray80 shape="box"]
        a1[label="car: 2"]
        b1[label="cdr: "]
        b0 -> a1
    }
    subgraph cluster_2 {
        label="Cell"
        color="gray80"
        node [color=gray80 shape="box"]
        a2[label="car: 3"]
        b2[label="cdr: nil"]
        b1 -> a2
    }
}

/tmp/list.svg

  (setq x2 (cons 1  (cons 2 (cons 3 nil))))
  (setq x3 (list 1 2 3))

Some useful functions

  • add-to-list
  (setq x4 (list 1 2 3 4))
  (add-to-list 'x4 3)
  (add-to-list 'x4 6)
  • push & pop
  (setq x5 (list 1 2 3 4))
  (push 1 x5)
  (pop x5)
  • member
  (setq x6 (list 'a 'b 1 2))
  (member 'z x6)
  (member 1 x6)
  • delete
  (setq x7 (list 1 2 3 4 5))
  (delete 3 x7)
  x7
  • remove
  (setq x8 (list 1 2 3 4 5))
  (remove 3 x8)
  x8
  • car
  • cdr
  (setq  x9 (list 1 2 3 4))
  (car x9)
  (cdr x9)

DONE Episode 6 - Property & Association Lists

CLOSED: [2022-06-13 Mon 10:38]

I have an idea

  • Develop FG42 on stream
  • I'll announce the date and time on:

    • Twitter: @lxsameer
    • Youtube Community (maybe)

eq vs equal

  • eq checks whether two objects are the same
  • equal checks whether two objects have similar structure and content.

Property List (plist)

  • Is a list of paired elements
  • Each of the pairs associates a property name with a property or value
  • The order of the property names (keys) is not significant
  • Keys must be unique
  • Emacs uses plists to store text properties and symbol properties

Examples

  (setq x '(:a 1 "b" 2 c 3 :d ("foo" "bar") :j nil))
  x

Functions

  • plist-get or lax-plist-get
  (plist-get x :a)
  (plist-get x "b")
  (lax-plist-get x "b")
  • plist-put or lax-plist-put
  (plist-put x :z 325)
  (plist-put x :z 10)
  (lax-plist-put x "b" 20)
  • plist-member
  (plist-get x :j)
  (plist-get x :g)
  (plist-member x :j)
  (plist-member x :g)

An example use case of plist

  (defun foo (&rest args)
    (message "ARGS: %s" args)
    (plist-get args :name))

  (foo :age 20 :name 'bob "blah" '(12 34 4))

Association List (alist)

  • It is a list of cons cells called associations
  • Mapping some keys to some values
  • The CAR of each cons cell is the key, and the CDR is the associated value
  • The order of associations matters

Examples

  (setq y '((:a . 1) ("b" . 2) (c . 3) (:d "foo" "bar")))
  y

Functions

  • assoc
  (assoc :a y)
  (assoc "b" y)
  • rassoc
  (rassoc 1 y)
  (rassoc 3 y)
  • assq
  (assq :a y)
  (assq "b" y)
  • alist-get
  (alist-get :a y)
  (alist-get :z y "blah")
  • cons
  (setq y1 (cons '(:z . 31) y))
  (assoc :z y1)

DONE Episode 7 - Basic Loops

CLOSED: [2022-07-09 Sat 10:31]

About previous episode

  • Duplicate keys in an association list
  • eval-defun

While

  • Form:
  (while CONDITION
    ...body...)
  • Loops and evaluates body as long as the CONDITION evaluates to true.
  • It always evaluats to the value of the CONDITION which will be false aaaaall the time.
  • We need to explicitly manage the condition.
  • Example:
  (let ((foo 1))
    (while (< foo 10)
      (message ">> %s" foo)
      (setq foo (+ 1 foo))))

  (let ((foo '(bar baz)))
    (while foo
      (message ">> %s" (car foo))
      (setq foo (cdr foo))))

dolist

  • It's a macro
  • Form:
  (dolist (element list [result])
    ...body...)
  • Evaluates the body with element set to the CAR of list on each iteration
  • At the ends evaluates result and return the evaluation result (if result is provided)
  • Example:
  (let ((foo '(9 8 7 6 5 4)))
    (dolist (x foo (+ 10 1))
      (message ">> %s" x)))


  (let ((foo '(9 8 7 6 5 4)))
    (macroexpand-1
     '(dolist (x foo 10)
        (message ">> %s" x))))

dotimes

  • It's a macro too
  • Form:
  (dotimes (var number)
    ...body...)
  • It's similar to dolist but iterates number of times
  • var in will contains the number of current iteration
  • Example:
  (let ((foo 10))
    (dotimes (x foo)
      (message ">> %s" x)))


  (let ((foo 10))
    (macroexpand-1
     '(dotimes (x foo)
        (message ">> %s" x))))

DONE Episode 8 - More Loops

CLOSED: [2022-07-29 Fri 15:11]

Recursion

  • A Recursive function, is a function that defines in terms of itself
  • Easy to implement
  • But should be careful with it to aviod infinit loops

Example

  (defun foo (int)
    (print int)
    (when  (> int 0)
      (foo (- int 1))))

  (foo 10)

Functional style loops

Mapping functions Family

  • mapcar
  (mapcar #'1+ '(1 2 3 4 5))

  (mapcar (lambda (x) (* x x))
          '(1 2 3 4))
  • mapc
  (mapc #'1+ '(1 2 3 4 5))
  (mapc #'print '(1 2 3 4 5))
  • map-concat
  (mapconcat (lambda (x)
               (format "[%s]" x))
             '(1 2 3 4 5)
             " <|> ")

Seq module

A collection of handy functions that operate on sequences.

  • seq-reduce
  (require 'seq)

  (seq-reduce

   (lambda (acc x)
     (+ acc x))

   '(1 2 3 4)

   0)
  • seq-filter
  (seq-filter (lambda (x) (< x 10))
              '(8 12 22 9))
  • seq-partition
  (seq-partition '(a b c d e f) 2)
  • seq-min, seq-max

DONE Episode 9 - Introduction to Macros

CLOSED: [2022-09-11 Sun 11:08]

What is a macro?

  • A macro is defined much like a function
  • It works on compile time
  • It returns a new expression as the return value
  • The compiler "expands" a macro by replacing the macro call with the return value of the macro
  • Different evaluation rule than functions

    • Unlike function calls, the arguments to a macro will be passed to the macro as they are, without evaluation.
  • Macros vs inline functions

How to define and expand a macro?

  • We can define a macro using defmacro form
  (defmacro inc (val)
    (list #'1+ val))

  (defmacro mydef (name val)
    (list 'setq (intern (concat "my-" (symbol-name name))) val))

  (defmacro foo (val)
      (1+ val))
  • We can inspect the expansion process using the macroexpand function family.

    • macroexpand: Expands the macros until no macro exists in the top level forms
    • macroexpand-all: Expands the macros all the way down to the subforms
    • macroexpand-1: Expands the macro only for one level or cycle
  (macroexpand-1 '(inc 10))
  (macroexpand-1 '(mydef blah 20))
  (print (macroexpand-1 '(when (> 10 5) (print "something"))))

Feedback or question

Episode 10 - More on Macros

Quasiquote aka backquote (`)

  • Backquote constructs allow us to quote an expression, but selectively evaluate sub-expressions
  • Similar to a template engine for lisp expressions
  • It can be used on its own but it will shine in macro definitions
  • On the simplest form it is identical to quote
  • Special markers , and ,@ can be used to mark expressions for evaluation
  • , will replace the return value of the evaluation with the expression
  • ,@ will replace and splice the return value of the evaluation

Examples

  `3
  `(1 2 3 4)
  `(1 2 3 ,(+ 5 6))
  `(1 2 3 ,(list 4 5 6))
  `(1 2 3 ,@(list 4 5 6))

  `(setq ,(intern (upcase "some_var")) 3)

declare form

  • It's a special macro which can be used to add meta properties to a function or macro

    • doc-string
    • indent

Real Examples

Episode 11 - Common pitfalls of Macros