#+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 * 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 - 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 * 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 - numberp - stringp - listp - boundp - More at https://www.gnu.org/software/emacs/manual/html_node/elisp/Type-Predicates.html ** 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) #+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 * 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 #+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 * 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