forked from FG42/FG42
884 lines
22 KiB
Org Mode
884 lines
22 KiB
Org Mode
#+TITLE: Emacs From Scratch - An Emacs tutorial for beginners
|
|
#+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
|
|
|
|
* 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:
|
|
#+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
|
|
|
|
* 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
|
|
#+BEGIN_SRC emacs-lisp
|
|
(defun foo (int)
|
|
(print int)
|
|
(when (> int 0)
|
|
(foo (- int 1))))
|
|
|
|
(foo 10)
|
|
#+END_SRC
|
|
|
|
** Functional style loops
|
|
*** Mapping functions Family
|
|
- ~mapcar~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(mapcar #'1+ '(1 2 3 4 5))
|
|
|
|
(mapcar (lambda (x) (* x x))
|
|
'(1 2 3 4))
|
|
#+END_SRC
|
|
|
|
- ~mapc~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(mapc #'1+ '(1 2 3 4 5))
|
|
(mapc #'print '(1 2 3 4 5))
|
|
#+END_SRC
|
|
|
|
- ~map-concat~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(mapconcat (lambda (x)
|
|
(format "[%s]" x))
|
|
'(1 2 3 4 5)
|
|
" <|> ")
|
|
#+END_SRC
|
|
|
|
*** Seq module
|
|
A collection of handy functions that operate on ~sequences~.
|
|
|
|
- ~seq-reduce~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(require 'seq)
|
|
|
|
(seq-reduce
|
|
|
|
(lambda (acc x)
|
|
(+ acc x))
|
|
|
|
'(1 2 3 4)
|
|
|
|
0)
|
|
#+END_SRC
|
|
|
|
- ~seq-filter~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(seq-filter (lambda (x) (< x 10))
|
|
'(8 12 22 9))
|
|
#+END_SRC
|
|
- ~seq-partition~
|
|
#+BEGIN_SRC emacs-lisp
|
|
(seq-partition '(a b c d e f) 2)
|
|
|
|
#+END_SRC
|
|
- ~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
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(defmacro inc (val)
|
|
(list #'1+ val))
|
|
|
|
(defmacro mydef (name val)
|
|
(list 'setq (intern (concat "my-" (symbol-name name))) val))
|
|
|
|
(defmacro foo (val)
|
|
(1+ val))
|
|
#+END_SRC
|
|
|
|
- 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
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(macroexpand-1 '(inc 10))
|
|
(macroexpand-1 '(mydef blah 20))
|
|
(print (macroexpand-1 '(when (> 10 5) (print "something"))))
|
|
|
|
#+END_SRC
|
|
|
|
** Feedback or question
|
|
- https://lxsameer.com
|
|
- [[https://twitter.com/lxsameer][@lxsameer]] on Twitter
|
|
|
|
* DONE Episode 10 - More on Macros
|
|
CLOSED: [2022-11-04 Fri 15:25]
|
|
** 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
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
`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)
|
|
#+END_SRC
|
|
|
|
** ~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
|
|
Let's discuss ~defflag~ and ~when-flag~ macros in [[file:../core/fg42/flags.el]]
|
|
|
|
* DONE Episode 11 - Common pitfalls of Macros
|
|
CLOSED: [2022-12-04 Sun 12:15]
|
|
** Compiletime vs runtime
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; `do-something-with-side-effect' evaluates on compile time
|
|
;; in the macro's context
|
|
(defmacro wrong (x)
|
|
(when x
|
|
(do-something-with-side-effect x)))
|
|
|
|
;; `do-something-with-side-effect' evaluates on run time
|
|
;; in the caller's context
|
|
(defmacro correct (x)
|
|
(when x
|
|
`(do-something-with-side-effect ,x)))
|
|
#+END_SRC
|
|
** Variable Capture
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; `result' will hide any binding with the same name in the
|
|
;; parent scope
|
|
(defmacro wrong (f &rest body)
|
|
`(let ((result ,f))
|
|
(if result
|
|
,@body
|
|
(message "Failed: %s" result))))
|
|
|
|
(defvar result 1)
|
|
(wrong 200 (message "> %s" result))
|
|
|
|
;; Instead we need to generate a local binding
|
|
(defmacro correct (f &rest body)
|
|
(let ((var (gensym)))
|
|
`(let ((,var ,f))
|
|
(if ,var
|
|
,@body
|
|
(message "Failed: %s" ,var)))))
|
|
|
|
(defvar result 1)
|
|
(correct 200 (message "%s" result))
|
|
#+END_SRC
|
|
|
|
More on *uninterned* symbols: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html
|
|
|
|
** Many evaluation
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; The argument `x' will be evaluated 2 times in this example.
|
|
;; what if it contains side effects?
|
|
(defmacro wrong (x)
|
|
`(if ,x
|
|
(do-something-with ,x)
|
|
(do-somthing-else ,x)))
|
|
|
|
;; It's better to use a local binding for it and evaluate it
|
|
;; just once
|
|
(defmacro correct (x)
|
|
(let ((var (gensym)))
|
|
`(let ((,var ,x))
|
|
(if ,var
|
|
(do-something-with ,var)
|
|
(do-somthing-else ,var)))))
|
|
#+END_SRC
|
|
** Evaluating arguments of a macro
|
|
Never evaluate the arguments of a macro manually. E.g. with =eval=
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; `eval' here will be evaluated before the caller context
|
|
;; is even populated
|
|
(defmacro wrong (x)
|
|
(list 'setq (eval x) 'blah))
|
|
|
|
;; The correct way is to mark `x' for evaluation instead
|
|
(defmacro correct (x)
|
|
`(setq ,x 'blah))
|
|
#+END_SRC
|
|
|
|
More info: https://www.gnu.org/software/emacs/manual/html_node/elisp/Eval-During-Expansion.html
|
|
** What's next?
|
|
* DONE Episode 12 - Features & Load Paths
|
|
CLOSED: [2023-01-14 Sat 11:44]
|
|
** Emacs Lisp files
|
|
Write elisp code in files with =.el= suffix.
|
|
|
|
*** Batch mode
|
|
Execute an elisp file via Emacs in a non-interactive (script like) fashion:
|
|
|
|
#+BEGIN_SRC bash
|
|
emacs --batch -l /path/to/the/file
|
|
#+END_SRC
|
|
|
|
*** =load= function
|
|
Loads an elisp file into the running Emacs process. For more info ~C-h f load~.
|
|
#+BEGIN_SRC emacs-lisp
|
|
(load "/path/to/the/file")
|
|
(load "PATH1")
|
|
#+END_SRC
|
|
|
|
- It first looks for the =PATH + .elc= combination
|
|
- If not successful, looks for the =PATH + .el= combination
|
|
- If not successful, looks for platform dependent suffixes
|
|
- If not successful, tries to load the =PATH= as it is
|
|
|
|
** Load Path
|
|
*** =load-path=
|
|
List of directories to search for files to load.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(add-to-list 'load-path "/path/to/a/directory")
|
|
#+END_SRC
|
|
|
|
*** =EMACSLOADPATH= environment variable
|
|
|
|
** Emacs =feature=
|
|
Emacs tracks loaded packages and file via =features=. Each elisp file can =provide=, zero or
|
|
more =features=.
|
|
|
|
Features are just symbols.
|
|
|
|
*** =features= list
|
|
A list of all loaded features. For more info, try ~C-h v features~.
|
|
|
|
*** =featurep=
|
|
A predicate function to check whether a feature is loaded or not.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(featurep 'some-feature)
|
|
#+END_SRC
|
|
|
|
*** =provide=
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(provide 'some-feature)
|
|
#+END_SRC
|
|
|
|
*** =require=
|
|
If the given feature as the parameter is not loaded yet, loads it via the =load=
|
|
function. For more info, ~C-h f require~.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(require 'some-feature)
|
|
|
|
;; Or
|
|
|
|
(require 'some-feature "/path/to/file")
|
|
#+END_SRC
|
|
|
|
** Installing Emacs packages the hard way
|
|
We can clone a library somewhere on the disk and add the path to it to the =load-path= list
|
|
and load the library files.
|
|
|
|
But that would be tedious to do so for all the libraries. That's why we use a package manager
|
|
* Episode 13 - Editing Modes, Part 1
|
|
Emacs provides a concept called ~editing mode~ that allows
|
|
us to control different aspect of the editor.
|
|
|
|
** Major Modes
|
|
Major modes are mutually exclusive, so each Buffer has exactly on
|
|
major mode and just one major mode can be active at any given
|
|
time. So, it is possible to switch between different major modes.
|
|
|
|
Major modes control the main behaviour of your editor for each buffer.
|
|
For example, The active major mode might:
|
|
|
|
- Provide syntax highlighter
|
|
- Control the indentation
|
|
- Provide a local =keymap=
|
|
- ...
|
|
|
|
To put it simply, major modes are specialized to handle certain files
|
|
and buffers.
|
|
|
|
*** Naming Convenstion
|
|
Usually, the name of a major mode is like =<major-mode-name>-mode= which is
|
|
an interactive function that we can call either directly or via =M-x= interface.
|
|
For example:
|
|
|
|
- python-mode
|
|
- fundamental-mode
|
|
- emacs-lisp-mode
|
|
- ...
|
|
|
|
**** Keymap
|
|
*We will take about Keymaps in the future*
|
|
|
|
Major modes usually have a keymap to hold their local keybindings that has the
|
|
the =-map= suffix.
|
|
|
|
**** Hooks
|
|
*We will take about Hooks in the future*
|
|
|
|
Hooks are lists of functions that can be called on certain occasions. For example,
|
|
after a major mode activates.
|
|
|
|
Usually major modes come with at least one hook called =<major-mode-name>-hook= that
|
|
runs after the major mode activates. E.g. =emacs-lisp-mode-hook= or =python-mode-hook=.
|
|
|
|
*** How Emacs choose a major mode for a buffer?
|
|
When we open a file, Emacs goes through some hoops to figure out what major mode
|
|
should it choose for that buffer.
|
|
|
|
To put it simply and avoid a lot of details, Emacs will try to match the buffer name
|
|
against the keys in ~auto-mode-alist~ and uses the mode provided by that key as a value.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(("\\`/tmp/fol/" . text-mode)
|
|
("\\.texinfo\\'" . texinfo-mode)
|
|
("\\.texi\\'" . texinfo-mode)
|
|
|
|
("\\.el\\'" . emacs-lisp-mode)
|
|
("\\.c\\'" . c-mode)
|
|
("\\.h\\'" . c-mode)
|
|
…)
|
|
#+END_SRC
|
|
|
|
For more info check out:
|
|
https://www.gnu.org/software/emacs/manual/html_node/elisp/Auto-Major-Mode.html
|
|
|
|
*** How to switch the major mode
|
|
Just call the other mode or
|
|
- ~major-mode-suspend~: Kills all the buffer local variables and record them
|
|
- ~major-mode-restore~: This function restores the major mode recorded by ~major-mode-suspend~
|
|
|
|
For more info:
|
|
https://www.gnu.org/software/emacs/manual/html_node/elisp/Major-Modes.html
|
|
|
|
** Minor Modes
|
|
A minor mode provides optional features that users may enable or disable independently of
|
|
the choice of major mode. Minor modes can be enabled individually or in combination.
|
|
|
|
The main difference with major modes is that minor modes are not mutually exclusive and
|
|
are not tied to buffers. They can operate globally or local to buffers.
|
|
|
|
*** How to enable/disable minor modes?
|
|
In order to toggle a minor mode we just have to call its function with no argument
|
|
*interactively*. In order to disable a minor mode we can pass a negative integer,
|
|
and to enable it we can pass a positive integer.
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; Enable
|
|
(blah-mode 1)
|
|
|
|
;; Disable
|
|
(blah-mode -1)
|
|
#+END_SRC
|
|
|
|
** Useful functions and variables
|
|
- ~describe-mode~: Display documentation of current major mode and minor modes and a brief
|
|
summary of the state of the current buffer.
|
|
- ~local-minor-modes~: This buffer-local variable lists the currently enabled minor modes
|
|
in the current buffer, and is a list of symbols.
|
|
- ~global-minor-modes~: This variable lists the currently enabled global minor modes,
|
|
and is a list of symbols.
|
|
- ~minor-mode-list~: The value of this variable is a list of all minor mode commands.
|