2021-12-21 21:18:32 +00:00
|
|
|
#+TITLE: How to build an editor with Emacs Lisp
|
|
|
|
#+SEQ_TODO: TODO(t/!) NEXT(n/!) BLOCKED(b@/!) | DONE(d%) CANCELLED(c@/!) FAILED(f@/!)
|
|
|
|
#+TAGS: READER(r) MISC(m)
|
|
|
|
#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty overview
|
|
|
|
|
2022-01-09 20:14:50 +00:00
|
|
|
* DONE Episode 1 - Introduction
|
|
|
|
CLOSED: [2022-01-09 Sun 19:03]
|
2021-12-21 21:18:32 +00:00
|
|
|
** 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
|
|
|
|
- It's my:
|
|
|
|
+ Editor/IDE
|
|
|
|
+ Email client
|
|
|
|
+ Window Manager
|
|
|
|
+ File Manager
|
|
|
|
+ Terminal Emulator
|
|
|
|
+ IRC client (at some point)
|
|
|
|
+ TODO manager
|
|
|
|
+ "Office suit" (air qoute)
|
|
|
|
+ ....
|
|
|
|
- Started on 2010 in a train
|
|
|
|
- I'm working on the V3
|
|
|
|
- Requirements
|
|
|
|
+ Emacs >= 27.1
|
|
|
|
|
|
|
|
- Website: https://fg42.org/
|
|
|
|
- Repository: https://devheroes.codes/FG42
|
|
|
|
- Website: https://lxsameer.com
|
|
|
|
- Email: lxsameer@gnu.org or lxsameer@lxsameer.com
|
2022-02-14 10:15:37 +00:00
|
|
|
* DONE Episode 2 - Survive on the first day
|
|
|
|
CLOSED: [2022-02-11 Fri 10:28]
|
2022-01-09 20:14:50 +00:00
|
|
|
** 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
|
|
|
|
- ...
|
2022-03-14 16:26:37 +00:00
|
|
|
-
|
|
|
|
3. List evaluation
|
|
|
|
* DONE Episode 3 - Lisp Basics
|
|
|
|
CLOSED: [2022-03-12 Sat 18:38]
|
2022-02-14 10:15:37 +00:00
|
|
|
** 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
|
2022-04-13 12:48:29 +01:00
|
|
|
* DONE Episode 4 - Conditionals
|
|
|
|
CLOSED: [2022-04-09 Sat 11:24]
|
2022-03-14 16:26:37 +00:00
|
|
|
** 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
|
|
|
|
- numberp
|
|
|
|
- stringp
|
|
|
|
- listp
|
|
|
|
- boundp
|
|
|
|
- More at https://www.gnu.org/software/emacs/manual/html_node/elisp/Type-Predicates.html
|
|
|
|
** type-of
|
2022-05-18 20:19:18 +01:00
|
|
|
* DONE Episode 5 - Lists
|
|
|
|
CLOSED: [2022-05-18 Wed 12:40]
|
2022-04-13 12:48:29 +01:00
|
|
|
** 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)
|
|
|
|
#+NAME: ep-5-cons
|
|
|
|
#+BEGIN_SRC graphviz-dot :file /tmp/cons.svg :cmdline -Kdot -Tsvg
|
|
|
|
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"]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
#+RESULTS: ep-5-cons
|
|
|
|
[[file:/tmp/cons.svg]]
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x1 (cons 'head 'tail))
|
|
|
|
(car x1)
|
|
|
|
(cdr x1)
|
|
|
|
|
|
|
|
'(head . tail)
|
|
|
|
(cons 2 nil)
|
|
|
|
(cons 1 x1)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
#+NAME: ep-5-list
|
|
|
|
#+BEGIN_SRC graphviz-dot :file /tmp/list.svg :cmdline -Kdot -Tsvg
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
#+RESULTS: ep-5-list
|
|
|
|
[[file:/tmp/list.svg]]
|
|
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x2 (cons 1 (cons 2 (cons 3 nil))))
|
|
|
|
(setq x3 (list 1 2 3))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** Some useful functions
|
|
|
|
- add-to-list
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x4 (list 1 2 3 4))
|
|
|
|
(add-to-list 'x4 3)
|
|
|
|
(add-to-list 'x4 6)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- push & pop
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x5 (list 1 2 3 4))
|
|
|
|
(push 1 x5)
|
|
|
|
(pop x5)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- member
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x6 (list 'a 'b 1 2))
|
|
|
|
(member 'z x6)
|
|
|
|
(member 1 x6)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- delete
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x7 (list 1 2 3 4 5))
|
|
|
|
(delete 3 x7)
|
|
|
|
x7
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- remove
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x8 (list 1 2 3 4 5))
|
|
|
|
(remove 3 x8)
|
|
|
|
x8
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- car
|
|
|
|
- cdr
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x9 (list 1 2 3 4))
|
|
|
|
(car x9)
|
|
|
|
(cdr x9)
|
|
|
|
#+END_SRC
|
|
|
|
|
2022-06-18 18:37:14 +01:00
|
|
|
* DONE Episode 6 - Property & Association Lists
|
|
|
|
CLOSED: [2022-06-13 Mon 10:38]
|
2022-05-18 20:19:18 +01:00
|
|
|
** 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
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq x '(:a 1 "b" 2 c 3 :d ("foo" "bar") :j nil))
|
|
|
|
x
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
*** Functions
|
|
|
|
- ~plist-get~ or ~lax-plist-get~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(plist-get x :a)
|
|
|
|
(plist-get x "b")
|
|
|
|
(lax-plist-get x "b")
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~plist-put~ or ~lax-plist-put~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(plist-put x :z 325)
|
|
|
|
(plist-put x :z 10)
|
|
|
|
(lax-plist-put x "b" 20)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~plist-member~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(plist-get x :j)
|
|
|
|
(plist-get x :g)
|
|
|
|
(plist-member x :j)
|
|
|
|
(plist-member x :g)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** An example use case of plist
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(defun foo (&rest args)
|
|
|
|
(message "ARGS: %s" args)
|
|
|
|
(plist-get args :name))
|
|
|
|
|
|
|
|
(foo :age 20 :name 'bob "blah" '(12 34 4))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** 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
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq y '((:a . 1) ("b" . 2) (c . 3) (:d "foo" "bar")))
|
|
|
|
y
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
*** Functions
|
|
|
|
- ~assoc~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(assoc :a y)
|
|
|
|
(assoc "b" y)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~rassoc~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(rassoc 1 y)
|
|
|
|
(rassoc 3 y)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~assq~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(assq :a y)
|
|
|
|
(assq "b" y)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~alist-get~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(alist-get :a y)
|
|
|
|
(alist-get :z y "blah")
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- ~cons~
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(setq y1 (cons '(:z . 31) y))
|
|
|
|
(assoc :z y1)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** References
|
|
|
|
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html
|
|
|
|
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Plist-Access.html
|
|
|
|
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Plists-and-Alists.html
|
2022-06-18 18:37:14 +01:00
|
|
|
|
|
|
|
* Episode 7 - Basic Loops
|
|
|
|
** About previous episode
|
|
|
|
- Duplicate keys in an association list
|
|
|
|
- ~eval-defun~
|
|
|
|
** While
|
|
|
|
- Form:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(while CONDITION
|
|
|
|
...body...)
|
|
|
|
#+END_SRC
|
|
|
|
- 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:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(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))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** dolist
|
|
|
|
- It's a macro
|
|
|
|
- Form:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(dolist (element list [result])
|
|
|
|
...body...)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
- 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:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(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))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
** dotimes
|
|
|
|
- It's a macro too
|
|
|
|
- Form:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(dotimes (var number)
|
|
|
|
...body...)
|
|
|
|
#+END_SRC
|
|
|
|
- It's similar to ~dolist~ but iterates ~number~ of times
|
|
|
|
- ~var~ in will contains the number of current iteration
|
|
|
|
- Example:
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
|
|
(let ((foo 10))
|
|
|
|
(dotimes (x foo)
|
|
|
|
(message ">> %s" x)))
|
|
|
|
|
|
|
|
|
|
|
|
(let ((foo 10))
|
|
|
|
(macroexpand-1
|
|
|
|
'(dotimes (x foo)
|
|
|
|
(message ">> %s" x))))
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
* Episode 8 - More Loops
|
|
|
|
** Recursion
|
|
|
|
** Functional style loops
|