├── .gitignore ├── Makefile ├── README ├── _build └── html │ └── .buildinfo ├── conf.py ├── contents ├── best-practice-1-writing-better-elisp.rst ├── contributors.rst ├── elisp-is-a-lisp.rst ├── emacs-and-the-dot-emacs-file.rst ├── getting-started.rst ├── learning-elisp.rst ├── lesson-1-1-using-emacs.rst ├── lesson-2-1-first-elisp-programme.rst ├── lesson-2-2-primitive-data-types-1.rst ├── lesson-2-3-lists-at-last.rst ├── lesson-2-4-symbols-and-variables.rst ├── lesson-2-5-arrays-and-sequences.rst ├── lesson-3-1-writing-functions.rst ├── lesson-3-2-more-functions.rst ├── lesson-4-1-writing-elisp-in-emacs.rst ├── lesson-4-2-adding-custom-functions-to-emacs.rst ├── lesson-4-3-emacs-menus.rst ├── lesson-4-4-adding-buttons-to-the-toolbar.rst ├── lesson-5-1-elisp-in-files.rst ├── lesson-5-2-working-with-buffers-1.rst ├── lesson-5-3-scope-of-variables-set-setq-let-etc.rst ├── lesson.template ├── major-and-minor-modes.rst ├── other-formats.rst ├── references.rst ├── the-learn-elisp-for-emacs-community.rst ├── ttd.rst ├── what-will-this-book-cover.rst ├── who-is-this-book-for.rst └── why-did-I-write-this-book.rst ├── images ├── elisp-sequences.png ├── emacs-components.png ├── emacs-customization-groups.png ├── emacs-debugger.png ├── emacs-debugger2.png ├── emacs-font-dialog-box.png ├── emacs-lisp.png ├── emacs-using-describe-function.png ├── emacs.png ├── learn-elisp-for-emacs.png └── synaptic_package_manager.png ├── index.rst └── make.bat /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | *~ 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | 15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " pickle to make pickle files" 22 | @echo " json to make JSON files" 23 | @echo " htmlhelp to make HTML files and a HTML help project" 24 | @echo " qthelp to make HTML files and a qthelp project" 25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 26 | @echo " changes to make an overview of all changed/added/deprecated items" 27 | @echo " linkcheck to check all external links for integrity" 28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 29 | 30 | clean: 31 | -rm -rf $(BUILDDIR)/* 32 | 33 | html: 34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 35 | @echo 36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 37 | 38 | dirhtml: 39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 40 | @echo 41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 42 | 43 | pickle: 44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 45 | @echo 46 | @echo "Build finished; now you can process the pickle files." 47 | 48 | json: 49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 50 | @echo 51 | @echo "Build finished; now you can process the JSON files." 52 | 53 | htmlhelp: 54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 55 | @echo 56 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 57 | ".hhp project file in $(BUILDDIR)/htmlhelp." 58 | 59 | qthelp: 60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 61 | @echo 62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LearneLispTheHardWay.qhcp" 65 | @echo "To view the help file:" 66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LearneLispTheHardWay.qhc" 67 | 68 | latex: 69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 70 | @echo 71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 73 | "run these through (pdf)latex." 74 | 75 | changes: 76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 77 | @echo 78 | @echo "The overview file is in $(BUILDDIR)/changes." 79 | 80 | linkcheck: 81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 82 | @echo 83 | @echo "Link check complete; look for any errors in the above output " \ 84 | "or in $(BUILDDIR)/linkcheck/output.txt." 85 | 86 | doctest: 87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 88 | @echo "Testing of doctests in the sources finished, look at the " \ 89 | "results in $(BUILDDIR)/doctest/output.txt." 90 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | INTRODUCTION 2 | ------------ 3 | 4 | This is the source code for the book *Learn Elisp The Hard Way* 5 | 6 | TO BUILD 7 | -------- 8 | 9 | To build the book from sources you need to install Sphinx 0.6.6. 10 | 11 | This is a package install on Ubuntu 10.10 12 | 13 | You also need to install the package texlive-full if you intend to build the PDF version of the book. 14 | -------------------------------------------------------------------------------- /_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 4f415f4b45c192b1a63cd2662957dad0 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Learn ELisp For Emacs build configuration file, created by 4 | # sphinx-quickstart on Sat Nov 6 22:31:37 2010. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.append(os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # Add any Sphinx extension module names here, as strings. They can be extensions 24 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 25 | extensions = ['sphinx.ext.todo'] 26 | 27 | # Add any paths that contain templates here, relative to this directory. 28 | templates_path = ['_templates'] 29 | 30 | # The suffix of source filenames. 31 | source_suffix = '.rst' 32 | 33 | # The encoding of source files. 34 | #source_encoding = 'utf-8' 35 | 36 | # The master toctree document. 37 | master_doc = 'index' 38 | 39 | # General information about the project. 40 | project = u'Learn Elisp For Emacs (Draft In Progress)' 41 | copyright = u'2010, Gordon Guthrie' 42 | 43 | # The version info for the project you're documenting, acts as replacement for 44 | # |version| and |release|, also used in various other places throughout the 45 | # built documents. 46 | # 47 | # The short X.Y version. 48 | version = '0.1' 49 | # The full version, including alpha/beta/rc tags. 50 | release = '0.1.1' 51 | 52 | # The language for content autogenerated by Sphinx. Refer to documentation 53 | # for a list of supported languages. 54 | #language = None 55 | 56 | # There are two options for replacing |today|: either, you set today to some 57 | # non-false value, then it is used: 58 | #today = '' 59 | # Else, today_fmt is used as the format for a strftime call. 60 | #today_fmt = '%B %d, %Y' 61 | 62 | # List of documents that shouldn't be included in the build. 63 | #unused_docs = [] 64 | 65 | # List of directories, relative to source directory, that shouldn't be searched 66 | # for source files. 67 | exclude_trees = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # The theme to use for HTML and HTML Help pages. Major themes that come with 93 | # Sphinx are currently 'default' and 'sphinxdoc'. 94 | html_theme = 'default' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | html_theme_options = {"rightsidebar": "false", 100 | "footerbgcolor": "#eee", 101 | "footertextcolor": "#666", 102 | "sidebarbgcolor": "#ccc", 103 | "sidebartextcolor": "#444", 104 | "sidebarlinkcolor": "#449", 105 | "relbarbgcolor": "#ddd", 106 | "relbartextcolor": "#555", 107 | "relbarlinkcolor": "#449", 108 | "bgcolor": "white", 109 | "textcolor": "#444", 110 | "linkcolor": "#449", 111 | #"visitedlinkcolor": "purple", 112 | "headbgcolor": "#eef", 113 | "headtextcolor": "black", 114 | "headlinkcolor": "blue", 115 | "codebgcolor": "grey", 116 | "codetextcolor": "black", 117 | "bodyfont": "calibri, sans-serif", 118 | "headfont": "verdana, serif" 119 | } 120 | 121 | # Add any paths that contain custom themes here, relative to this directory. 122 | #html_theme_path = [] 123 | 124 | # The name for this set of Sphinx documents. If None, it defaults to 125 | # " v documentation". 126 | html_title = 'Learn Elisp For Emacs (Draft In Progress)' 127 | 128 | # A shorter title for the navigation bar. Default is the same as html_title. 129 | #html_short_title = None 130 | 131 | # The name of an image file (relative to this directory) to place at the top 132 | # of the sidebar. 133 | #html_logo = None 134 | 135 | # The name of an image file (within the static path) to use as favicon of the 136 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 137 | # pixels large. 138 | #html_favicon = None 139 | 140 | # Add any paths that contain custom static files (such as style sheets) here, 141 | # relative to this directory. They are copied after the builtin static files, 142 | # so a file named "default.css" will overwrite the builtin "default.css". 143 | html_static_path = ['_static'] 144 | 145 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 146 | # using the given strftime format. 147 | #html_last_updated_fmt = '%b %d, %Y' 148 | 149 | # If true, SmartyPants will be used to convert quotes and dashes to 150 | # typographically correct entities. 151 | #html_use_smartypants = True 152 | 153 | # Custom sidebar templates, maps document names to template names. 154 | html_sidebars = { 155 | #'index' : 'comments.html', ## removed for compatibility with Sphinx 1. 156 | } 157 | 158 | # Additional templates that should be rendered to pages, maps page names to 159 | # template names. 160 | #html_additional_pages = {} 161 | 162 | # If false, no module index is generated. 163 | #html_use_modindex = True 164 | 165 | # If false, no index is generated. 166 | html_use_index = True 167 | 168 | # If true, the index is split into individual pages for each letter. 169 | #html_split_index = False 170 | 171 | # If true, links to the reST sources are added to the pages. 172 | html_show_sourcelink = False 173 | 174 | # If true, an OpenSearch description file will be output, and all pages will 175 | # contain a tag referring to it. The value of this option must be the 176 | # base URL from which the finished HTML is served. 177 | #html_use_opensearch = '' 178 | 179 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 180 | #html_file_suffix = '' 181 | 182 | # Output file base name for HTML help builder. 183 | htmlhelp_basename = 'Learn-Elisp-For-Emacsdoc' 184 | 185 | # -- Options for LaTeX output -------------------------------------------------- 186 | 187 | # The paper size ('letter' or 'a4'). 188 | #latex_paper_size = 'A4' 189 | 190 | # The font size ('10pt', '11pt' or '12pt'). 191 | #latex_font_size = '12pt' 192 | 193 | # Grouping the document tree into LaTeX files. List of tuples 194 | # (source start file, target name, title, author, documentclass [howto/manual]). 195 | latex_documents = [ 196 | ('index', 'Learn-Elisp-For-Emacs.tex', u'Learn Elisp For Emacs', 197 | u'Gordon Guthrie', 'manual'), 198 | ] 199 | 200 | # The name of an image file (relative to this directory) to place at the top of 201 | # the title page. 202 | #latex_logo = None 203 | 204 | # For "manual" documents, if this is true, then toplevel headings are parts, 205 | # not chapters. 206 | #latex_use_parts = False 207 | 208 | # Additional stuff for the LaTeX preamble. 209 | #latex_preamble = '' 210 | 211 | # Documents to append as an appendix to all manuals. 212 | #latex_appendices = [] 213 | 214 | # If false, no module index is generated. 215 | #latex_use_modindex = True 216 | -------------------------------------------------------------------------------- /contents/best-practice-1-writing-better-elisp.rst: -------------------------------------------------------------------------------- 1 | ====================================== 2 | Best Practice 1 - Writing Better Elisp 3 | ====================================== 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | So far we have knocked up quick'n'dirty Elisp. As we get deeper into writing Elisp it is important to start following best practices to try and make sure our code is clean, good and easy to maintain. 10 | 11 | Best practices will be introduced in small chapters like this. 12 | 13 | ------------------------------ 14 | Avoiding Name Space Collisions 15 | ------------------------------ 16 | 17 | Emacs (and the Elisp it is written in) uses a lot of global state to manage itself. One of the problems with global state is that it can lead to developers accidentally overwriting other peoples function definitions and variables through name space collisions. 18 | 19 | When writing custom code for Emacs you should choose a name that describes what you are doing and use that as a prefix on all your variable and function definitions. 20 | 21 | For the rest of this book our chosen name is *omar*. Why omar? I like *The Wire* so why not. 22 | 23 | ----------------------------- 24 | Which Keys Should You Bind To 25 | ----------------------------- 26 | 27 | Emacs as an editor has an emphasis on keyboard shortcuts. There are lots of different add-ons and packages, major and minor modes, all of which use keyboard short cuts. 28 | 29 | If you start binding functions to key combinations randomly you may well start breaking other parts of Emacs. 30 | 31 | There are a complex set of conventions about which keys you should use - but we will conform to the most basic set of there here. 32 | 33 | The following keys are reserved for the use of users: 34 | 35 | * *[F5]* to *[F9]* 36 | * *[C-c][a]* to *[C-c][z]* 37 | 38 | We will follow these conventions. 39 | 40 | ------------------ 41 | Additional Reading 42 | ------------------ 43 | 44 | There are more `Coding Conventions`_ for writing Elisp additional and rules about `Key-Binding Conventions`_ in the *Emacs Lisp Reference Manual*. 45 | 46 | .. _Coding Conventions: http://www.gnu.org/software/emacs/elisp/html_node/Coding-Conventions.html#Coding-Conventions 47 | 48 | .. _Key-Binding Conventions: http://www.gnu.org/s/emacs/manual/html_node/elisp/Key-Binding-Conventions.html#Key-Binding-Conventions 49 | -------------------------------------------------------------------------------- /contents/contributors.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributors 3 | ============ 4 | 5 | Thanks to the following for their corrections: 6 | 7 | * Justin Lilly 8 | * Kevin R Barnes 9 | * Luke Plant 10 | * Rafe Kettler 11 | * Yuanxuan Wang 12 | -------------------------------------------------------------------------------- /contents/elisp-is-a-lisp.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Elisp is a Lisp 3 | =============== 4 | 5 | There are many Lisps and ELisp is one of them. As you will see Lisp is a rich and complex language made from many small and fundamental components. 6 | 7 | Lisp has a long history going back to 1958 and over the years has spawned many dialects, including: 8 | 9 | * many variants of Common Lisp 10 | * Scheme 11 | * Clojure 12 | * Paul Graham's Arc 13 | 14 | One of the characteristics of Lisp is that Lisp programmes are also Lisp data. Many advanced Lisp techniques involve using meta-programming - the use of a Lisp to generate and execute Lisp programmes. 15 | 16 | One consequence of this is the various Lisp implementations have themselves diverged with different collections of libraries that can radically alter the 'flavour' of a particular dialect. 17 | 18 | This variance can make it hard to learn a Lisp from scratch. It if very difficult for a beginner to untangle the various dialects from each other. 19 | 20 | This book very much focused on Elisp and largely eschews any discussion of other dialects to avoid complicating things for people learning, what is in many cases, a radically different way for programming. 21 | 22 | There are a small number of places where other Lisp implementations will be discussed, but they are all paranthetic to the main book - and none of them will be in the *lessons* themselves. 23 | 24 | Other Lisp Resources 25 | -------------------- 26 | 27 | There are a number of freely available Lisp books, including: 28 | 29 | * `On Lisp`_ 30 | * `Practical Common Lisp`_ 31 | 32 | There are also purchasable books, including: 33 | 34 | * `The Little Schemer`_ 35 | 36 | Although the focus of this book is on building Emacs tools, another intention is to teach enough Lisp that a beginner can cheerfully use the extensive Emacs Lisp reference documentation, and feel confident to try out other dialects of Lisp. 37 | 38 | .. _On Lisp: http://www.paulgraham.com/onlisptext.html 39 | .. _Practical Common Lisp: http://gigamonkeys.com/book/ 40 | .. _The Little Schemer: http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=4825 41 | -------------------------------------------------------------------------------- /contents/emacs-and-the-dot-emacs-file.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Emacs And The .emacs File 3 | ========================= 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | We will be using the `.emacs` file a lot to get our functionality into Emacs. Emacs itself also uses the `.emacs` file. Let's see how it uses it. 10 | 11 | -------------- 12 | Saving Options 13 | -------------- 14 | 15 | Emacs saves some of your options in the `.emacs` file. Let's change some options, save them and then see how they appear. 16 | 17 | Start by clearing the `.emacs` file - open it in an editor, delete all the contents and save it. (You might want to copy it elsewhere if it has stuff in it you really care about). 18 | 19 | If you edited it in Emacs you will need to close Emacs and reopen it to 'lose' all your old configuration - if you edited it in an other editor, simply open Emacs. 20 | 21 | We are going to do some simple changes to our default fonts and then save them. 22 | 23 | Use the menu item *Options -> Set Default Fonts...* and you will get the standard font dialog box: 24 | 25 | .. image :: /images/emacs-font-dialog-box.png 26 | 27 | Choose a different font, size, weight etc etc. Your open buffers will redraw with the new fonts. 28 | 29 | Now save the options with the menu item *Options -> Save Options*. 30 | 31 | Notice that the modeline now says something like `Wrote /home/gordonguthrie/.emacs` - obviously it will have your name in it and not mine. 32 | 33 | Now open the `.emacs` file. Mine looks like: 34 | 35 | :: 36 | 37 | (custom-set-variables 38 | ;; custom-set-variables was added by Custom. 39 | ;; If you edit it by hand, you could mess it up, so be careful. 40 | ;; Your init file should contain only one such instance. 41 | ;; If there is more than one, they won't work right. 42 | ) 43 | (custom-set-faces 44 | ;; custom-set-faces was added by Custom. 45 | ;; If you edit it by hand, you could mess it up, so be careful. 46 | ;; Your init file should contain only one such instance. 47 | ;; If there is more than one, they won't work right. 48 | '(default ((t (:inherit nil :stipple nil :background "white" :foreground "black" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 143 :width normal :foundry "bitstream" :family "Courier 10 Pitch"))))) 49 | 50 | Emacs has *saved options* into the `.emacs` file. Emacs marks the code that it adds with quotes as above. If you see big chunks of code like this in your `.emacs` file - that's what it is. Don't panic. 51 | 52 | --------------------- 53 | What You Have Learned 54 | --------------------- 55 | 56 | You have learned not to worry about finding strange code in your `.emacs` file. 57 | 58 | ---------------- 59 | Extra Activities 60 | ---------------- 61 | 62 | You can really customise Emacs with the menu item *Options -> Customise Emacs - > Browse Customization Groups*. 63 | 64 | This should open up a page that looks like this: 65 | 66 | .. image :: /images/emacs-customization-groups.png 67 | 68 | Have a play with the various options and see what happens to your `.emacs` file when you save them. 69 | -------------------------------------------------------------------------------- /contents/getting-started.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Getting Started 3 | =============== 4 | 5 | -------------------------- 6 | What Needs To Be Installed 7 | -------------------------- 8 | 9 | This book assumes that you have a clean install of Ubuntu 10.10 Desktop which can be obtained `from Ubuntu`_. 10 | 11 | Having created a clean install the Emacs package (version 23.1+1-4ubunutu7) should be installed. 12 | 13 | This can be done by: 14 | 15 | * selecting the Ubuntu menu `System -> Administration -> Synaptic Package Manager` 16 | * use the Quick search input box in the top right 17 | * select `emacs` by clicking the tick box in the first column 18 | * click the `Apply` button and click `Apply` in the Summary dialog box 19 | 20 | .. image :: /images/synaptic_package_manager.png 21 | 22 | A dialog box entitled `Applying Changes` will appear. When the changes have been applied you may close the dialog box. 23 | 24 | **Please** only install the Emacs package as indicated. The exercises in this book are predicated on that being the case. 25 | 26 | ----------------------- 27 | How This Book Will Work 28 | ----------------------- 29 | 30 | The work on learning Elisp will take place within an X-Windows enabled version of Emacs as shown below. 31 | 32 | .. image :: /images/emacs.png 33 | 34 | 35 | .. _from Ubuntu: http://www.ubuntu.com/desktop/get-ubuntu/alternative-download 36 | -------------------------------------------------------------------------------- /contents/learning-elisp.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Learning Elisp 3 | ============== 4 | 5 | -------------------- 6 | Who This Book Is For 7 | -------------------- 8 | 9 | This book is for people who can already programme, but who are not familiar with functional programming. It is suitable for most programmers with experience in popular programming languages like Ruby, Java, Python, Perl, C, C++ and so on. 10 | 11 | It assumes that the reader can get a clean install of Ubuntu GNU/Linux up and running. 12 | 13 | --------------------------- 14 | How This Book Teaches Elisp 15 | --------------------------- 16 | 17 | This book teaches Elisp through the medium of Emacs. Emacs has a *scratch* window in which arbitrary Elisp expressions can be evaluated. Initial lessons will use the *scratch* window. Later lessons will move on to creating external lisp files and loading them into Emacs to use them. 18 | -------------------------------------------------------------------------------- /contents/lesson-1-1-using-emacs.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Lesson 1-1 - Using Emacs 3 | ======================== 4 | 5 | -------------- 6 | Learning Emacs 7 | -------------- 8 | 9 | This book is not designed to teach you how to use Emacs. It will teach you enough Emacs to complete the work in this book, but not more. 10 | 11 | If you want to learn to use Emacs then you should consider buying a book - I recommend `Learning Gnu Emacs`_. 12 | 13 | ---------------- 14 | Emacs Components 15 | ---------------- 16 | 17 | The version of Emacs we are using has 5 components on it: 18 | 19 | * a menubar 20 | * a toolbar 21 | * a window area (it is possible to have multiple window views) 22 | * a mode line 23 | * a minibuffer 24 | 25 | These are used for different things and are marked on the diagram below: 26 | 27 | .. image :: /images/emacs-components.png 28 | 29 | A file is referred to as a buffer - and a window is therefore a view of a buffer. 30 | 31 | ---------- 32 | Emacs Keys 33 | ---------- 34 | 35 | Emacs is primarily a keyboard-focused editor. The version we are using has mouse-friendly components (the menu bar, the toolbar) but they are very much tacked on. In a lot of environments the non-X Windows version isn't supported so learning the key short cuts for **all** menu actions is essential. 36 | 37 | In this book the various keyboard short cuts will be introduced as needed. There are two keys that you will need to know about. 38 | 39 | Emacs uses so-called key modifiers to implement keyboard shortcuts. The two important ones are the Control Key (`[Ctrl]` on your keyboard) and the Meta Key (`[Alt]` on your keyboard). Some keyboard shortcuts require you to use both of them at the same time. 40 | 41 | The most common key modifier on the keyboard is the Shift Key `[Shift]`. Control and Meta/Alt work in the same way. You implement Control-x by pressing `[Ctrl]` first, and then, whilst holding it down, pressing `x` - the same way as you do Shift-x. 42 | 43 | Where keyboard commands are required in this book they will be spelled out, but in other publications online (or the Emacs help) they are often written in a contracted form like C-x or M-x. 44 | 45 | .. _Learning Gnu Emacs: http://oreilly.com/catalog/9781565921528 46 | -------------------------------------------------------------------------------- /contents/lesson-2-1-first-elisp-programme.rst: -------------------------------------------------------------------------------- 1 | ================================== 2 | Lesson 2-1 - First Elisp Programme 3 | ================================== 4 | 5 | ----------------- 6 | Let's Get Started 7 | ----------------- 8 | 9 | This lesson will show you how to execute your first Elisa programme. 10 | 11 | * start Emacs 12 | * go to the scratch buffer by using the menu `Buffers -> \*scratch\*` 13 | 14 | :You Type: ``(+ 1 2)`` 15 | 16 | Then put the cursor at the **end** of the expression - that is to say after the right bracket and type ``Control-j`` 17 | 18 | :Result: ``3`` 19 | 20 | What you typed in consists of an expression ``(+ 1 2)`` and a command to Emacs to execute it ``[Control-j]``. Expressions are sometimes called *forms*. 21 | 22 | Elisp is a dialect of Lisp - which stands for List Processing. A list is any thing between two brackets ``(`` and ``)`` 23 | 24 | The programme that was executed consisted of an operator ``+`` and two constants ``1`` and ``2`` 25 | 26 | The command ``Control-j`` in Emacs is applied at the point where the cursor is - it evaluates all the Elisp in the window up to that point and prints the output. 27 | 28 | Let's look at executing the same expression in a different way. Delete the expression in the \*scratch\* buffer and type in a new one. 29 | 30 | :You Type: ``(+ 1.0 2.0)`` 31 | 32 | Now put the cursor in the **middle** of the expression - that is to say between the brackets and type ``Control-Alt-x`` 33 | 34 | :Result: In the window nothing will change. The result of the expression is now put in the *minibuffer* ``3.0`` 35 | 36 | It seems as if the way in which you evaluate the expression determines where the output goes - that is a bit of a simplification. See the *Advanced* sub-section for a deeper discussion. Also notice that the previous examples used integers like ``1`` and ``2`` and returned an integer value. This expression uses floating point numbers like ``1.0`` and returns a float as the result. 37 | 38 | :You Type: ``(+ 1.0e+3 2.0e-2)`` 39 | 40 | Now put the cursor at the **end** of the expression and type ``Control-x Control-e`` 41 | 42 | :Result: In the window nothing will change by the value is now placed in the *minibuffer* ``1000.02`` 43 | 44 | You can express floating point numbers in scientific notation. 45 | 46 | -------------------- 47 | What You Have Learnt 48 | -------------------- 49 | 50 | You have learnt how to evaluate a basic Elisp expression (or form) in the scratch buffer. 51 | 52 | **In future lessons you will not be told how to evaluate an expression - be sure to remember the key sequences to do it.** 53 | 54 | ------------------ 55 | Additional Reading 56 | ------------------ 57 | 58 | There is a section on data types in the `GNU Emacs Lisp Reference Manual`_. 59 | 60 | -------- 61 | Advanced 62 | -------- 63 | 64 | Elisp, like all the Lisp family, is a functional language. In functional languages there is a strict differences between a pure function and a function which has side effects. 65 | 66 | A pure function is one which takes some parameters and returns a value - the same input parameters reliably returning the same value. 67 | 68 | A function with side-effects interacts with the outside world: it writes to a file, or it sets a global variable. Sometimes it lets the outside world in - for instance a function that returns a random number. 69 | 70 | In this section we talk about evaluating expression and them returning values to the \*scratch\* buffer or the modeline. In fact, we evaluate a function which evaluates an expression and then, as a side effect, writes the return value to \*scratch\* or the modeline. 71 | 72 | This might seem an esoteric distinction now, but it is important and will become even more later on. 73 | 74 | ---------------- 75 | Extra Activities 76 | ---------------- 77 | 78 | Try some expressions that add integers to floats. What is the result? 79 | 80 | What happens if you use scientific integers like ``1e+10``? 81 | 82 | Can you add negative numbers? 83 | 84 | What do you think the following expressions will return? 85 | 86 | | ``(- 3 4)`` 87 | | ``(* 4 5)`` 88 | | ``(/ 1.0 4.0)`` 89 | 90 | Evaluate the following expressions and try and work out why they return what they do? 91 | 92 | | ``(/ 1 4)`` 93 | | ``(/ 1 4.)`` 94 | 95 | What do you think these symbols represent? 96 | 97 | | ``#b10101010`` 98 | | ``#o127`` 99 | | ``#x12DE`` 100 | | (**Tip**: try using them in arithmetic expressions) 101 | 102 | What do you think these symbols represent? 103 | 104 | | ``1.0e+INF`` 105 | | ``-1.0e+INF`` 106 | | ``0.0e+NaN`` or ``-0.0e+NaN`` 107 | 108 | .. _GNU Emacs Lisp Reference Manual: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/Numbers.html#Numbers 109 | -------------------------------------------------------------------------------- /contents/lesson-2-2-primitive-data-types-1.rst: -------------------------------------------------------------------------------- 1 | ===================================== 2 | Lesson 2-2 - Primitive Data Types (1) 3 | ===================================== 4 | 5 | **Prerequisite:** This lesson presumes you know how to invoke Elisp expression as shown in Lesson 2-1. 6 | 7 | ------- 8 | Context 9 | ------- 10 | 11 | The previous lessons looked at performing basic arithmetic operations on various sorts of numbers. 12 | 13 | This lessons will look at the other sorts of data types in Elisp. There are two different sorts of data types: 14 | 15 | * primitive data types 16 | * non-primitive data types 17 | 18 | The difference between them is that non-primitive data types can be assembled from primitive ones. 19 | 20 | The general set of primitive data types of Elisp are: 21 | 22 | * integer 23 | * float 24 | * string 25 | * character 26 | * bool-vector 27 | * symbol 28 | * sequence 29 | * cons 30 | * array 31 | * vector 32 | * char-table 33 | * hash-table 34 | * function 35 | * primitive function (or subr) 36 | * macro 37 | * byte-code 38 | * auto-load 39 | 40 | These primitive data types largely correspond to the primitive data types of other Lisps. 41 | 42 | In addition Elisp has a number of data types that are peculiar to it, because they pertain to the fact that Elisp is the scripting language of an editor. These data types are: 43 | 44 | * buffer 45 | * marker 46 | * window 47 | * frame 48 | * terminal 49 | * window configuration 50 | * frame configuration 51 | * process 52 | * stream 53 | * keymap 54 | * overlay 55 | * font 56 | 57 | .. warning:: 58 | 59 | don't really understand types, primitive and otherwise... 60 | 61 | --------------------------- 62 | What This Lesson Will Cover 63 | --------------------------- 64 | 65 | This lesson will look at: 66 | 67 | * the representation of boolean values 68 | * the integer and float data types which were introduced earlier 69 | * the string data type 70 | * testing for data types 71 | * casting between values 72 | 73 | -------- 74 | Booleans 75 | -------- 76 | 77 | Booleans represent *true* and *false*. 78 | 79 | :You Type: ``(= 1 1)`` 80 | :Result: ``t`` 81 | 82 | This function tests for equality. The value ``t`` is a boolean (ie means *true*). This expression (which means *is 1 equal to 1*) is easy to switch to test for false. 83 | 84 | :You Type: ``(= 1 2)`` 85 | :Result: ``nil`` 86 | 87 | The value ``nil`` is the second boolean it means *false*. The two values ``t`` and ``nil`` are *constant values* that always evaluate to themselves. 88 | 89 | We can use the function ``if`` to investigate the boolean types. ``if`` takes three parameters, it is a standard ternary if function familiar from other langauges. 90 | 91 | :You Type: ``(if t "it's true" "it's false")`` 92 | :Result: ``"it's true"`` 93 | 94 | You can read the if expression like this ``if t`` *is true then return* ``"it's true"`` *if it isn't then return* ``"it's false"``. 95 | 96 | :You Type: ``(if nil "it's true" "it's false")`` 97 | :Result: ``"it's false"`` 98 | 99 | However booleans are not types. They are called *Constant Variables*. 100 | 101 | Handling *true/false* is not so simple, however. Consider the following: 102 | 103 | :You Type: ``(if () "it's true" "it's false")`` 104 | :Result: ``"it's false"`` 105 | 106 | The empty list ``()`` is also a synomym for false. ``if``, however, follows the convention that *that which is not false is true* as we can see from the following: 107 | 108 | :You Type: ``(if 101 "it's true" "it's false")`` 109 | :Result: ``"it's true"`` 110 | 111 | ------- 112 | Strings 113 | ------- 114 | 115 | We have seen string data types being used in the previous tests - strings are represented by characters between double quotes. 116 | 117 | :You Type: ``(concat "ab" "cd")`` 118 | :Result: ``"abcd"`` 119 | 120 | ``concat`` is just a string concatenation function. The strings can include single quotes and escaped double quotes. 121 | 122 | :You Type: ``(concat "a`b" "c\"d")`` 123 | :Result: ``"a'bc\"d"`` 124 | 125 | The ``concat`` operator can have a indefinite number of arguments. 126 | 127 | :You Type: ``(concat "ab" "cd" "ef" "12" "34" "45")`` 128 | :Result: ``"abcdef123445"`` 129 | 130 | ------------------------------------------------- 131 | Predicate Functions - Testing The Types Of Vaules 132 | ------------------------------------------------- 133 | 134 | There are a whole class of functions that tests data types - the so-called *predicates*. 135 | 136 | :You Type: ``(integerp 11)`` 137 | :Result: ``t`` 138 | 139 | This predicate function (like most predicate functions) can be recognised by the fact that it ends in p 140 | 141 | :You Type: ``(integerp (+ 1 2.0))`` 142 | :Result: ``nil`` 143 | 144 | We see from this example that data types cast automatically. The sum of an integer and a float is a float - and the predicate therefore fails. 145 | 146 | Certain functions expect certain types - for instance ``+`` expects numbers as it parameters. 147 | 148 | :You Type: ``(+ 1 "two")`` 149 | :Result: The function throws an error and dumps you into the debugger. 150 | 151 | This is in a window called \*backtrace\*. It is worth looking at the output in some detail. 152 | 153 | :: 154 | 155 | Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p "two") 156 | +(1 "two") 157 | eval((+ 1 "two")) 158 | eval-last-sexp-1(t) 159 | eval-last-sexp(t) 160 | eval-print-last-sexp() 161 | call-interactively(eval-print-last-sexp nil nil) 162 | 163 | The first line of this give us some details of the problem, it is a Lisp error - the predicate function ``number-or-marker-p`` on the parameter ``two`` threw a ``wrong-type-argument`` error. We will look at the debugger later on in the book. If you go back to the list of Emacs specific types you will see that there is one called marker. The operator ``+`` can operate on numbers or markers and so it uses this special predicate function to test the arguments before running the function. 164 | 165 | ----------------------------- 166 | Converting Between Data Types 167 | ----------------------------- 168 | 169 | Sometimes Elisp converts between data types. Consider mixed arithmetic with integers and floating point numbers: 170 | 171 | :You Type: ``(+ 1 2.5)`` 172 | :Result: ``3.5`` 173 | 174 | The integer value of ``1`` has been *cast* to a floating point number. 175 | 176 | You can force this casting with functions: 177 | 178 | :You Type: ``(float 1)`` 179 | :Result: ``1.0`` 180 | 181 | You can turns numbers into string: 182 | 183 | :You Type: ``(number-to-string 1234)`` 184 | :Result: ``"1234"`` 185 | 186 | You can also cast strings which contain the numerical characters into numbers: 187 | 188 | :You Type: ``(string-to-number "1234")`` 189 | :Result: ``1234`` 190 | 191 | --------------------- 192 | What You Have Learned 193 | --------------------- 194 | 195 | We have seen the list of primitive and composite data types and have looked at a couple of the most common of them in some detail. We have seen how to test what data type an object it, and how to cast one data type to another. 196 | 197 | ------------------ 198 | Additional Reading 199 | ------------------ 200 | 201 | There is a section on data types in the `GNU Emacs Lisp Reference Manual`_. 202 | 203 | ---------------- 204 | Extra Activities 205 | ---------------- 206 | 207 | List gets its name from LIS(t) P(rocessing) - and yet lists don't appear as a primitive data types. From the additional reading can you work out why? 208 | 209 | What do the following predicate functions do: 210 | 211 | * ``floatp`` 212 | * ``numberp`` 213 | * ``zerop`` 214 | * ``wholenump`` 215 | 216 | What do the following functions do: 217 | 218 | * ``float`` 219 | * ``truncate`` 220 | * ``ceiling`` 221 | * ``floor`` 222 | 223 | .. _GNU Emacs Lisp Reference Manual: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/Lisp-Data-Types.html#Lisp-Data-Types 224 | -------------------------------------------------------------------------------- /contents/lesson-2-3-lists-at-last.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Lesson 2-3 - Lists (At Last) 3 | ============================ 4 | 5 | **Prerequesite:** This lesson presumes you know how to invoke Elisp expression as shown in Lesson 2-1. 6 | 7 | ------------ 8 | Introduction 9 | ------------ 10 | 11 | Elisp is a dialect of Lisp - the LISt Processing language. 12 | 13 | You will have noticed that all the expressions we have used so far have been of the form ``(something somethingelse anotherthing)``. That basic form is a list - defined by the opening and closing brackets. All the expressions we have looked at so far have been the simplest sort of programmes - lists where the first element is an operator and the remaining elements are data. But a list can also be simple data. 14 | 15 | ---------- 16 | Data Lists 17 | ---------- 18 | 19 | The Elisp interpreter has to be told that it is a data list. This is done by **quoting** it with a single quote. 20 | 21 | :You Type: ``'(1 2 3)`` 22 | :Result: ``(1 2 3)`` 23 | 24 | The apostrophe ``'`` is syntactic sugar for the quote operator which can be invoked like a normal operator: 25 | 26 | :You Type: ``(quote (1 2 3))`` 27 | :Result: ``(1 2 3)`` 28 | 29 | You can also make a list with the list operator: 30 | 31 | :You Type: ``(list 1 2 3)`` 32 | :Result: ``(1 2 3)`` 33 | 34 | It all seems so reasonable, but wait, lets try that again. 35 | 36 | :You Type: ```(1 2 3)`` 37 | :Result: ``(1 2 3)`` 38 | 39 | "*Ah, we have just done that*" sez you - except we haven't. This last example has a **backtick** ````` and not a **single quote** ``'``. The backtick is a different operator which, in this instance, just produces a list. In other circumstances it behaves very differently to the single quote operator. 40 | 41 | ------------------ 42 | Nested Expressions 43 | ------------------ 44 | 45 | You can nest expressions. 46 | 47 | :You Type: ``(+ 1 (* 2 3))`` 48 | :Result: ``7`` 49 | 50 | The inner expression is evaluated first: 51 | 52 | :Inner: ``(* 2 3)`` 53 | :Result: ``6`` 54 | 55 | This is then put into the outer expression which is then evaluated: 56 | 57 | :Outer: ``(+ 1 6)`` 58 | :Result: ``7`` 59 | 60 | --------------------- 61 | What You Have Learned 62 | --------------------- 63 | 64 | One of the great simplicities of Lisp is that data and programmes are very similar - both are lists - and that you can manipulate programmes as if they were data. 65 | 66 | We have previously seen *lists-as-programmes* and this section has looked at *lists-as-data* and the nesting of lists. 67 | 68 | ---------------- 69 | Extra Activities 70 | ---------------- 71 | 72 | There are three additional functions that can be used to make and break lists ``cons``, ``car`` and ``cdr``. 73 | 74 | ``cons`` is short for constructs and is used to build lists. ``car`` and ``cdr`` take their name from assembly code instructions whose meanings may as well be lost in the mists of time. 75 | 76 | You build a lists with ``cons`` like this: 77 | 78 | :You Type: ``(cons 1 '(2 3))`` 79 | :Result: ``(1 2 3)`` 80 | 81 | ``cons`` adds a new value to the start or *head* of a list. Note that the list to which you are adding it has to be quoted. 82 | 83 | You can split a list into two parts - the first value (the *head*) and the remaining ones (the *tail*). The head is extracted with ``car``: 84 | 85 | :You Type: ``(car '(1 2 3))`` 86 | :Result: ``1`` 87 | 88 | The tail is extracted with ``cdr``: 89 | 90 | :You Type: ``(cdr '(1 2 3))`` 91 | :Result: ``(2 3)`` 92 | 93 | 94 | -------------------------------------------------------------------------------- /contents/lesson-2-4-symbols-and-variables.rst: -------------------------------------------------------------------------------- 1 | ================================== 2 | Lesson 2-4 - Symbols And Variables 3 | ================================== 4 | 5 | **Prerequisite:** This lesson presumes you know how to invoke Elisp expression as shown in Lesson 2-1. 6 | 7 | ---------------- 8 | Symbols Overview 9 | ---------------- 10 | 11 | Before you can start building functions we need to understand what symbols are. We have seen expressions like ``(concat "blah" "bleh")``. In that expression ``concat`` is a symbol - a symbol whose value is a function or an operator. 12 | 13 | Symbols can contain different things: 14 | 15 | * operators or functions 16 | * data values 17 | * property lists 18 | * the print name of the symbol 19 | 20 | Some symbols are also the so-called *constant variables* - they evaluate to themselves (their data value is their name) and they cannot have their datavalue set to anything else. 21 | 22 | The constant values are used to define property lists. 23 | 24 | ------------------------- 25 | Symbols As Function Names 26 | ------------------------- 27 | 28 | Symbols can be the name of functions (or operators). We will look into how these are set in a later lesson. 29 | 30 | -------------------- 31 | Symbols As Variables 32 | -------------------- 33 | 34 | Instances of Data Types evaluate to themselves in Elisp: 35 | 36 | :You Type: ``9`` 37 | :Result: ``9`` 38 | 39 | You can evaluate Symbols similarly 40 | 41 | :You Type: ``fill-column`` 42 | :Result: ``70`` 43 | 44 | (It might not be ``70`` - but it probably will be). At a first glance it might appear that ``fill-column`` is a variable in Elisp with global scope - turn out it is a bit more subtle that that as will become apparent in Lesson 5-3. Later on we will see how this sort of variable will be used and have its value changed. 45 | 46 | Variables don't just exist with default values. If you try and use a random symbol in an expression it will fail. 47 | 48 | :You Type: ``(+ 1 do_tell)`` 49 | :Result: You are dropped into the debugger 50 | 51 | :: 52 | 53 | Debugger entered--Lisp error: (void-variable do_tell) 54 | (+ 1 do_tell) 55 | eval((+ 1 do_tell)) 56 | eval-last-sexp-1(t) 57 | eval-last-sexp(t) 58 | eval-print-last-sexp() 59 | call-interactively(eval-print-last-sexp nil nil) 60 | 61 | The variable ``do_tell`` has been created but its value is *void* and it cannot be used. 62 | 63 | You give a symbol a value using the operators ``set`` and ``setq``. **These define global variables**. 64 | 65 | :You Type: ``(set 'do_tell '11)`` 66 | :Result: ``11`` 67 | 68 | If we now evaluate the ``do_tell`` it no longer throws an error: 69 | 70 | :You Type: ``do_tell`` 71 | :Result: ``11`` 72 | 73 | Notice that when the value of ``do_tell`` was set ``do_tell`` was quoted viz ``'do_tell``. The quoting says to Elisp "*don't treat do_tell as a variable is a value to be passed to the operator set*". The operator ``setq`` just *absorbs* that quote and lets you not quote the first parameter. 74 | 75 | :You Type: ``(setq do_tell '22)`` 76 | :Return: ``22`` 77 | 78 | We can now use this variable in an expression: 79 | 80 | :You Type: ``(+ do_tell 33)`` 81 | :Return: ``55`` 82 | 83 | There is a variant on ``set`` and ``setq`` called ``defvar`` that defines a variable. It is different from them in that it only applies to uninitialised variables. If a variable is already defined it won't overwrite it. 84 | 85 | :You Type: ``(defvar farmer_dell 123)`` 86 | :Return: ``farmer_dell`` 87 | 88 | We can now see what ``defvar`` has done to the variable ``farmer_dell`` by evaluating that: 89 | 90 | :You Type: ``farmer_dell`` 91 | :Return: ``123`` 92 | 93 | But if we ``defvar`` on ``do_tell`` it won't take: 94 | 95 | :You Type: ``(defvar do_tell 123)`` 96 | :Return: ``do_tell`` 97 | 98 | and now evaluate ``do_tell``: 99 | 100 | :You Type: ``do_tell`` 101 | :Return: ``33`` 102 | 103 | (This only works if you have used ``set`` or ``setq`` to define ``do_tell`` in the \*scratch\* buffer earlier in the same editing session). 104 | 105 | -------------------------------------- 106 | Constant Variables And Keyword Symbols 107 | -------------------------------------- 108 | 109 | Some symbols can't be redefined. We have met a couple of them before ``nil`` and ``t``. Dy design all symbols which begin with ``:`` are also constant values. 110 | 111 | If you try and set a symbol whose name starts with ``:`` you will get an error. 112 | 113 | :You Type: ``(setq :hotdog 3)`` 114 | :Return: ``Debugger entered--Lisp error: (setting-constant :hotdog) ...`` 115 | 116 | An alternative name for a symbol which starts with ``:`` is a keyword symbol and these *constant variables* are commonly used as keywords in property lists. 117 | 118 | -------------- 119 | Property Lists 120 | -------------- 121 | 122 | Property lists are lists where each pair of concurrent values are regarded as a pair. The two values can be anything, but conventionally the first of them is a constant variable with a name beginning with ``:``. Here is an example: 123 | 124 | ``(:quality "great" :achievement "impressive")`` 125 | 126 | The relationship of property lists with symbols is a bit messy and is discussed in the *Extra Activities* section of this lesson. 127 | 128 | --------------------- 129 | What You Have Learned 130 | --------------------- 131 | 132 | You have learned how to set values of Symbols and then reuse those symbols in expressions. 133 | 134 | ------------------ 135 | Additional Reading 136 | ------------------ 137 | 138 | Symbols in Elisp are a bit more complex than symbols in other languages - there is a discussion of `Symbols`_ in the *Introduction To Emacs Lisp* manual. 139 | 140 | You can read about `Symbol Properties`_ in the *Emacs Lisp Reference* manual. 141 | 142 | ------------------------ 143 | Extra Quoting Activities 144 | ------------------------ 145 | 146 | If we fail to quote variables properly with the set operator will generate errors. Can you work out what they mean? 147 | 148 | | ``(set bleh '(1 2 3))`` 149 | | ``(set 'bleh (1 2 3))`` 150 | 151 | ---------------------------- 152 | Extra Property List Activity 153 | ---------------------------- 154 | 155 | Property lists can be the *value* of a symbol and are associated with it by ``setq``: 156 | 157 | :You Type: ``(setq hotdog '(:quality "great" :achievement "impressive"))`` 158 | :Return: ``(:quality "great" :achievement "impressive")`` 159 | 160 | But the symbol can also have its own *plist* which is created by the special function ``setplist``. (the symbol must already have been created.) 161 | 162 | :You Type: ``(setplist 'hotdog '(:rhubarb "custard" :status "borked"))`` 163 | :Return: ``(:rhubarb "custard" :status "borked")`` 164 | 165 | However if we now evaluate the value of ``hotdog`` you will see that it is ``(:quality "great" :achievement "impressive")`` as that is the *value* we set previously: 166 | 167 | :You Type: ``hotdog`` 168 | :Return: ``(:quality "great" :achievement "impressive")`` 169 | 170 | What happens if you try and set the property list of an undefined symbol? 171 | 172 | .. _Symbols: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/Symbol-Components.html#Symbol-Components 173 | 174 | .. _Symbol Properties: http://www.gnu.org/software/emacs/elisp/html_node/Symbol-Plists.html#Symbol-Plists 175 | -------------------------------------------------------------------------------- /contents/lesson-2-5-arrays-and-sequences.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Lesson 2-5 - Arrays (And Sequences) 3 | =================================== 4 | 5 | **Prerequesite:** This lesson presumes you know how to invoke Elisp expression as shown in Lesson 2-1. 6 | 7 | ------------ 8 | Introduction 9 | ------------ 10 | 11 | We have seen *lists* in Elisp. Lists are an example of a *sequence* - a load of things stored in another thing which we can access sequentially. 12 | 13 | There is another type of *sequence* in Elisp - an *array*. Arrays themselves come in 2 flavours: 14 | 15 | * strings 16 | * vectors 17 | * bool-vector 18 | * char-table 19 | 20 | The relationship of all these things is shown below: 21 | 22 | .. image :: /images/elisp-sequences.png 23 | 24 | There are sets of functions that operate on all *sequences*, some which apply to *array*'s only and then other sets for the actual data types themselves (*lists*, *strings*, *vectors*, *bool-vectors* and *char-tables*). 25 | 26 | This lesson will look at: 27 | 28 | * strings 29 | * vectors 30 | 31 | The Extra Activities section will cover functions that operate on sequences. 32 | 33 | ------------------------- 34 | Why Arrays And Not Lists? 35 | ------------------------- 36 | 37 | The difference between arrays and lists is that arrays have fixed lengths and lists have variable length. This gives them different performance characteristics - array elements are accessible in constant time, whereas the access time for lists is proportional to their length. 38 | 39 | -------------------------------------- 40 | Difference Between Strings And Vectors 41 | -------------------------------------- 42 | 43 | In Elisp a string is simply an array whose elements consists of the integers which represent unicode points. A vector is a general array whose elements are any valid Elisp term. 44 | 45 | ------------------- 46 | Why Only 1D Arrays? 47 | ------------------- 48 | 49 | Arrays are 1 dimensional only. Given that the elements of a vector can consist of other valid Elisp symbol, multi-dimensional arrays can be implemented as vectors of vectors. 50 | 51 | --------------- 52 | Creating Arrays 53 | --------------- 54 | 55 | A array is delimited by square brackets (``[`` and ``]``). You can create them inline: 56 | 57 | :You Type: ``[1 2 3]`` 58 | :Return: ``[1 2 3]`` 59 | 60 | You can create vectors using the ``vector`` operator: 61 | 62 | :You Type: ``(vector 1 2 3)`` 63 | :Return: ``[1 2 3]`` 64 | 65 | The operator ``string`` does the same for strings. To create a string you need array elements that are the integers which represent characters - a full set of unicode values is supported. 66 | 67 | :You Type: ``(string 97 98 99)`` 68 | :Result: ``"abc"`` 69 | 70 | (96 is ascii for ``a``) 71 | 72 | --------------------- 73 | What You Have Learned 74 | --------------------- 75 | 76 | You have learned about additional types of sequences and see how they are constructed. 77 | -------------------------------------------------------------------------------- /contents/lesson-3-1-writing-functions.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Lesson 3-1 - Writing Functions 3 | ============================== 4 | 5 | ----------------- 6 | Script Mode Elisp 7 | ----------------- 8 | 9 | In order to write functions it is necessary to change the way in which Elisp expressions will be evaluated. Instead of invoking expressions in the \*scratch\* buffer it is time to switch to running Elisp as a script. 10 | 11 | To do this an Elisp file has to be invoked from the command line. If you had some Elisp expressions in a file called *first_programme.el* the following command would be run it as a script ``emacs --no-site-file --script first_programme.el`` 12 | 13 | The option ``--no-site-file`` means that emacs doesn't load any Elisp from the site libraries. By default the ``--script`` option also includes option ``--no-init-file``. Normally emacs starts and executes a init file. In Ubuntu this file is ``.emacs`` in the users home directory. 14 | 15 | Start by creating a new directory, and in that create a file called *message.el*. The contents of that file is a single Elisp expression: 16 | 17 | :: 18 | 19 | (message "Bonjour Tout Le Monde") 20 | 21 | The file should be executed by running this batch command in the directory in which you have created *message.el* 22 | 23 | :: 24 | 25 | emacs --no-site-file --script message.el 26 | 27 | The output should be ``Bonjour Tout Le Monde`` 28 | 29 | -------------------------- 30 | Defining A Simple Function 31 | -------------------------- 32 | 33 | We will start by defining a function. Create a file with the following code in it: 34 | 35 | :: 36 | 37 | (defun bonjour () (message "Bonjour Tout Le Monde")) 38 | (bonjour) 39 | 40 | On executing this file the output will be: 41 | 42 | :: 43 | 44 | Bonjour Tout Le Monde 45 | 46 | Let's understand what we are seeing. Consider the first line - the operator ``defun`` indicates that we are defining a function. Here it is taking 3 parameters: 47 | 48 | | *1* ``bonjour`` which is the name of the function 49 | | *2* ``()`` which is a list of the parameters that the function will take 50 | | *3* ``(message "Bonjour Tout Le Monde")`` is the body of code that will executed when the function is run 51 | 52 | The second line simply executes the fuction ``bonjour``. The function definition states that ``bonjour`` takes no parameters (the list of parameters is empty). 53 | 54 | -------------------------------- 55 | Defining A More Complex Function 56 | -------------------------------- 57 | 58 | Let's create a function that takes multiple arguments: 59 | 60 | :: 61 | 62 | (defun tough_maths (i j k) 63 | "jeepers maths is tough!" 64 | (message (number-to-string (+ i j k)))) 65 | (tough_maths 3 4 5) 66 | 67 | When executed this will return: 68 | 69 | :: 70 | 71 | 12 72 | 73 | In this case (unlike the simple case) ``defun`` takes 4 parameters and not three. The second paramater ```(i j k)`` is a list of parameters that the function takes. The third parameter is the documentation - it can be a string broken over many lines. The fourth parameter is the body of the function as in the previous example. Notice that in order to write the output the value of the expression ``(+ i j k)`` must be cast to a string with the operator ``number-to-string``. 74 | 75 | -------------------------------------------- 76 | Functions With Variable Numbers Of Arguments 77 | -------------------------------------------- 78 | 79 | We have seen that the function ``defun`` has variable arity - that is to say it can take 3 or 4 arguments - we will see later that it can actually take 5 parameters. 80 | 81 | Let's write a variable arity function: 82 | 83 | :: 84 | 85 | (defun variable_arity (a &optional b &rest c) 86 | "This is a function which has variable arity" 87 | (message (concat "variable a is " a)) 88 | (message (concat "variable b is " b)) 89 | (if c (message "c is not an empty list") (message "c is an empty list"))) 90 | (message "run the fn with 1 variable") 91 | (variable_arity "eh") 92 | (message "run the fn with 2 variables") 93 | (variable_arity "eh" "bee") 94 | (message "run the fn with 3 variables") 95 | (variable_arity "eh" "bee" "see") 96 | (message "run the fn with 4 variables") 97 | (variable_arity "eh" "bee" "see" "dee") 98 | (message "run the fn with 5 variables") 99 | (variable_arity "eh" "bee" "see" "dee" "eee") 100 | 101 | 102 | The result is: 103 | 104 | :: 105 | 106 | run the fn with 1 variable 107 | variable a is eh 108 | variable b is 109 | c is an empty list 110 | run the fn with 2 variables 111 | variable a is eh 112 | variable b is bee 113 | c is an empty list 114 | run the fn with 3 variables 115 | variable a is eh 116 | variable b is bee 117 | c is not an empty list 118 | run the fn with 4 variables 119 | variable a is eh 120 | variable b is bee 121 | c is not an empty list 122 | run the fn with 5 variables 123 | variable a is eh 124 | variable b is bee 125 | c is not an empty list 126 | 127 | The important part of this is the first part of the function definition ``(defun variable_arity (a &optional b &rest c)...``. ``a`` is a required option - calling ``variable_arity`` with zero parameters will result in an error. The marker ``&optional b`` indicates that the subsequent parameter ``b`` is optional. In this function there is only one optional function but a clause like ``(i j &optional k l m)`` would have three optional arguments. The final clause ``&rest c`` indicates that all parameters from 3 onwards will be collected into the variable ``c`` as a list. You can have either ``&optional`` or ``&rest`` or both together as in this function. 128 | 129 | --------------------- 130 | What You Have Learned 131 | --------------------- 132 | 133 | You have learned how to run Elisp programmes in batch mode, and also how to define simple, more complex and variable arity functions and invoke them. 134 | 135 | ------------------ 136 | Additional Reading 137 | ------------------ 138 | 139 | There is a section of the Elisp Reference Manual entitled `Functions`_. 140 | 141 | ---------------- 142 | Extra Activities 143 | ---------------- 144 | 145 | Write a function with multiple line documentation. 146 | 147 | The *required*, *optional* and *rest* clauses must be specified in that order. Can you work out why? 148 | 149 | 150 | .. _Functions: http://www.gnu.org/software/emacs/elisp/html_node/Functions.html#Functions 151 | 152 | -------------------------------------------------------------------------------- /contents/lesson-3-2-more-functions.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Lesson 3-2 - More Functions 3 | =========================== 4 | 5 | **Prerequisite:** This lesson presumes you know how to invoke Elisp expression as scripts as shown in Lesson 3-1. 6 | 7 | ------------ 8 | Introduction 9 | ------------ 10 | 11 | The functions we built in the previous lesson were a bit useless. This lesson will look at some more sophisticated functions: 12 | 13 | * ones which can use local variables 14 | * recursive functions 15 | 16 | ------------------------------ 17 | Functions With Local Variables 18 | ------------------------------ 19 | 20 | We have seen how to use ``set`` and ``setq`` to set *global* variables. Global variables are very ugly to use as they can be changed from anywhere and at anytime. This makes them very hard to reason about, and hence to use safely and debug. 21 | 22 | It is important to be able to define *local* variables - variables which can only be set and changed locally from a small number of defined and known places. 23 | 24 | The function used to do this is ``let``. It works like ``set``. 25 | 26 | Type the following expressions in a file: 27 | 28 | | ``(let ((first "hey")`` 29 | | ``(second "ho"))`` 30 | | ``(message first)`` 31 | | ``(message second))`` 32 | 33 | The output should be: 34 | 35 | | ``hey`` 36 | | ``ho`` 37 | 38 | If you carefully count the brackets you will see that ``(first "hey")`` and ``(second "ho")`` are both within a list that is the first parameter of ``let``. The scope of those variables is then the list that makes up the rest of the expression that has ``let`` as its operator. 39 | 40 | We can see that this is the case by adding another message line: 41 | 42 | | ``(let ((first "hey")`` 43 | | ``(second "ho"))`` 44 | | ``(message first)`` 45 | | ``(message second))`` 46 | | ``(message first)`` 47 | 48 | When we try and run this we get an error message printed out: 49 | 50 | | ``hey`` 51 | | ``ho`` 52 | | ``Symbol's value as variable is void: first`` 53 | 54 | This can now be used to make functions which are safe to use. Type in the following function: 55 | 56 | | ``(defun myfun (a b c d)`` 57 | | ``"This is a nonce function designed to show how to`` 58 | | ``use local variables safely"`` 59 | | ``(let ((e (+ a b))`` 60 | | ``(f (* c d)))`` 61 | | ``(- e f)))`` 62 | | ``(message (number-to-string (myfun 7 5 3 1)))`` 63 | 64 | The result should be: 65 | 66 | ``9`` 67 | 68 | Check that result yourself by working through the arithmetic. 69 | 70 | ------------------- 71 | Recursive Functions 72 | ------------------- 73 | 74 | Recursive functions are an important part of functional programming. A recursive function is simply one that calls itself 75 | 76 | Create the following file: 77 | 78 | | ``(defun print_int (n)`` 79 | | ``"This function prints a list of integers in reverse order"`` 80 | | ``(message (number-to-string n))`` 81 | | ``(if (= n 0) (message "That's all folks!") (print_int (- n 1))))`` 82 | | ``(print_int 5)`` 83 | 84 | Your output should be: 85 | 86 | | ``5`` 87 | | ``4`` 88 | | ``3`` 89 | | ``2`` 90 | | ``1`` 91 | | ``0`` 92 | | ``That's all folks!`` 93 | 94 | The key is the ``if`` expression. The first expression is *the terminal test*. If it is true the function prints "*That's all folks!*". If the terminal test is not met (ie it is false) the function calls itself with a value of the current value of ``n - 1``. 95 | 96 | --------------------- 97 | What You Have Learned 98 | --------------------- 99 | 100 | You have learned how to build basic functions with local variables and then how to build functions that call themselves. 101 | 102 | ------------------ 103 | Additional Reading 104 | ------------------ 105 | 106 | There is a section on `Recursive Functions`_ in the Gnu Emacs Lisp Intro. 107 | 108 | ---------------- 109 | Extra Activities 110 | ---------------- 111 | 112 | Write a recursive function to calculate the factorial of an integer. 113 | 114 | .. _Recursive Functions: http://www.gnu.org/software/emacs/emacs-lisp-intro/html_node/Recursive-Definition-Parts.html#Recursive-Definition-Parts 115 | -------------------------------------------------------------------------------- /contents/lesson-4-1-writing-elisp-in-emacs.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Lesson 4-1 - Writing Elisp In Emacs 3 | =================================== 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | Emacs as an editor provides a host of specific tools to help software developers in a wide range of languages. Not surprisingly the support for the Elisp language in Emacs is very good. 10 | 11 | This lesson will explore Emacs as an editor for Elisp. 12 | 13 | Emacs switches into a special mode for a particular programming language by looking at the extension on the filename - the extension for Elisp is ``.el``. If you create a file called *something*.el and open it with Emacs you will see that the editor has changed itself. 14 | 15 | .. image :: /images/emacs-lisp.png 16 | 17 | The modeline now contains the expression (Emacs-Lisp) which indicates that it is in *the Emacs Lisp Major Mode*. The menu bar now has an *Emacs-Lisp* menu. 18 | 19 | A new menu has appeared. Let's look at some of the commands on it. There are indenting commands that can be used to pretty up the source code and lay it out consistently. (*Indent Line* uses the [Tab] key to indent a line. Regions commands can be used on regions - blocks of code which have been selected by marking their starts with [Control][Space] and the moving the cursor point. 20 | 21 | There are menu commands for evaluating expressions and the contents of the buffer as well as various profiling and tracing tools. 22 | 23 | If you execute expressions now, the operator ``message`` will now output to the *minibuffer* at the bottom of Emacs. 24 | 25 | One of the most important features in the debugger - which is triggered when you instrument a function for debugging using the menu command *Instrument Functions for Debugger*. 26 | 27 | .. image :: /images/emacs-debugger.png 28 | 29 | Detailed instructions on using the Emacs debugger can be found in the `Emacs Manual`_ 30 | 31 | Load an Elisp file, and execute it under the debugger. The diagram below shows it working. You can step through the code line-by-line. The debugger shows the values of the last expression executed in the minibuffer at the bottom. In the picture the last expression executed is ``a`` (as shown by the debugger cursor which is placed after it) - its current value (``7``) is shown in the minibuffer. 32 | 33 | .. image :: /images/emacs-debugger2.png 34 | 35 | Read the manual section and try out the debugger until you have mastered it - it will be necessary to use it to develop more complex functionality. 36 | 37 | --------------------- 38 | What You Have Learned 39 | --------------------- 40 | 41 | This lesson has covered the operations of the Emacs debugger Edebug. 42 | 43 | ---------------- 44 | Extra Activities 45 | ---------------- 46 | 47 | Run the menu item *Check Document Strings* in the *Emacs-Lisp* menu - can you work out what does the operator ``provide`` does? 48 | 49 | .. _Emacs Manual: http://www.gnu.org/software/emacs/manual/html_node/elisp/Using-Edebug.html#Using-Edebug 50 | -------------------------------------------------------------------------------- /contents/lesson-4-2-adding-custom-functions-to-emacs.rst: -------------------------------------------------------------------------------- 1 | ============================================= 2 | Lesson 4-2 - Adding Custom Functions To Emacs 3 | ============================================= 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | In order to run custom Elisp functions it is necessary to have them loaded into Emacs at run time. 10 | 11 | On load time emacs executes a startup file. In Emacs-23 on Ubuntu 10.10 this is a file called ``.emacs`` in your home directory. 12 | 13 | This file may or may not exist. Emacs is quite happy for it not to exist. If you change any settings using the *Options* menu and then save them, the results will be written to the ``.emacs`` file. 14 | 15 | ------------------------ 16 | A Simple Custom Function 17 | ------------------------ 18 | 19 | Open the ``.emacs`` file (or create it if it doesn't exist) and add the following function: 20 | 21 | :: 22 | 23 | (defun doodlebug () 24 | "Nonce function" 25 | (interactive) 26 | (message "Howdie-doodie fella")) 27 | 28 | The first time you do this, edit the ``.emacs`` file and then open Emacs. If you edit it in Emacs you will need to quit and restart. 29 | 30 | On starting Emacs all the code in ``.emacs`` is reloaded and evaluated. 31 | 32 | This function can be run simply. The command *[Alt][x]* is used to a run a function interactively. Typing *[Alt][x]* switches the focus in Emacs to the minibuffer - if you then type in a function name it will be executed. To run ``doodlebug`` simply type *[Alt][x]* and then *doodlebug*. 33 | 34 | You should then see the output in the minibuffer: 35 | 36 | :: 37 | 38 | Howdie-doodie fella 39 | 40 | Look carefully at the function definition. The third parameter of the list is the expression ``(interactive)`` - this is necessary if we are to invoke the function from either a key-binding or the minibuffer. 41 | 42 | --------------------------------- 43 | A Custom Function With User Input 44 | --------------------------------- 45 | 46 | Let's edit the function to take some parameters: 47 | 48 | :: 49 | 50 | (defun doodlebug (a b c) 51 | "Nonce function" 52 | (interactive "sAdjective: \nsNoun: \nsExclamation: \n") 53 | (message "Its a %s thing, this %s, so it is, %s" a b c)) 54 | 55 | You can't reload the ``.emacs`` file, but you can manually re-evaluated by using the command *Emacs-Lisp -> Evaluate Buffer* in the ``.emacs`` buffer. 56 | 57 | When you run this version of the function with *[Alt][x]doodlebug* it will offer up three prompts, to wit: 58 | 59 | :: 60 | 61 | Adjective: 62 | Noun: 63 | Exclamation: 64 | 65 | As you type in a string at each prompt (ending with *[Return]*) each of the strings wll be bound to the variables ``a``, ``b`` and ``c`` in turn. 66 | 67 | This behaviour in enabled by the new form of the *interactive* expression. The string which has been added to that expression consists of 6 separate components: 68 | 69 | :: 70 | 71 | s 72 | Adjective: \n 73 | s 74 | Noun: \n 75 | s 76 | Exclamation: \n 77 | 78 | The 2nd, 4th and 6th parts are the prompts which will be shown in the minibuffer. The three ``s``'s are Interactive Codes which refer to strings (ie key sequences terminated with *[Return]* which are entered at the prompt. There are a range of other Interative Codes, some of which are: 79 | 80 | 81 | | ``a`` - a function name 82 | | ``b`` - the name of an existing buffer 83 | | ``B`` - the name of a buffer which may or may not exist 84 | | ``c`` - a character 85 | | ``C`` - a command 86 | | etc, etc 87 | 88 | You can read the full list of `Interactive Codes`_ in the reference manual 89 | 90 | --------------------------------------------- 91 | Binding The Custom Function To A Key Sequence 92 | --------------------------------------------- 93 | 94 | To bind the custom function to a key sequence add the following line to the ``.emacs`` file. 95 | 96 | :: 97 | 98 | (global-set-key [f5] 'doodlebug) 99 | 100 | This expression will bind the function ``doodlebug`` to the *F5* function key. Once you have re-evaluated the ``.emacs`` buffer you will be able to fire the function with the *F5* key. 101 | 102 | We can identify which function is bound to which key with the command: 103 | 104 | :: 105 | 106 | (lookup-key (current-global-map) [f5]) 107 | 108 | The rules for binding keys are a bit complex. We can use the operator ``kbd`` to generate the appropriate input to ``global-set-key`` and ``lookup-key``, for instance: 109 | 110 | :: 111 | 112 | (global-set-key (kbd "C-c a") 'doodlebug) 113 | (lookup-key (current-global-map) (kbd "C-c a")) 114 | 115 | The expression ``(kbd "C-c a")`` generates the appropriate keymap for the key sequence *[C-c][a]*. 116 | 117 | --------------------- 118 | What You Have Learned 119 | --------------------- 120 | 121 | You have learned: 122 | 123 | * a way to load a new function into emacs 124 | * how to make the function take interactive paramaters 125 | * how to invoke that command - via the command line and via a custom key 126 | 127 | ------------------ 128 | Additional Reading 129 | ------------------ 130 | 131 | There is a good discussion of keybindings in your ``.emacs`` file in the Emacs Lisp Introduction. 132 | 133 | The whole process of binding keys to functions in emacs is quite complex and is covered in the `Keymaps`_ section of the manual 134 | 135 | ---------------- 136 | Extra Activities 137 | ---------------- 138 | 139 | What happens if you try and run a function which doesn't include the expression ``(interactive)``? 140 | 141 | Experiment with other Interactive Codes in your functions. 142 | 143 | Bind and unbind some keys to functions in your ``.emacs`` file. 144 | 145 | .. _Interactive Codes: http://www.gnu.org/software/emacs/elisp/html_node/Interactive-Codes.html#Interactive-Codes 146 | 147 | .. _Key Bindings: http://www.gnu.org/software/emacs/emacs-lisp-intro/html_node/Keybindings.html#Keybindings 148 | 149 | .. _Keymaps: http://www.gnu.org/s/emacs/manual/html_node/elisp/Keymaps.html#Keymaps 150 | -------------------------------------------------------------------------------- /contents/lesson-4-3-emacs-menus.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Lesson 4-3 - Emacs Menus 3 | ======================== 4 | 5 | **Prerequisite:** this lesson presumes you know how to use the ``.emacs`` file as outlined in Lessons 4-1 and 4-2. 6 | 7 | ------------ 8 | Introduction 9 | ------------ 10 | 11 | This section will look at creating a new menu in Emacs and binding a custom function to it. Before doing that we need to create a couple of functions in our ``.emacs`` file to bind to the menu. 12 | 13 | We will incorporate our best practice naming conventions in it. 14 | 15 | :: 16 | 17 | (defun omar-hip () 18 | "a nonce menu function" 19 | (interactive) 20 | (message "hip, hop, don't stop")) 21 | 22 | (defun omar-hotel () 23 | "another nonce menu function" 24 | (interactive) 25 | (message "hotel, motel, holiday inn")) 26 | 27 | ------------------- 28 | The Basics Of Menus 29 | ------------------- 30 | 31 | We are going to create a menu called ``Omar`` which calls these two functions. 32 | 33 | Type the following into your ``.emacs`` file and re-evaluate the buffer. 34 | 35 | :: 36 | 37 | (define-key global-map [menu-bar omar] 38 | (cons "Omar's Menu" (make-sparse-keymap "Omar"))) 39 | 40 | You will see that this has created a new top-level menu at the left of the menu bar. It consists of the words *Omar's Menu*. There are no items below it. 41 | 42 | Lets look at that expression - it is defining a new key in the ``global-map``. The global map is a data structure which holds details of all key inputs: 43 | 44 | * menu items 45 | * toolbar items 46 | * key shortcuts 47 | * etc, etc 48 | 49 | You can look at the value of the global keymap by evaluating the expression ``(current-global-map)`` in the \*scratch\* buffer. 50 | 51 | The next parameter is the array ``[menu-bar omar]`` which tells the global keymap that this new key is under the menu. The final item is a parameter list - in this cause just jusing a normal string as the key. The function ``make-sparse-keymap`` creates an empty keymap - we will fill this keymap with the menu items later. 52 | 53 | You should be quite confused by the terminology now. We are creating *menus* and all the functions refer to *keys*. Emacs has a mechanism for handling keyboard events. All the other user input mechanisms (mouse events, menus, toolbar buttons, etc, etc) are all extensions of key-handling mechanisms. Hence the fact that all these things are configured by *key* related functions. 54 | 55 | The menu we have just created is in the wrong place really. The standard Emacs menus are: 56 | 57 | * *File* 58 | * *Edit* 59 | * *Options* 60 | * *Buffers* 61 | * *Tools* 62 | 63 | These constitute the *global* menu bar. In addition there is the *Help* menu - this is the *final items* menu. The Emacs convention is that user or mode-specific menus appear in the middle - that is to say to the right of the global menus and to the 64 | left of the final items menu. 65 | 66 | We can make our menu do that by changing the definition from ``define-key`` to ``define-key-after``. 67 | 68 | Now lets make a proper menu. Type the following into your ``.emacs`` file and re-evaluate the buffer: 69 | 70 | :: 71 | 72 | (define-key-after global-map [menu-bar omar] 73 | (cons "Omar's Menu" (make-sparse-keymap "Omar"))) 74 | (define-key global-map [menu-bar omar omar-hip] 75 | '(menu-item "Hip" omar-hip 76 | :help "Hip, yeah!")) 77 | (define-key global-map [menu-bar omar separator-replace-tags] 78 | '(menu-item "--")) 79 | (define-key global-map [menu-bar omar omar-hotel] 80 | '(menu-item "Hotel" omar-hotel 81 | :help "Hotel, yeah!")) 82 | 83 | Notice how we are adding menu-items down the array ``[menu-bar omar omar-hip]`` and so on and so forth. 84 | 85 | ------------------------------------ 86 | Adding New Items To An Existing Menu 87 | ------------------------------------ 88 | 89 | Lets bind the two nonce functions to an existing menu. Clear out the menu definition code from your ``.emacs`` file and replace it with this: 90 | 91 | :: 92 | 93 | (defvar menu-bar-omar-menu (make-sparse-keymap "Omar's Menu")) 94 | (define-key menu-bar-omar-menu [omar-hip] 95 | '(menu-item "Hip" omar-hip 96 | :help "Hip, yeah!")) 97 | (define-key menu-bar-omar-menu [separator-omar-1] 98 | '(menu-item "--")) 99 | (define-key menu-bar-omar-menu [omar-hotel] 100 | '(menu-item "Hotel" omar-hotel 101 | :help "Hotel, yeah!")) 102 | (define-key menu-bar-edit-menu [omar] 103 | (list 'menu-item "Omar Menu" menu-bar-omar-menu)) 104 | 105 | Lets step through it line by line. The first line defines a new variable ``menu-bar-omar-menu``. Note that it has a conventional name. It is part of the *menu* system so it has the prefix ``menu-bar-``. The value of this variable is set to a *sparse keymap*. The entire input management system is built around datatypes called *keymaps*. A *sparse* keymap is just an empty uninitialised one. 106 | 107 | The next three lines add elements to the sparse keymap. The first and third items are normal menu items, the second is a separator. 108 | 109 | The ``define-key`` operator defines a key: 110 | 111 | * the first parameter it takes is the keymap to which the key is added 112 | * the second is an array with the function name the menu item is bound to 113 | * the third item is the value that the ``menu-item`` operator returns (which is why the third expression is quoted) 114 | 115 | The ``menu-item`` expression takes 3 parameters: 116 | 117 | * the string that appears in the menu 118 | * the function that is associated with the menu 119 | * the final parameter is a property list (ie 2 elements) containing the constant variable ``:help`` and the help string which appears as the tooltip on the menu 120 | 121 | Notice how we built this menu in a different way - creating a new keymap, adding elements into it, and finally sticking the new keymap into a keymap ``menu-bar-edit-menu`` which is already bound into the global-map. 122 | 123 | ------------------ 124 | Keyboard Shortcuts 125 | ------------------ 126 | 127 | Keyboard shortcuts are automatically added to menus if they exist. To try this out bind one of the functions to a key combination. Add a key binding to ``.emacs`` and reevaluate the buffer. 128 | 129 | :: 130 | 131 | (global-set-key [f5] 'omar-hip) 132 | 133 | When you look at the menu now you should see the keyboard shortcut ```` alongside the menu item *Hip*. 134 | 135 | --------------------- 136 | What You Have Learned 137 | --------------------- 138 | 139 | You have seen how to add basic menu items which bind to functions. 140 | 141 | ------------------ 142 | Additional Reading 143 | ------------------ 144 | 145 | There is a section on `Keymaps`_ in the *Introduction To Emacs Lisp* Manual - it includes a section on menu manipulation. 146 | 147 | ---------------- 148 | Extra Activities 149 | ---------------- 150 | 151 | You can alter the layout of your menus with a variety of `Menu Separators`_ create a new menu with some swanky separators. 152 | 153 | We have build menus with single items - can you build sub-menus and sub-sub-menus? 154 | 155 | .. _Keymaps: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/Keymaps.html#Keymaps 156 | 157 | .. _Menu Separators: http://www.gnu.org/software/emacs/elisp/html_node/Menu-Separators.html#Menu-Separators 158 | -------------------------------------------------------------------------------- /contents/lesson-4-4-adding-buttons-to-the-toolbar.rst: -------------------------------------------------------------------------------- 1 | =========================================== 2 | Lesson 4-4 - Adding Buttons To The Tool-bar 3 | =========================================== 4 | 5 | **Prerequisite:** this lesson presumes you know how to use the ``.emacs`` file as outlined in Lessons 4-1 and 4-2. 6 | 7 | ------------ 8 | Introduction 9 | ------------ 10 | 11 | Adding buttons to the tool-bar is conceptually similar to adding menu items - binding in a 'non-key' keymap to the ``global=map``. 12 | 13 | Before you do it you will need to create a new button image. Emacs buttons are stored in the directory ``usr/share/emacs/23.1/etc/images/``. Copy one out to a directory under your home directory. Fire up the Gimp, edit the image and resave it as ``omar.xmp``. Sudo to root and copy the new icon back to ``usr/share/emacs/23.1/etc/images/``. 14 | 15 | We will use the functions ``omar-hip`` and ``omar-hotel`` which we defined for the previous lesson. 16 | 17 | ------------------------- 18 | The Basics Of The Toolbar 19 | ------------------------- 20 | 21 | Add the following line to your ``.emacs`` file and re-evaluate the buffer: 22 | 23 | :: 24 | 25 | (define-key global-map [tool-bar omar-button] 26 | '(menu-item "Hotel" omar-hotel 27 | :help "OMG Omar!" 28 | :image (image :type xpm :file "omar.xpm"))) 29 | 30 | We are binding in a ``menu-item`` onto the tool-bar - the ``menu-item`` has a paired-list with an image description. 31 | 32 | --------------------- 33 | What You Have Learned 34 | --------------------- 35 | 36 | You have learned: 37 | 38 | * where tool-bar icons are 39 | * how to edit them 40 | * how to bind them in 41 | 42 | ---------------- 43 | Extra Activities 44 | ---------------- 45 | 46 | The tool-bar button we created was added at the start of the tool-bar. How would you add it to the end of the toolbar? 47 | -------------------------------------------------------------------------------- /contents/lesson-5-1-elisp-in-files.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Lesson 5-1 - Elisp In Files 3 | =========================== 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | So far we have created emacs functions in the ``.emacs`` file and attached that to menu-bar and the like. This is a bit sub-optimal. To use Elisp properly we should package up functionality into files and make it easy for them to be added to emacs. 10 | 11 | Emacs loads files from various libraries. It used a global variable called ``load-path`` to work out where to load them from. 12 | 13 | You can look at the current value of that global variable in the \*scratch\* buffer by evaluating (type in the text and type *[Control][j]* at the end): 14 | 15 | ``load-path`` 16 | 17 | Your install of emacs will dump out loads of directories: 18 | 19 | ``("/usr/share/emacs23/site-lisp/thailatex" "/usr/share/emacs23/site-lisp/latex-cjk-thai" "/usr/share/emacs23/site-lisp/latex-cjk-common" "/usr/share/emacs23/site-lisp/dictionaries-common" "/etc/emacs23" "/etc/emacs" "/usr/local/share/emacs/23.1/site-lisp" "/usr/local/share/emacs/site-lisp" "/usr/share/emacs/23.1/site-lisp" "/usr/share/emacs/23.1/site-lisp/dictionaries-common" "/usr/share/emacs/23.1/site-lisp/latex-cjk-common" "/usr/share/emacs/23.1/site-lisp/latex-cjk-thai" ...)`` 20 | 21 | For a shared production package (ie one that everyone on a particular machine will need access to) the install directory would be somewhere in the shared path space (ie a directory like ``/usr/share/emacs23/site-lisp/``). The convention is that there are ``site-lisp`` directories for all versions of Emacs as well a for specific versions. Upgrades of the base Emacs operator can cause some packages to fail. 22 | 23 | For this lesson we will store our Elisp files locally. Conventionally this is done in a directory called ``.emacs.d``. Best practice says that we don't not add ``.emacs.d`` to the ``load-path``, but we can create a sub-directory under that and add it. 24 | 25 | Create a subdirectory called ``omars-dir`` in ``~/.emacs.d/`` and inside that create a file called ``myomar.el``. 26 | 27 | Add versions of our old favourite functions to ``myomar.el`` 28 | 29 | | ``(defun omar-hip ()`` 30 | | ``(interactive)`` 31 | | ``(message "hip, hop, don't stop"))`` 32 | 33 | | ``(defun omar-hotel ()`` 34 | | ``(interactive)`` 35 | | ``(message "hotel, motel, holiday inn"))`` 36 | 37 | In order to make this available to us we need to add the path to ``load-path``. This is done in our ``.emacs`` file. 38 | 39 | ``(add-to-list 'load-path "~/.emacs.d/omars-dir")`` 40 | 41 | Re-evaluate the ``.emacs`` buffer and then switch to the scratch buffer and evaluate ``load-path`` - our directory should now be the first path in the list. 42 | 43 | -------------- 44 | Using Our File 45 | -------------- 46 | 47 | We have our new directory in the *load-path* we have our file in that directory. Is that enough? 48 | 49 | Quit Emacs and restart (thus losing all our history and defined functions). Our new directory should still be in the *load-path*; but will the code be loaded? 50 | 51 | Emacs has an interactive command for executing interactive functions called execute-extended-command. It is bound to the key combination *[M-x]* so simply type that and the focus will switch to the mini-buffer and wait for you to enter the name of the command you want to run. Stick in ``omar-hotel``. Your attempt to run it should fail. 52 | 53 | Providing code in a searchable path isn't enough. You need to add a line to the ``.emacs`` file telling it to load our new file, and another line in the file itself to identify what it is that the file is providing. 54 | 55 | To make life simpler we are going to call the features that our ``myomar.el`` file provides the same base name as the file, ie ``myomar``. 56 | 57 | To get this to autoload we add the following line to our ``.emacs`` file after the line where we have added ``~/.emacs.d/omars-dir/`` to the ``load-path``: 58 | 59 | ``(require 'myomar)`` 60 | 61 | and we add this line at the top of ``myomar.el``: 62 | 63 | ``(provide 'myomar)`` 64 | 65 | Now if we quite Emacs and restart it and the use the *[M-x]* trick with ``omar-hip`` the function will execute. 66 | 67 | ------------------- 68 | Our Execution Model 69 | ------------------- 70 | 71 | This is the execution model we will use from now on: 72 | 73 | * create a custom file or files in a standard directory 74 | * edit ``.emacs`` to run an initialisation function 75 | 76 | The initialisation function will do a number of things: 77 | 78 | * set up the global environment 79 | * change menus, tool-bars and key bindings 80 | * load the code that is needed 81 | 82 | Usually this is done conditionally via hooks. The classic route is a *major-mode* which is triggered by editing files with a certain file type. Later on we will create our own major mode for *omar*. When files whose names match ``*.omar`` are loaded a new mode with menus, tool-bar buttons and key bindings will *magically* appear. 83 | 84 | On starting Emacs our ``.emacs`` file will bind a variety of functions such that Emacs runs them when a file that matches ``*.omar`` is edited. These functions will load our modules as needed and dynamically customise Emacs. 85 | 86 | --------------------- 87 | What You Have Learned 88 | --------------------- 89 | 90 | You have learned: 91 | 92 | * the basics of including code 93 | * how Emacs looks for modules 94 | * how to load some custom code into Emacs at startup 95 | 96 | ------------------ 97 | Additional Reading 98 | ------------------ 99 | 100 | There is a slightly more to loading code in Elisp which is described in the `Loading Code`_ section of the Elisp Reference Manual. 101 | 102 | .. _Loading Code: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/How-Programs-Do-Loading.html#How-Programs-Do-Loading 103 | -------------------------------------------------------------------------------- /contents/lesson-5-2-working-with-buffers-1.rst: -------------------------------------------------------------------------------- 1 | ===================================== 2 | Lesson 5-2 - Working With Buffers (1) 3 | ===================================== 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | We need to learn how to programme Elisp a bit better, and the best way to do that is to write some programmes that add functionality to Emacs itself. 10 | 11 | In this lesson we are going to: 12 | 13 | * add a menu to Emacs 14 | * call functions from that menu which operate on the current buffer 15 | 16 | To do that we will create a file of Elisp which will: 17 | 18 | * define some functions 19 | * add an Emacs menu bound to those functions 20 | 21 | We will then edit the `.emacs` file to load our Elisp file at start up. 22 | 23 | ------------------------ 24 | Preparing Our Elisp File 25 | ------------------------ 26 | 27 | Create a new file called ``omarmenu.el`` in the directory ``~/.emacs.d/omars-dir/`` and type the following code in: 28 | 29 | :: 30 | 31 | (defun omar-count () 32 | (interactive) 33 | (message "When we have finished this will count the number of words in the current buffer")) 34 | 35 | (defvar menu-bar-omar-menu (make-sparse-keymap "Omar")) 36 | 37 | (define-key-after global-map [menu-bar omar] 38 | (cons "Omar's Menu" (make-sparse-keymap "Omar"))) 39 | 40 | (define-key global-map [menu-bar omar omar-count] 41 | '(menu-item "Count" omar-count 42 | :help "Will eventually count words in the current buffer!")) 43 | 44 | (global-set-key (kbd "C-c a") 'omar-count) 45 | 46 | (provide 'omarmenu) 47 | 48 | 49 | Then open your ``.emacs`` file in your home directory add the following lines - You might want to delete everything that is in it first: 50 | 51 | | ``(add-to-list 'load-path "~/.emacs.d/omars-dir")`` 52 | | ``(require 'omarmenu)`` 53 | 54 | All we have done is create an empty function (it prints *When we have finished this will count the number of words in the current buffer* into the modeline). 55 | 56 | We have then created a menu called *Omar's Menu* with one item *Count*. We have then bound *Count* to the approved user key-shortcut *[C]-c a*. 57 | 58 | Finally ``omarmenu.el`` announes to the world that it provied ``omarmenu``. 59 | 60 | We have then edited the ``.emacs`` file telling it to look for Elisp programmes in the directory ``~/.emacs.d/omars-dir/`` and asking it to load the functionality of ``omarmenu``. 61 | 62 | If you have been editing these files (or any files) in Emacs then close it and reopen it. 63 | 64 | Emacs should load its ``.emacs`` file and add a menu item to the menubar. 65 | 66 | Click on the menu-item *Count* and the message should print in the modeline. 67 | 68 | What we will do in this and subsequent lessons is fill in the *empty function* *Count* until it can count the words in the current buffer. 69 | 70 | ---------------------- 71 | Examining Our Function 72 | ---------------------- 73 | 74 | We are going to use a lot of Emacs functions to write our function `omar-count` so we need to learn how to look up their documentation. 75 | 76 | Let's start by examining our own function. We will use the built-in Emacs function `describe-function`. It can be called in the usual way: 77 | 78 | * *[M]-x* `describe-function` 79 | * then enter `omar-count` into the modeline. 80 | 81 | You should see something like this: 82 | 83 | .. image :: /images/emacs-using-describe-function.png 84 | 85 | Let's add a proper function definition for our function. Edit `omarmenu.el`: 86 | 87 | | ``(defun omar-count ()`` 88 | | ``(interactive)`` 89 | | ``"This function counts the number of words in the current buffer"`` 90 | | ``(message "When we have finished this will count the number of words in the current buffer"))`` 91 | 92 | To see this help string in action you will need to either select the menu item *Emacs-Lisp -> Evaluate Buffer* or close and re-open emacs before typing *[M]-x* `describe-function` 93 | 94 | ------------------------- 95 | Implementing The Function 96 | ------------------------- 97 | 98 | Now that we have the function wired in, lets make it do what it says on the tin. Edit the function to look like this: 99 | 100 | | ``(defun omar-count ()`` 101 | | ``"This function will count the number of words in the current buffer."`` 102 | | ``(interactive)`` 103 | | ``(let ((count 0))`` 104 | | ``(goto-char (point-min))`` 105 | | ``(while (< (point) (point-max))`` 106 | | ``(forward-word 1)`` 107 | | ``(setq count (1+ count)))`` 108 | | ``(message "Buffer has %d words." count)))`` 109 | 110 | Let's see what this function does. It starts by defining a local variable `count` using the `let` operator. Note that the brackets which include `let` cover the whole rest of the function. We will look at local and global scope of variables in the next lesson. 111 | 112 | The next function call is ``(goto-char (point-min))``. We can use `describe-function` to work what that does. Executing *[M]-x* `describe-function` for `goto-char` and it prints the following: 113 | 114 | | ``goto-char is an interactive built-in function in `C source code'.`` 115 | | 116 | | ``It is bound to .`` 117 | | 118 | | ``(goto-char position)`` 119 | | 120 | | ``Set point to position, a number or marker.`` 121 | | ``Beginning of buffer is position (point-min), end is (point-max).`` 122 | | 123 | | ``The return value is position.`` 124 | 125 | We can repeat this exercise and see that `point`, `point-min` and `point-max` are all functions that evaluate, respectively, to: 126 | 127 | * the current position of the cursor in integer characters from the start of the buffer 128 | * the position of the start of the buffer - (usually 1 but you can monkey about with where you can start editing the buffer from) 129 | * the position of the end of the buffer 130 | 131 | Note that there are functions that return values, but not the names of variables. The only way to tell them apart is to try and evaluate `point` as both a variable and a function in the *scratch* buffer: 132 | 133 | | ``point ;;this is how you evaluate a variable`` 134 | | ``(point) ;;this is how you evaluate a function`` 135 | 136 | Attempting to evaluate it as a variable will drop you into the debugger. 137 | 138 | The function is then pretty straight forward to understand. Step through the buffer, word-by-word, incrementing the value of `count` every time you do. At the end print out the value of `count`. 139 | 140 | Open a file on your system and try out the function. You will notice that that the `omar-count` actually moves the cursor - it is not some sort of virtual cursor, `got-char` and `forward-word` actually move the cursor. This behaviour is sub-optimal from a user perspective. 141 | 142 | It can be cured by using a special function `save-excursion`. Edit the function to add wrap the body our count function in it as shown below: 143 | 144 | | ``(defun omar-count ()`` 145 | | ``"This function will count the number of words in the current buffer."`` 146 | | ``(interactive)`` 147 | | ``(save-excursion`` 148 | | ``(let ((count 0))`` 149 | | ``(goto-char (point-min))`` 150 | | ``(while (< (point) (point-max))`` 151 | | ``(forward-word 1)`` 152 | | ``(setq count (1+ count)))`` 153 | | ``(message "Buffer has %d words." count))))`` 154 | 155 | Running `describe-function` tells us: 156 | 157 | | ``save-excursion is a special form in 'C source code'.`` 158 | | 159 | | ``(save-excursion &rest body)`` 160 | | 161 | | ``Save point, mark, and current buffer; execute body; restore those things.`` 162 | | ``Executes body just like 'progn'.`` 163 | | ``The values of point, mark and the current buffer are restored`` 164 | | ``even in case of abnormal exit (throw or error).`` 165 | | ``The state of activation of the mark is also restored.`` 166 | | 167 | | ``This construct does not save `deactivate-mark', and therefore`` 168 | | ``functions that change the buffer will still cause deactivation`` 169 | | ``of the mark at the end of the command. To prevent that, bind`` 170 | | ``'deactivate-mark' with 'let'.`` 171 | 172 | --------------------- 173 | What You Have Learned 174 | --------------------- 175 | 176 | You have learned: 177 | 178 | * how to build and plumb in a function from end-to-end 179 | * how to interrogate source code in Elisp to try and work out what things do 180 | * some basic cursor operations 181 | * how to restore the users state once you have manipulated it 182 | 183 | ------------------ 184 | Additional Reading 185 | ------------------ 186 | 187 | When writing this lesson I decided on a function which counted the words in a buffer. Whilst trying to work out how to do it I stumbled upon Chapter 11 of `Learning GNU Emacs`_ which has a function to do precisely this. 188 | 189 | The rest of Chapter 11 is worth reading. 190 | 191 | ---------------- 192 | Extra Activities 193 | ---------------- 194 | 195 | Try and work out how to count the paragraphs and sentences in a buffer. 196 | 197 | .. _Learning Gnu Emacs: http://oreilly.com/catalog/9781565921528 198 | 199 | -------------------------------------------------------------------------------- /contents/lesson-5-3-scope-of-variables-set-setq-let-etc.rst: -------------------------------------------------------------------------------- 1 | ========================================================== 2 | Lesson 5-3 - Scope Of Variables (set, setq, let, let* etc) 3 | ========================================================== 4 | 5 | Introduction 6 | ------------ 7 | 8 | Scope is an important concept in programming. When is the variable 'X' this 'X' and not that 'X', from where does 'X' gets its value, how is 'X' changed. 9 | 10 | ELisp has 4 different types of scope: 11 | 12 | * global scope 13 | * local scope 14 | * buffer-local scope 15 | * terminal-local scope 16 | 17 | The type of scope that Elisp implements is *dynamic* scope. The majority of Lisp dialects implement dynamic scope, but they predominately use a different type of scope called *lexical* scope. 18 | 19 | A version of lexical scope is available in Elisp by using a package called 'cl'. This will not be discussed in this book. 20 | 21 | TODO - add a section on dynamic scope in Elisp versus lexical scope in other Lisps 22 | 23 | ------------ 24 | Global Scope 25 | ------------ 26 | 27 | Let's create a variable with *global scope*. Edit the file ``omar-menu.el`` in ``./emacs.d/omars-dir/`` 28 | 29 | Add the line: 30 | 31 | :: 32 | 33 | (setq omars-kills 123) 34 | 35 | and then use the menu *Emacs-Lisp -> Evaluate Buffer* to execute that file again. 36 | 37 | If you now go to *\*scratch\** and evaluate the variable ``omars-kills`` in it you will see ``123``. 38 | 39 | The *global variable* ``omars-kills`` is available to any line of any function in the programme. 40 | 41 | This is what we techies call **A Bad Thing**, or to put it another way **A Really Bad Thing (TM) (C) (R)**. 42 | 43 | At least in ELisp you have to explicity make a symbol have global scope - unlike Javascript where you can make a global scope variable by accident. 44 | 45 | ------------------------------------ 46 | The Dastardly Nature Of Global Scope 47 | ------------------------------------ 48 | 49 | 50 | 51 | Buffer-Local Variables 52 | ---------------------- 53 | 54 | We have seen that Elisp has some variables that *appear* global in scope. We looked at the variable ``fill-column`` in lesson 2-4 and it appeared to be one such. 55 | 56 | If we evaluate ``fill-column`` in *\*scratch\** we get the value: 57 | 58 | :: 59 | 60 | fill-column ;;its not in brackets because it is not a function! 61 | 70 62 | 63 | (remember to evaluate an expression in *\*scratch\** use *[Crtl]-j*) 64 | 65 | But if we use ``describe-variable`` to see the definition of ``fill-column`` it tells a slightly different story: 66 | 67 | :: 68 | 69 | fill-column is a variable defined in `C source code'. 70 | Its value is 70 71 | 72 | Automatically becomes buffer-local when set in any fashion. 73 | This variable is safe as a file local variable if its value 74 | satisfies the predicate `integerp'. 75 | 76 | Documentation: 77 | *Column beyond which automatic line-wrapping should happen. 78 | Interactively, you can set the buffer local value using C-x f. 79 | 80 | You can customize this variable. 81 | 82 | The thing that should get your eyebrows raised is the phrase *buffer-local*. What this means is that ``fill-column`` isn't actually a *global-variable* there is a ``fill-column`` variable for each buffer. 83 | 84 | This chapter will look at how that sort of local scope is implemented in Elisp. 85 | 86 | --------------------- 87 | What You Have Learned 88 | --------------------- 89 | 90 | ------------------ 91 | Additional Reading 92 | ------------------ 93 | 94 | Richard Stallman laid out the rationale for dynamic binding in a `paper`_ he wrote for the ACM Conference on Text Processing. 95 | 96 | ---------------- 97 | Extra Activities 98 | ---------------- 99 | 100 | 101 | .. _paper: http://www.gnu.org/software/emacs/emacs-paper.html#SEC15 102 | -------------------------------------------------------------------------------- /contents/lesson.template: -------------------------------------------------------------------------------- 1 | ================================ 2 | Lesson 3 | ================================ 4 | 5 | :You Type: 6 | :Result: 7 | 8 | --------------------- 9 | What You Have Learned 10 | --------------------- 11 | 12 | ------------------ 13 | Additional Reading 14 | ------------------ 15 | 16 | ---------------- 17 | Extra Activities 18 | ---------------- 19 | 20 | 21 | -------------------------------------------------------------------------------- /contents/major-and-minor-modes.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Major And Minor Modes 3 | ===================== 4 | 5 | ------------ 6 | Introduction 7 | ------------ 8 | 9 | The purpose of this book is to teach you how to do useful stuff with Elisp. The thing Elisp is really useful for is customising Emacs. Before we start writing programmes like that we need to understand a bit more about how Emacs is designed to be customised. 10 | 11 | Emacs works by reading files from the hard drive into buffers and performing operations on them at the users request. You can customise what operations are done with 2 mechanisms: 12 | 13 | * minor modes 14 | * major modes 15 | 16 | --------------- 17 | What Is A Mode? 18 | --------------- 19 | 20 | 21 | 22 | The difference between them is simple: 23 | * at anyone time 24 | 25 | --------------------- 26 | What You Have Learned 27 | --------------------- 28 | 29 | ------------------ 30 | Additional Reading 31 | ------------------ 32 | 33 | ---------------- 34 | Extra Activities 35 | ---------------- 36 | 37 | 38 | -------------------------------------------------------------------------------- /contents/other-formats.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Other Formats 3 | ============= 4 | 5 | --- 6 | PDF 7 | --- 8 | 9 | This book is also available as a `PDF`_. 10 | 11 | .. _PDF: http://learn-Elisp-for-emacs.org/files/Learn-Elisp-For-Emacs.pdf 12 | -------------------------------------------------------------------------------- /contents/references.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | References 3 | ========== 4 | 5 | The GNU organisation has published a book on programming in Elisp. It is entitled `An Introduction To Programming In Elisp`_. 6 | 7 | There is also a reference manual - the `GNU Emacs Lisp Reference Manual`_. 8 | 9 | There is also a commercially published book `Writing GNU Emacs Extensions`_. 10 | 11 | Where appropriate this book will refer you to these works for further reading. 12 | 13 | 14 | .. _An Introduction To Programming In Elisp: http://www.gnu.org/software/emacs/emacs-lisp-intro/ 15 | 16 | .. _GNU Emacs Lisp Reference Manual: http://www.gnu.org/software/emacs/emacs-lisp-intro/elisp/index.html#Top 17 | 18 | .. _Writing GNU Emacs Extensions: http://astore.amazon.com/hypernumbersc-20/detail/1565922611 19 | -------------------------------------------------------------------------------- /contents/the-learn-elisp-for-emacs-community.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | The Learn Elisp For Emacs Community 3 | =================================== 4 | 5 | ------- 6 | License 7 | ------- 8 | 9 | When this book is finished it will be released under a Creative Commons License. At the moment is remain copyright Gordon Guthrie (2010). Until it has been finished you MAY NOT redistribute it but may participate in the community development of the text by forking the git repository. 10 | 11 | ----------- 12 | eMail Group 13 | ----------- 14 | 15 | You can join the `Mailing List`_ to contribute your thoughts or ask for help. 16 | 17 | --------------------- 18 | Public Git Repository 19 | --------------------- 20 | 21 | You can checkout the sources for this book from the `Public Git Repository`_ 22 | 23 | ------- 24 | Website 25 | ------- 26 | 27 | This book has an `Official Website`_. 28 | 29 | .. _Mailing List: http://groups.google.com/group/learn-Elisp-for-emacs 30 | 31 | .. _Public Git Repository: https://github.com/hypernumbers/learn_Elisp_the_hard_way 32 | 33 | .. _Official Website: http://learn-Elisp-for-emacs.org/ 34 | -------------------------------------------------------------------------------- /contents/ttd.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Things To Do 3 | ============ 4 | 5 | -------------------------- 6 | Changes to written lessons 7 | -------------------------- 8 | 9 | * need a lesson on arrays (used in menus for lesson 9) - called lesson-6 a for he mo pending reorganisation 10 | 11 | * lesson 9 needs finishing 12 | 13 | ------------------------------ 14 | Suggestions for future lessons 15 | ------------------------------ 16 | 17 | * needs some lessons on control structures - do/while - eek no for loops 18 | 19 | * needs some more list processing functions - map etc, etc 20 | 21 | * mebbies needs some anonymous function stuff 22 | -------------------------------------------------------------------------------- /contents/what-will-this-book-cover.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | What This Book Will Cover? 3 | ========================== 4 | 5 | --------- 6 | What's In 7 | --------- 8 | 9 | This book will cover enough Elisp to enable you to: 10 | 11 | * understand ``.emacs`` files 12 | * write your own functions to put in ``.emacs`` files 13 | * create your own Emacs menu's 14 | * write functions that execute on events like opening and closing a file 15 | * attach functions to key strokes to enable you to customise the behaviour of your Emacs 16 | 17 | ------------- 18 | What's Not In 19 | ------------- 20 | 21 | This book will not teach you enough Lisp to be an proper Lisp developer. 22 | -------------------------------------------------------------------------------- /contents/who-is-this-book-for.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Who Is This Book For? 3 | ===================== 4 | 5 | --------------- 6 | Target Audience 7 | --------------- 8 | 9 | The target audience for this book is people with some experience of programming in a non-functional programming language: 10 | 11 | * procedural languages like Fortran, Algol, C etc, etc 12 | * object orientated languages like C++, Java, Ruby etc, etc 13 | * scripting languages like PHP, Python, Perl etc, etc 14 | 15 | (I appreciate that these categories probably fail as strict Comp Sci definitions.) 16 | 17 | If you have already mastered a 'conventional' Functional Programming language this book **might not** be for you - there are good books about learning a variety of Lisps out there. Functional Programming languages include: 18 | 19 | * Lisp and it dialects like Scheme, Clojure, Common Lisp (CL) etc, etc 20 | * Erlang 21 | * Haskell 22 | 23 | (Of course the majority of the worlds 'programmers' are end-users who are pragmatic folks using Excel, Open Office or, natch, Hypernumbers. This book is not really aimed at end-user spreadsheet 'programmers' either.) 24 | 25 | ------------------------------ 26 | How Much Experience Is Needed? 27 | ------------------------------ 28 | 29 | If you can write a small programme to do something in a non-functional programming language from scratch then you should be experienced enough. 30 | -------------------------------------------------------------------------------- /contents/why-did-I-write-this-book.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Why Did I Write This Book? 3 | ========================== 4 | 5 | ---------- 6 | Why Elisp? 7 | ---------- 8 | 9 | I am writing this book to learn Elisp myself. I use Emacs every day because it is the IDE of choice for Erlang and I am an Erlang programmer. 10 | 11 | My relationship with Emacs is that of Simson Garfinkel, Daniel Weise and Steven Strassmann to `Unix`_ - I genuinely loathe it. 12 | 13 | Emacs is the most prominent piece of software in the *apostolic* tradition. You are supposed to learn it by being instructed by someone who learnt it by being instructed by someone recursively all the way back to the original authors in a continuous apostolic succession. 14 | 15 | I would fain be the John Knox, the Calvin, the Luther, and hell mend them. 16 | 17 | By writing this book I hope to be able to write Elisp to configure and extend Emacs in my working environment. 18 | 19 | ----------------------- 20 | Why Choose This Format? 21 | ----------------------- 22 | 23 | I have chosen to use a format based on *Learn X The Hard Way*. That format is specifically aimed at writing books for non-programmers. My target audience is programmers with no functional programming experiences. Funtional Programming Languages in general (and Lisp in particular) are far enough from Object Orientated or Procedural languages that learning them is like starting to programme again - so the *beginners* format is quite appropriate. 24 | 25 | I have not called the book *Learn Elisp The Hard Way* because this slightly hybrid formula would confuse that core brand. 26 | 27 | I occasionally have to dip into Elisp in the form of .emacs files which are executed on startup and are how you configure Emacs to do specific stuff for your particular requirements. 28 | 29 | One of the reasons why the *Learn X The Hard Way* books work is that the format of forcing people to type in code is a great way to teach them how to read the syntax. Elisp still looks like line noise to me and I have been programming since the late 70s in languages as diverse as Fortran, VB, C++, Java, Perl, Python, PHP, Ruby and Erlang. Writing this book has been a good way to learn how to *read* Elisp for me, and I hope it will work for the readers. 30 | 31 | The transition from Fortran to the Obect Orientated paradigm of C++ was enormously painful. The shift from the OO paradigm (Ruby was my language *de jour* then) to functional programming in the form of Erlang was also horrendous. 32 | 33 | I may be wrong, but I think that many experienced programmers who have no previous exposure to functional programming would benefit from a pretty brutal beginners style book about Elisp. 34 | 35 | I have copies of `On Lisp`_ by Paul Graham and `Common Lisp A Gentle Introduction To Symbolic Computing`_ but have never been able to learn Lisp because of the very basic problem that Zed Shaw identified in `his article`_ on *How To Write A LxTHW* - I could never work out how to get to a basic working shell to type the code examples into. It's not that I didn't try, its just that after a summer of trying to start learning Lisp I had gotten nowhere. If you think that that's my fault, then it falls to you to explain how I managed to learn a bazillion other languages successfully. 36 | 37 | The other appealing part of this format is that it isn't a reference book. To make clear just how unsuited I am to write a reference book about Lisp, let me enumerate ATTIDNK (All The Things I Do Not Know): 38 | 39 | * the difference between Emacs and XEmacs 40 | * the difference between Elisp and Lisp 41 | * how Common Lisp is related to Clojure or any other Lisp 42 | * how Lisp does package management 43 | * pretty much everything else I would need to know to write a reference book 44 | 45 | ---------------------------------- 46 | On Learning Functional Programming 47 | ---------------------------------- 48 | 49 | If you just want to learn **a functional programming language** you really should learn Erlang and I recommend `Joe's book`_ or `Franceso and Simon's one`_. 50 | 51 | ------------------- 52 | Big Up For Zed Shaw 53 | ------------------- 54 | 55 | Zed Shaw? `Who?`_ `Why?`_ 56 | 57 | .. _Unix: http://www.amazon.com/UNIX-Haters-Handbook-Daniel-Weise/dp/1568842031/ref=sr_1_1?ie=UTF8&s=books&qid=1290297419&sr=1-1 58 | .. _On Lisp: http://www.amazon.com/LISP-Advanced-Techniques-Common/dp/0130305529/ref=sr_1_1?ie=UTF8&qid=1290295941&sr=8-1 59 | .. _Common Lisp A Gentle Introduction To Symbolic Computing: http://www.amazon.com/Common-Lisp-Introduction-Symbolic-Computation/dp/0805304924/ref=sr_1_8?s=books&ie=UTF8&qid=1290296197&sr=1-8 60 | .. _his article: http://sheddingbikes.com/posts/1288945508.html 61 | .. _Joe's book: http://www.amazon.com/Programming-Erlang-Software-Concurrent-World/dp/193435600X/ref=sr_1_2?s=books&ie=UTF8&qid=1290296292&sr=1-2 62 | .. _Franceso and Simon's one: http://www.amazon.com/ERLANG-Programming-Francesco-Cesarini/dp/0596518188/ref=sr_1_1?s=books&ie=UTF8&qid=1290296292&sr=1-1 63 | .. _Who? : http://www.zedshaw.com/ 64 | .. _Why? : http://sheddingbikes.com/posts/1288945508.html 65 | -------------------------------------------------------------------------------- /images/elisp-sequences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/elisp-sequences.png -------------------------------------------------------------------------------- /images/emacs-components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-components.png -------------------------------------------------------------------------------- /images/emacs-customization-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-customization-groups.png -------------------------------------------------------------------------------- /images/emacs-debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-debugger.png -------------------------------------------------------------------------------- /images/emacs-debugger2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-debugger2.png -------------------------------------------------------------------------------- /images/emacs-font-dialog-box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-font-dialog-box.png -------------------------------------------------------------------------------- /images/emacs-lisp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-lisp.png -------------------------------------------------------------------------------- /images/emacs-using-describe-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs-using-describe-function.png -------------------------------------------------------------------------------- /images/emacs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/emacs.png -------------------------------------------------------------------------------- /images/learn-elisp-for-emacs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/learn-elisp-for-emacs.png -------------------------------------------------------------------------------- /images/synaptic_package_manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypernumbers/learn_elisp_the_hard_way/a7ffebd8c3ccaad808682dc179d9628a7874b7f7/images/synaptic_package_manager.png -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | .. Learn ELisp For Emacs master file, created by 2 | sphinx-quickstart on Sat Nov 6 22:31:37 2010. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Learn Elisp For Emacs 7 | ===================== 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | 12 | contents/learning-elisp 13 | contents/why-did-I-write-this-book 14 | contents/contributors 15 | contents/who-is-this-book-for 16 | contents/what-will-this-book-cover 17 | contents/references 18 | contents/the-learn-elisp-for-emacs-community 19 | contents/other-formats 20 | contents/ttd 21 | 22 | 1 - Getting Started 23 | =================== 24 | 25 | .. toctree:: 26 | :maxdepth: 1 27 | 28 | contents/getting-started 29 | contents/lesson-1-1-using-emacs 30 | 31 | 2 - First Steps 32 | =============== 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | contents/lesson-2-1-first-elisp-programme 38 | contents/lesson-2-2-primitive-data-types-1 39 | contents/lesson-2-3-lists-at-last 40 | contents/lesson-2-4-symbols-and-variables 41 | contents/lesson-2-5-arrays-and-sequences 42 | contents/elisp-is-a-lisp 43 | 44 | 3 - eLisp Scripts 45 | ================= 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | 50 | contents/lesson-3-1-writing-functions 51 | contents/lesson-3-2-more-functions 52 | 53 | 4 - eLisp In Emacs (With The Debugger) 54 | ====================================== 55 | 56 | .. toctree:: 57 | :maxdepth: 1 58 | 59 | contents/lesson-4-1-writing-elisp-in-emacs 60 | contents/lesson-4-2-adding-custom-functions-to-emacs 61 | contents/best-practice-1-writing-better-elisp 62 | contents/lesson-4-3-emacs-menus 63 | contents/lesson-4-4-adding-buttons-to-the-toolbar 64 | contents/emacs-and-the-dot-emacs-file 65 | 66 | 5 - eLisp Files 67 | =============== 68 | 69 | .. toctree:: 70 | :maxdepth: 1 71 | 72 | contents/lesson-5-1-elisp-in-files 73 | contents/lesson-5-2-working-with-buffers-1 74 | contents/lesson-5-3-scope-of-variables-set-setq-let-etc 75 | 76 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set BUILDDIR=_build 7 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 8 | if NOT "%PAPER%" == "" ( 9 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 10 | ) 11 | 12 | if "%1" == "" goto help 13 | 14 | if "%1" == "help" ( 15 | :help 16 | echo.Please use `make ^` where ^ is one of 17 | echo. html to make standalone HTML files 18 | echo. dirhtml to make HTML files named index.html in directories 19 | echo. pickle to make pickle files 20 | echo. json to make JSON files 21 | echo. htmlhelp to make HTML files and a HTML help project 22 | echo. qthelp to make HTML files and a qthelp project 23 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 24 | echo. changes to make an overview over all changed/added/deprecated items 25 | echo. linkcheck to check all external links for integrity 26 | echo. doctest to run all doctests embedded in the documentation if enabled 27 | goto end 28 | ) 29 | 30 | if "%1" == "clean" ( 31 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 32 | del /q /s %BUILDDIR%\* 33 | goto end 34 | ) 35 | 36 | if "%1" == "html" ( 37 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 38 | echo. 39 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 40 | goto end 41 | ) 42 | 43 | if "%1" == "dirhtml" ( 44 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 45 | echo. 46 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 47 | goto end 48 | ) 49 | 50 | if "%1" == "pickle" ( 51 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 52 | echo. 53 | echo.Build finished; now you can process the pickle files. 54 | goto end 55 | ) 56 | 57 | if "%1" == "json" ( 58 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 59 | echo. 60 | echo.Build finished; now you can process the JSON files. 61 | goto end 62 | ) 63 | 64 | if "%1" == "htmlhelp" ( 65 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 66 | echo. 67 | echo.Build finished; now you can run HTML Help Workshop with the ^ 68 | .hhp project file in %BUILDDIR%/htmlhelp. 69 | goto end 70 | ) 71 | 72 | if "%1" == "qthelp" ( 73 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 74 | echo. 75 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 76 | .qhcp project file in %BUILDDIR%/qthelp, like this: 77 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\LearneLispTheHardWay.qhcp 78 | echo.To view the help file: 79 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\LearneLispTheHardWay.ghc 80 | goto end 81 | ) 82 | 83 | if "%1" == "latex" ( 84 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 85 | echo. 86 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 87 | goto end 88 | ) 89 | 90 | if "%1" == "changes" ( 91 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 92 | echo. 93 | echo.The overview file is in %BUILDDIR%/changes. 94 | goto end 95 | ) 96 | 97 | if "%1" == "linkcheck" ( 98 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 99 | echo. 100 | echo.Link check complete; look for any errors in the above output ^ 101 | or in %BUILDDIR%/linkcheck/output.txt. 102 | goto end 103 | ) 104 | 105 | if "%1" == "doctest" ( 106 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 107 | echo. 108 | echo.Testing of doctests in the sources finished, look at the ^ 109 | results in %BUILDDIR%/doctest/output.txt. 110 | goto end 111 | ) 112 | 113 | :end 114 | --------------------------------------------------------------------------------