Emacs
Table of Contents
- 1. Tmp
- 2. Jupyter
- 3. buffer
- 4. Getting Help
- 5. Configuration
- 6. Window and Frame
- 7. File Operation
- 8. Editing
- 9. Programming
- 10. Remote
- 11. Moving
- 12. Navigating
- 13. Special Modes
- 14. Variables
- 15. Advanced Topics
- 16. Plugins
- 17. Mail
- 18. Elisp
- 19. Reference
1 Tmp
toggle-truncate-lines
: some file format, e.g. txt, will have a line wrap at the end of the screen. This might be annoying, and toggle this will truncate the line.browse-url-of-file
: open current file in browserorg-toggle-inline-images (C-c C-x C-v)
In emacs, <DEL> means backspace, <delete> means the delete key.
If sometimes emacs runs slow, you can profiler-start
, and do the
slow operations, and profiler-report
. When finished, stop it by
profiler-stop
to avoid overhead.
1.1 DOS/UNIX line ending
If the mode line shows a (DOS) indicator, click on it twice to cycle to : meaning Unix newlines and then save the file.
If you can't click on the mode line or prefer a keyboard-based solution, run the command C-x RET f (set-buffer-file-coding-system) and type unix.
1.2 electric-indent-mode
Disabling this to yank raw content
1.3 emacs-common-non-dfsg
In debian/ubuntu, emacs and elisp info pages are not installed by default with
emacs
package. You need to install emacs-common-non-dfsg
to get them. Not
sure why and not sure what does "dfsg" mean.
2 Jupyter
I'm moving from Emacs to JupyterLab. There are several good reasons:
- Jupyter is implemented as server-client model. I have to use remote server because I don't want to bring a desktop with me. Emacs-with-tramp and VScode does not feel right, and it is confusing of whehter you are on local or remote. The jupyter model is server only.
- Multiple users.
- Literal programming. The jupyter notebook's way of mixing docs/code/results is so much cleaner than org-mode.
- last but no least, scalability
2.1 Jupyterlab editor experience
2.1.1 Use jupyter Emacs bindings with Chrome
[X]
Ctrl-n: this can be solved by running chrome in app mode[X]
ctrl-p: this can be solved by adding some custom shortcuts:
{"shortcuts": [ { "command": "apputils:print", "keys":["Accel P"], "selector": "body", "disabled": true }, { "command": "documentsearch:start", "keys": [ "Accel F" ], "selector": ".jp-mod-searchable", "disabled": true }, ]}
2.1.2 TODO syntax highlight for racket in editor
How to tell the editor to use scheme syntax for .rkt files?
2.1.3 TODO auto indent
[ ]
no auto-reindent functionality, and I rely on that a lot. This is going to be too hard. I'm turning to just use SSH+Emacs + jupyter notebook for simple high-level visualization. Also the boards should be written in notebooks, and I'll be manually indenting them probably.
2.1.4 doc accessibility
2.1.5 lab extensions
I have trouble to use web extension manager, most likely due to permission. I cannot set up admin user account no matter the confiuguration file.
I have to install via command line.
jupyter labextension install my-extension jupyter labextension enable my-extension jupyter labextension list
and you seem to need to restart jupyterlab.
This actually requires the specific jupyter binary:
sudo /opt/jupyterhub/bin/jupyter install ...
Many times, you will have to install some pip packages. E.g. for installing @jupyterlab/git, I'll need:
sudo /opt/jupyterhub/bin/jupyter install @jupyterlab/git sudo /opt/jupyterhub/bin/python3 -m pip install jupyterlab-git sudo /opt/jupyterhub/bin/jupyter lab build sudo systemctl restart jupyterhub
2.2 Setting up jupyterhub
Follow this guide.
2.3 jupyter notebook external availability
by default jupyter notebook is only available localhost.
Following https://jupyter-notebook.readthedocs.io/en/stable/public_server.html:
jupyter lab --port=8888 --no-browser --ip=0.0.0.0
But I'll need to have the token, and it did not seem to be the most secure. It is possible to setup password according to that doc.
2.4 TODO HTTPS and other security implication
2.5 Other things
2.5.1 binder
Turn a Git repo into a collection of interactive notebooks
3 buffer
list-face-displays
fill-region
- count-matches
4 Getting Help
describe-key-briefly
: defaults toC-h c
, return the command name of a key stroke.where-is
: defaults toC-h w
, return the current shortcut for a commandinfo
: defaults toC-h i
, open the built-in info reader.view-echo-area-messages
5 Configuration
To configure a specific key map.
Note that the global-set-key
will not overwrite a specific key map,
because the specific one has a higher priority.
(define-key org-mode-map (kbd "C-j") (lambda() (interactive) (join-line -1)))
Package installation is done by the built-in package management. Be sure to add it into the start script to be able to automatically install it for a new build of emacs.
list-package
: open the package page. UseU x
to update all available.
6 Window and Frame
6.1 window manage
balance-window
toggle-window-split
enlarge-window
shrink-window
6.2 dired
dired-next-subdir
dired-prev-subdir
dired-tree-up
dired-tree-down
6.3 packages
In *package*
buffer, Ux
to update all packages.
7 File Operation
revert-buffer
- Replace current buffer text with the text of the visited file on disk. I.e. Reload file.
recover-file
- recover from
#xxx#
file. read-only-mode
- disable it to edit read only files
8 Editing
8.1 text transformation
replace-rectangle
upcase-word
downcase-word
transpose-words
transpose-lines
To insert a control sequence, use C-q xxx
.
capitalize-word
fill-paragraph
(M-q)fill-region
auto-fill-mode
When replace-string, use C-q C-j
to represent newline.
8.2 killing
zap-to-char
zap-up-to-char
8.3 spell checking
Use ispell
, and flycheck
to check on-the-fly. Check emacs manual for detail.
8.4 Replace regexp for multiple files inside project
find-name-dired
, select the root directory, and provide a pattern for files- press
t
to toggle mark all files - press Q for query and replace in files, and provide regexp and replacement
- proceed each of the match by:
SPC
to confirm, andn
to skip to next. - Finally all files are not saved. To save that,
C-x s
will prompt all file and wait for your confirm byy
. To avoid hittingy
many times, useC-x s !
.
9 Programming
checkdoc
: check the warnings in doc string. It can also fix it:C-h f
.C-x C-e
: evaluateC-u C-x C-e
: evaluate and insert result
10 Remote
Use tramp
can easily work with remote machine. It is shipped with
Emacs. To use it, simply C-x C-f
and enter /user@host:
, Emacs will
prompt password. user@
is optional. Do not use fancy shell prompt,
otherwise tramp might hang. You can also enter /su::
to edit as
root for local files.
You can use helm
no problem, and you can also enter the remote
shell.
11 Moving
Defun movement:
C-M-a
- move to the beginning of defun
C-M-e
- move to the end of defun
C-M-h
- mark defun
C-M-x
- evaluate defun
Sexp movement
C-M-f
- move forward a sexp
C-M-b
- move backward a sexp
C-M-k
- kill a sexp
C-M-<SPC>
- mark following sexp
C-M-n
- move to the next sexp
C-M-p
- move to the previous sexp
Other
C-M-t
- transpose expressions
C-M-u
- move up parenthesis
C-M-d
- move down parenthesis
M-m
- back-to-indentation
12 Navigating
forward-sexp
: forward semantic blockbackward-sexp
org-forward-heading-same-level
:C-c C-f
org-backword-heading-same-level
:C-c C-b
12.1 marking
exhange-point-and-mark
mark-word
mark-sexp
mark-paragraph
mark-defun
mark-page
mark-whole-buffer
point-to-register
: save ppposition in a registerjump-to-register
set-mark-command
: C-SPC, set mark, and activate itC-SPC C-SPC
: set mark, but not activate it.C-u C-SPC
: pop to previous mark in mark ring. current is stored at the end of mark ring(rotating)pop-global-mark
: will store both position and buffer
All events that set the mark:
C-SPC C-SPC
C-w
- search
12.2 register
jump-to-register
: the register can store a filecopy-to-register
insert-register
12.3 Tags
helm-etags-select
13 Special Modes
13.1 Tex Mode
tex-validate-region
14 Variables
14.1 File Local Variable
On first line, emacs will try to find
-*- mode: Lisp; fill-column: 75; comment-column: 50; -*-=
mode
defines the major mode for this file, while unlimited
numbers of variables follows, separated by ;
Emacs looks for
local variable specifications in the second line if the first line
specifies an interpreter, e.g. shebang.
A second way to specify file local variable is to have a "local
variables list" near the end of the file (no more than 3000
characters from the end of the file). The Local Variables:
and
End:
will be matched literally.
This /* Local Variables: */ Is /* mode: c */ Garbage /* comment-column: 0 */ Data /* End: */
You can also interactively add by add-file-local-variable
, reload
the variable by revert-buffer
14.2 Directory Local Variable
Put .dir-locals.el
at the root directory, and it will be in effect for all the files under that directory, recursively.
It should be an associate list, the car can be either a mode name (or nil
applies to all modes) indicating the variables are for that mode,
or a sub-directory name to apply only in that directory.
((nil . ((indent-tabs-mode . t) (fill-column . 80))) (c-mode . ((c-file-style . "BSD") (subdirs . nil))) ("src/imported" . ((nil . ((change-log-default-name . "ChangeLog.local"))))))
15 Advanced Topics
15.1 Info
Info is a document system.
It is closely bundled with emacs, so I put it here.
To install some new info document in the system,
issue the following commands (using gnu-c-manual
as an example):
# download the gnu-c-manual code make gnu-c-manual.info mv gnu-c-manual.info /usr/local/share/info cd /usr/local/share/info sudo install-info --info-file=gnu-c-manual.info --info-dir=.
15.1.1 Operations
key | description |
---|---|
SPC | page down, can cross node |
BACKSPACE | page up, can cross node |
M-n | clone-buffer , create a new independent info window |
n | next node on same level |
p | previous |
] | next node regardless of level |
[ | previous |
u | up node |
l | back |
r | forward |
m | Info-menu , convenient for search node title |
s | TODO search a text in the whole info file |
i | TODO search indices only |
15.2 Babel
How to write a ob-xxx.el
file?
- search org-mode babel, you will get a link: http://orgmode.org/worg/org-contrib/babel/
- In this link, there's a "languages" link. http://orgmode.org/worg/org-contrib/babel/languages.html
- Under "Develop support for new languages" section, there's link to ob-template.el: http://orgmode.org/w/worg.git/blob/HEAD:/org-contrib/babel/ob-template.el
- follow instruction to modify it.
some good example to look at: ob-plantuml.el, ob-C.el
16 Plugins
16.1 ERC
erc
: connecterc-iswitch
:C-c C-b
erc-join-channel
:C-c C-j
erc-save-buffer-in-logs
:C-c C-l
erc-channel-names
:C-c C-n
: run/names #channel
command in the current channel.erc-part-from-channel
:C-c C-p
: leave the channelerc-quit-server
:C-c C-q
: disconnect server
IRC commands
- identify:
/msg NickServ identify <password>
- join:
/join #linux
- register:
/msg NickServ register <psssword> <email>
- private talking:
/query <nick>
. Only registered people can be queried
16.2 Flycheck
The default (at least the one I'm using) for C/C++ is c/c++-clang
.
flycheck-describe-checker
flycheck-list-errors
16.3 flyspell
flyspell-auto-correct-word
(C-.
)flyspell-goto-next-error
(C-,
)
16.4 AUCTex
C-c C-c
: tex-compile
16.5 DocView
Can view pdf in emacs. It is convenient to use the same keybinding for tex-compile
:
when you press C-c C-c
the second time after compilation, it will default to \doc-view
.
16.5.1 navigation
C-p
C-n
C-b
C-f
still works+
and-
to adjust scalen
andp
for page navigationspace
anddelete
to page up and down across pagesM-<
andM->
still worksM-g M-g
works as jump to page
16.6 pdf-tools
The doc view produce very blur text. The pdf-view-mode provided by pdf-tools solved this. Also, this package is said to open pdf on demand. It seems to solve my concern for pdf greatly.
Extra bonus:
- search in text
- view and edit annotations!
http://emacs.stackexchange.com/questions/19686/how-to-use-pdf-tools-pdf-view-mode-in-emacs
16.6.1 Installation
sudo aptitude install libpng-dev libz-dev sudo aptitude install libpoppler-glib-dev sudo aptitude install libpoppler-private-dev sudo aptitude install imagemagick
cd /path/to/pdf-tools make install-server-deps # optional make -s make install-package # or M-x package-install-file RET pdf-tools-${VERSION}.tar RET
activate in emacs by (pdf-tools-install)
16.6.2 key binding
o
: open outlineQ
: kill bufferq
: kill window
16.7 Paredit
command | Key | description |
---|---|---|
paredit-forward-slurp-sexp | C-) | enclose the next into this sexp |
paredit-forward-barf-sexp | C-} | exclude |
paredit-backward-slurp-sexp | C-( | |
paredit-backward-barf-sexp | C-{ | |
paredit-wrap-round | M-( | |
paredit-join-sexp | M-J | |
paredit-splice-sexp | M-s | |
paredit-split-sexp | M-S | |
paredit-raise-sexp | M-r | |
paredit-convolute-sexp | M-? | exchange child and parent |
16.8 Magit
C-x g
to enter, and
c c
to commmitc a
to amend commitP u
to pushF u
to pull
16.9 Speedbar
This is strictly not a plugin. Toggle by speedbar
.
- q
- quit
- g
- refresh
- t
- toggle slowbar mode, which stop update until activate
- n,p
- next, previous
- M-n,M-p
- restricted next/previous. Will 1) skip subdirectory, and 2) will not leave subdirectory
- f
- file mode
- b
- buffer mode
- r
- previous mode
- =
- expand
- -
- hide
- RET
- open
16.9.1 Buffer Mode
- k
- kill the buffer
- r
- revert the buffer
16.10 EDBI
This is database viewer for MySQL, Sqlite, Postgresql.
Install edbi
and edbi-sqlite
package and run as root:
cpan RPC::EPC::Service DBI DBD::SQLite DBD::Pg DBD::mysql
Run edbi-sqlite
to open a sqlite database. This will open database view.
To sum up:
- n/p
- nav rows
- c
- query editor
- C-c C-c
- execute
- q
- quit
- RET
- go into
- SPC
- display info
- V
- show table data
16.10.1 Database View
- n/p
- nav rows
- c
- switch to query editor buffer
- RET
- show table data
- SPC
- show table definition
- q
- quit and disconnenct
16.10.2 Table definition View
- n/p
- c
- V
- show table data
- q
- kill buffer
16.10.3 Query Editor
- C-c C-c
- execute
- C-c q
- kill buffer
- M-p/n
- SQL history back/forward
16.10.4 Query Result Viewer
- n/p
- SPC
- display whole data at current cell, hit SPC again to dismiss
- q
- quit
16.11 EMMS
16.11.1 Add files into playlist
- emms-add-file
- emms-add-directory
- emms-add-directory-tree (recursive)
- emms-add-playlist (m3u)
- emms-add-find: use regexp with find
16.11.2 Interactive control in playlist mode
- emms-start
- emms-stop (s)
- emms-next (n)
- emms-previous
- emms-shuffle
- emms-pause (P)
- emms-random (r): go to a randomly selected track in the playlist
- emms-sort
- emms-show (f): show the current track in minibuffer
- emms-seek-forward (>)
- emms-seek-backward (<)
- emms-playlist-mode-center-current (c): center the current song
- emms-playlist-mode-play-smart (RET): play the song under cursor
- emms-playlist-mode-bury-buffer (q): bury buffer
- emms-playlist-mode-clear (C)
In playlist mode, you can kill and yank as normal, use C-j
to insert
newline.
In addition to the default playlist, we also have the markable
playlist. The emms-mark-mode
and emms-mark-mode-disable
can switch
between them. In the mark mode, you can:
- emms-mark-forward (m)
- emms-mark-unmark-all (U)
- emms-mark-toggle (t)
- emms-mark-unmark-forward (u)
- emms-mark-regexp (% m)
When tracks are marked, you can
- emms-mark-delete-marked-tracks (D)
- emms-mark-kill-marked-tracks (K): like D, but put into kill ring, so we can yank it back
- emms-mark-copy-marked-tracks: just kill, ready for yank
Play Property
emms-repeat-playlist
: variable, non-nil means repeat the playlistemms-toggle-repeat-playlist
: changeemms-repeat-playlist
emms-toggle-random-playlist
: random
Play list
emms-playlist-new
emms-playlist-save
(C-x C-s): just use m3u format
16.11.3 Edit the tags:
- emms-tag-editor-edit (E): need to have software support. E.g
mp3info
- emms-tag-editor-rename-format: this variable controls how to generate file name from meta data, nice!
- emms-tag-editor-rename: this function perform file renaming according to above format
16.11.4 Smart Browser
emms-smart-browse
to enter the smart browsing page.
16.11.4.1 TODO when I start emacs, it can find all the music, how did it remember?
In browser, you can update by relist the browser
- emms-browse-by-artist (b 1)
- emms-browse-by-album
- emms-browse-by-genre
- emms-browse-by-year
Interact:
- emms-browser-add-tracks (RET)
- emms-browser-add-tracks-and-play (C-j)
- emms-browser-toggle-subitems (SPC): toggle subitems
- emms-browser-collapse-all (1)
- 2: expand one level
- 3: expand two levels
- 4: expand three levels
- emms-browser-clear-playlist (C): also clear the playlist, but use capital
- E: expand everything
- d: visit the current directory
- r: jump to a random track
- /: search
17 Mail
In this section, we discuss how to set up and use Email in Emacs.
17.1 Reading Mail
Some groups should be combined. The most obviously example is INBOX
and Sent, so that I can have a tree-view of the interactions of
email. To do that, in the group buffer, create a virtual group via G
V
, then edit it by C-e
. A edit buffer should pop out and the
content should be changed to something like this:
(nnvirtual "nnimap\\+cymail:INBOX\\|nnimap\\+cymail:.*/Sent Mail")
17.2 Composing Mail
message-mark-inserted-region
can be used to insert cut-here code
snippet in mail. The code will be shown in style when using Emacs as
email reader.
17.3 Sending Mail
I usually just use m
in gnus buffer to send mail. But you can also
use compose-mail (C-x m)
at any time, and this seems to use the same
set of configuration for sending mail. Fire message-send-and-exit
(C-c C-c)
to send it, C-c C-k
to kill it.
The easiest way to use multiple SMTP account is through msmtp
. The
configuration of msmtp
in $HOME/.msmtprc
with 600
access permission:
defaults tls_trust_file /etc/ssl/certs/ca-certificates.crt tls on auth on port 587 account XXX from [email protected] host smtp.gmail.com user [email protected] password XXXXXX account YYY from [email protected] host smtp.gmail.com user [email protected] password YYYYYY
17.4 Gnus Usage
Inside emacs, run gnus
command. This brings the *Group*
buffer. You will see the list of groups, use <spc>
or <enter>
to
enter the group. As usual, g
to refresh. q
for quit.
In general in all buffers, the important keybindings are: c
for
catch up current item, n
and p
for next or previous unread
articles N
and P
for actually next and previous article, m
for
create new message, a
for creating new post, r
for reply without
cite, R
for reply with cite, t
for toggle some mode.
17.4.1 Server buffer
From group buffer, type ^
to enter server buffer. Use <space>
(NOT
<enter>
!) to browse the groups of it, and subscribe via u
. To
unsubscribe, type u
again. Actually after unsubscribe, the group
still shows up in the group buffer, with U
mark. To really remove
it, use C-k
(gnus-group-kill-group
) on it in the group
buffer. Oh, just noticed this is just kill-line command, so you can
yank it back via C-y
(gnus-group-yank-group
). Likewise, kill a
region also works as expect.
17.4.2 Group Buffer:
Finding the groups
gnus-group-browse-foreign-server
(B
): usenntp
as back-end andnews.gmane.org
as address.gnus-group-list-active (A A)
: List all groups that are available from the server(s).gnus-group-unsubscribe-current-group (u)
: toggle subscription of the groupgnus-group-list-groups (l)
: list only subscribed ones with unread articlesgnus-group-list-all-groups (L)
: show all subscribed groupsgnus-group-make-rss-group (G R)
: paste the rss feed url to add RSS feedsgnus-group-jump-to-group (j)
: jump to a group by entering name, this works for non-listing groups.gnus-group-make-rss-group (G R)
: prompt to enter the RSS url. It is the link of the rss page of a blog, e.g. https://danluu.com/atom.xml
Management
gnus-group-catchup-current (c)
: mark all unread articles in the group under cursor as readgnus-group-catchup-current-all (C)
: mark allunreadarticles in the group under cursor as readgnus-group-mail (m)
: create a new messagegnus-group-post-news (a)
: create a new postgnus-group-enter-server-mode (^)
: enter server buffer
Since we like organizing, there's a topic mode, enabled by t
. After
that, you will have a bunch of command prefixed with T
. Topic mode
group subscriptions into categories.
gnus-topic-mode (t)
: toggle topic minor mode.gnus-topic-create-topic (T n)
: create a new topicgnus-topic-indent (<TAB>)
: indent current topicgnus-topic-unindent (M-<TAB>)
: unindentgnus-topic-delete (T <Del>)
: delete topic under cursor
You generally just kill (C-k) and yank (C-y) to organize the groups into specific topics. UPDATE: Don't use C-k C-y, it seems to cause bug, that cannot save the configuration. Use the following instead.
gnus-topic-move-group (T m)
: move the group under cursor to a topic
When topic mode is enabled, <enter> and <space> on a topic line will fold or unfold it. So you don't really need the following commands.
gnus-topic-hide-topic (T h)
:gnus-topic-show-topic (T s)
:
Groups can be combined into virtual groups. This is very helpful for
reading emails. For gmail, the inbox will not show my interactions,
that is in Sent Mail
. So on Group buffer, create a virtual group by
gnus-group-make-empty-virtual (G V)
and edit it via
gnus-group-edit-group-method (M-e)
with regular expression like
this:
(nnvirtual "nnimap\\+cymail:INBOX\\|nnimap\\+cymail:.*/Sent Mail")
17.4.3 Summary and Article buffer
This will list all the mails. <RET>
to enter a specific mail. The
following commands work in both buffers.
gnus-summary-next-unread-article (n)
: next unread articlegnus-summary-prev-unread-article (p)
: previous unread articlegnus-summary-next-article (N)
: next articlegnus-summary-prev-article (P)
: previous articlegnus-summary-next-page (<SPC>)
: scroll down, move to next unread article when at bottomgnus-summary-prev-page (<DEL> or <BACKSPACE>)
: scroll up, but will not move articlegnus-summary-expand-window (=)
: this expand the summary buffer, very handy (instead of switch to summary and C-x 1).
Replying
gnus-summary-followup-with-original (F)
: follow-up to group and cite the articlegnus-summary-followup (f)
: follow-up to group without citing the articlegnus-summary-reply-with-original (R)
: reply by mail and cite the articlegnus-summary-reply-with-original (r)
: reply by mail without cite the articlemessage-forward-show-mml (C-c C-f)
: forward to another persongnus-summary-mail-other-window (m)
: new mailgnus-summary-post-news (a)
: new post
Management
gnus-summary-catchup-and-exit (c)
: catchup ALL in the buffergnus-summary-toggle-header (t)
: toggle all headers (a lot of MIME information)gnus-summary-insert-old-articles (/ o)
: show all read articlesgnus-summary-rescore (V R)
: recompute the score. Score is computed by emacs rules. This can be explicitly set, or affected by some operations. For example, when you mark an article as read while didn't really read it, the related ones are marked like this.gnus-sticky-article (A S)
: normally the article and summary buffer is reused, that means you cannot put two mails side-by-side. This command make the current article buffer un-reusable for doing that.
Threading
gnus-summary-toggle-threads (T T)
: toggle threading (flat style or thread style)gnus-summary-refer-thread (A T)
: display the full threadgnus-summary-refer-parent-article (^)
: fetch parent articlegnus-summary-top-thread (T o)
: go to the top of this threadgnus-summary-kill-thread (T k)
: mark whole thread as read
Scores are computed for each article, for the sake of making important ones stand out.
gnus-summary-lower-score (L)
: create low scoregnus-summary-increase-score (I)
: create high score
Article will have marks to indicate the status of them. The followings are read marks:
r
: marked as read byd
commandR
: actually been readO
: stands for old, marked as read in previous sessionY
: having a too low scoreC
: marked as catchup
Other marks:
!
: tick, i.e. important, and will always show?
: dormant for now. This will show up whenever there are follow-ups.A
: this article has been replied or followed-up by me.gnus-replied-mark
, this variable has a default value of 65, the ASCII for "A".F
: this article has been forwarded*
: this article is stored in cacheS
: this article is saved#
: the process mark. This is similar tom
in dired: you select some articles, and process them at the same time, using some commands..
: gnus-unseen-mark, this article hasn't been seen before by the user. What does this mean??
The following commands interact with marks
gnus-summary-clear-mark-forward (M c)
: clear markgnus-summary-mark-as-read-forward (d)
: mark as read.gnus-summary-tick-article-forward (!)
: mark as important.gnus-summary-mark-as-dormant (?)
: mark as dormant.gnus-summary-set-bookmark (M b)
: set a bookmark in the current article. This seems to be a position inside a long article. Gnus will jump to this bookmark the next time it encounters the article.gnus-summary-remove-bookmark (M B)
: remove the bookmark from current article.gnus-summary-mark-as-processable (#)
: mark the current article the process markgnus-summary-unmark-as-processable (M-#)
: remove the process mark
17.4.4 Message buffer
This is pretty standard: C-c C-c
for send, C-c C-k
for kill. What
is not standard though is C-c C-d
for draft, C-c C-m f
to attach
file.
During editing a message, you can just save it normally, and it will
be in the draft group. The next time you enter draft, type D e
(gnus-draft-edit-message
) in draft summary buffer, you will resume
to editing. Rejected articles will also be in draft group.
There are some commands for jumping around the buffer, and edit the headers.
17.5 Scoring
To mark a score for an article:
- how:
I
for increase orL
for lower. - what:
a
for authors
for subject line
- match type:
e
exact matchf
fuzzy
- expiring
t
: temporaryp
: permanenti
: immediate, i.e. in effect right now, before even save the file
So what I want is actually I a f p
. The scoring file is stored by
default at ~/News/<group-name>.SCORE
.
18 Elisp
In emacs lisp intro, the Robert J. Chassell quoted the following.
I prefer to learn from reference manuals. I “dive into” each paragraph, and “come up for air” between paragraphs.
When I get to the end of a paragraph, I assume that that subject is done, finished, that I know everything I need (with the possible exception of the case when the next paragraph starts talking about it in more detail). I expect that a well written reference manual will not have a lot of redundancy, and that it will have excellent pointers to the (one) place where the information I want is.
18.1 IO
princ
is for human, it print object without quotes. print
is the
most verbose, print quotes and newlines. prin1
omit the newlines.
If you just evaluate the print, the result is the object being
printing, so the echo area will have two copy of the object.
message
accepts only string, and used inclusively on echo area.
18.2 Symbol
Since elisp is lisp-1, a symbol can be both variable and a function at the same time. Macros and functions use the same namespace.
Elisp use nil in three ways: the symbol, the logical false, and the empty list.
Elisp also has #'
, but instead of syntax, it is the read syntax of
quoting for function, i.e. function
.
Elisp by default uses dynamic binding and dynamic extent for local
variables. This means, the variable refers to the most recent local
binding, and a binding exists all the way as long as the binding form
is executing (e.g. body of let). setq
works on the most recent
binding.
Thus, when using a local dynamic binding, always make sure (by
yourself, unfortunately) the variable is bound. When really using
global variable, declare it at the top, via defvar
and
defconst
. defvar
will initialize the variable if it is originally
void, while defconst
will unconditionally initialize it. Other
than that, there's no difference, the compiler will not complain if
you changed the constant. The variable will be marked as "special",
meaning that it will always have dynamic binding. There's a third way
to create global binding, the defcustom
. It is used to create
customizable variable, also called user option. It is special in
that, it is shown in customize interface, and the defcustom
will
specify how it should be displayed, and what values to take.
On the other hand, lexical scope establish lexical binding, and has
indefinite extent. This means the variable has to refer to a binding
that is lexical written in scope. The binding is available even
outside the execution of the binding form, and construct a closure.
To enable lexical binding, you have to set buffer-local variable
lexical-binding
to non-nil. Even after this, special variables are
still dynamic binding.
Emacs supports another binding, called buffer-local binding. As name
suggests, the binding is in effect when that buffer is the current
buffer, and goes out of effect when it is not. This is most useful in
major modes. Two ways can make buffer-local
variable. make-local-variable
set the variable to local to current
buffer, while make-variable-buffer-local
set a variable buffer-local
in all buffers.
18.3 Regular Expression
You can use basic .*+?
, as well as non-greedy counter part *?
,
+?
, ??
.
Bracket is special in elisp regex. Character classes can be used
inside []
. E.g. [[:ascii:]]
. Possible values include
- ascii: 0-127
- alnum: letter or digit
- alpha: letter
- blank: space and tab
- digit: 0-9
- lower: lower case
- upper
- punct
- space: white space
- word: same as
\w
Parenthesis and braces are not special, thus can be used
literally. When using for grouping, they need to be escaped for
capturing, otherwise it is literal. Non-capturing group is also
supported by \(?:\)
. \1
for back reference.
Back slash some code has special meanings. e.g. \w
\b
. The
uppercase is negation.
\w
: word\b
:\s-
: whitespace\sw
: \w\s.
: punctuation
When constructing regexp that match string literals, you can use
regexp-quote
and regexp-opt
to avoid getting specially
interpreted. regexp-quote
returns a regular expression, whose only
exact match is string. regexp-opt
returns an efficient regular
expression, that will matches any of the strings supplied.
The mostly used functions are re-search-forward
and backward. It
search in the buffer. You can also search in a string by
string-match
or string-match-p
. They will set match data.
After search, you can retrieve the previous match data by
match-string
and match-string-no-property
(for clean string). You
can also use match-beginning
and match-end
to get the position of
the match instead of content.
Finally, replace-regexp-in-string
replaces all matches in a string.
18.4 Lisp Common Sense
eq
, equal
, =
are available.
Numeric function:
- comparison:
max
,min
,abs
- rounding:
truncate
,floor
,ceiling
,round
- arithmetic:
%
,mod
- bit-wise:
lsh
,ash
,logand
,logior
,logxor
,lognot
- math:
expt
,exp
,sin
,cos
,log
,sqrt
- random:
random
18.5 string
Creating string by make-string
. Most likely we are creating from
existing strings, e.g. substring
, concat
, split-string
. String
are compared using string=
, string<
(no string>
?). Converted by
number-to-string
, string-to-number
, and casing operations
downcase
, upcase
, capitalize
.
Of course, the most powerful string construction function is
formating, with foramt
, and format-message
. The format string
follows C style though, using %s
as printed representation
(princ
), %S
for prin1
, %c
for character,
18.6 list
List is defined as the last cdr to be nil
. If the last is not nil,
it is called dotted list instead of improper list.
- append: the interesting part is, all arguments except the last one
are copied. If you want to force copy the last one as well, add a
nil
as the last of append. - reverse
list generation:
- number-sequence: inclusive from a to b
Apart from car
and cdr
, elisp has car-safe
and cdr-safe
, that,
if the argument is not a cons cell, return nil. nth
, nthcdr
,
last
are available.
destructive means the cdr of the cons cells are modified.
pop
and push
is destructive. pop
will return the car of the
list. push
is the counter part for cons
onto the
list. add-to-list
only adds if the element is not there
already. There are also very bare-bone functions setcar
and
setcdr
. Note that sort
is also destructive.
List can be, of course, used as set. member
does predicate, remove
removes item from set, delete
destructively removes. They use
equal
, but have eq
counter parts obviously. Finally, delete-dups
remove duplication.
Association list is same as scheme, a list of pairs. assoc
can be
used to retrieve by car
, while rassoc
retrieve by cdr
.
Property list is a flat list. The odd elements are property name, and
the even elements are values. The property names must be unique.
The order of the "pairs" does not matter. plist-get
and plist-put
modify the list. plist-member
is useful because it can distinguish
the missing property and the property with value "nil"
A symbol can have a property list. It has a simpler syntax, get
and
put
with the symbol as argument. symbol-plist
can retrieve the
plist from symbol, setplist
gives a plist to a symbol.
18.7 Sequence
Sequence is more general than list, specifically it also covers array.
elt
is used to retrieve from sequence by position. copy-sequence
creates new sequence, but the elements are not copied.
Array is fixed length sequence, can be vector or string. make-vector
or vector
constructs vector, and aref
and aset
access it.
18.8 Hash Table
make-hash-table
constructs a table, and access by gethash
,
puthash
, remhash
, clrhash
. Hash table can be counted by
hash-table-count
instead of length
, iterated by maphash
instead
of map
.
18.9 Function
Functions are defined by following. To specify optional argument, use
&optional
before all optional arguments. Collect rest arguments by
putting &rest
before the final argument. A lambda expression
evaluates to a function object.
(defun name (var ...) body ...) (lambda (arg ...) body ...) (required-var ... [&optional op-var ...] [&rest rest-var])
apply
append the arguments into a list, and call the function with
the splice of list as arguments. The last argument must be a
list. funcall
just call with the rest arguments.
mapcar
is the typical map, return the list. mapc
is used for side
effect. mapconcat
is a shorthand for concatenate the result as a
string.
A function with (interactive)
is a command, i.e. it can be
executed with M-x. This apply to both defun and lambda. Although
interactive is often used without argument, it can actually do very
interesting staff. It basically defines what kind of arguments the
user should provide to the command. Most likely, it is a multi-line
string containing key code of what kind of values to expect, and
prompt string. The numeric prefix argument "p" is just one of them,
and it can differentiate C-u
prefix of the command.
18.10 Macro
defmacro name (args) body...
The macro is very simple: leave the arguments as is and put them into the macro body to form an expression. The expression is then evaluated for result.
18.11 Control Structure
Sequential structure has progn
, prog1
, prog2
.
if
, when
, unless
, not
, and
, or
are common.
cond
takes the following form
(cond (condition body ...) ...)
pcase
takes
(pcase exp (pat code ...) ...)
Loops takes follows. There's no mention what is the return of
while. dolist
does return the value of result, defaults to
nil. dotimes
bind var to [0,count)
.
(while condition forms ...) (dolist (var list [result]) body ...) (dotimes (var count [result]) body ...)
18.12 Packages
- org-drill: flashcard app, using spaced repetition algorithm
18.12.1 Dash.el
https://github.com/magnars/dash.el
This is a collection of list libraries.
-map
takes a function to map over the list, the anaphoric form with double dashes executed withit
exposed as the list item.;; normal version (-map (lambda (n) (* n n)) '(1 2 3 4)) ;; also works for defun, of course (defun square (n) (* n n)) (-map 'square '(1 2 3 4)) ;; anaphoric version (--map (* it it) '(1 2 3 4))
-update-at
:(-update-at N FUNC LIST)
Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.-flatten
:(-flatten L)
: Take a nested list L and return its contents as a single, flat list.
18.12.2 s.el
https://github.com/magnars/s.el
The string manipulation library
18.12.3 cl-lib.el loop
This package ports many common lisp facilities into elisp,
most importantly, the loop facility.
So this section, at least for now, focus on cl-loop
.
18.12.3.1 general loop form
(cl-loop clauses...)
The clauses can be:
- for clauses
- TODO
18.12.3.2 for clauses
for VAR from FROM to TO by STEP
FROM
defaults to 0.STEP
must be positive and default to 1.- inclusive
[from,to]
from
can beupfrom
anddownfrom
. I think it is wired to use this.to
can beupto
anddownto
. This makes more sense.above
andbelow
can be used, but exclusive. e.g.for var below 10
for VAR in LIST by FUNCTION
FUNCTION
is used to traverse the list, defaults tocdr
for VAR on LIST by FUNCTION
VAR
is bound to the cons cell of the list instead of the element.for VAR across ARRAY
- iterates all elements of array
for VAR = EXPR1 then EXPR2
- this is the most general form.
The
VAR
is bound toEXPR1
initially, and will be set by evaluatingEXPR2
in successive iterations.EXPR2
can refer the oldVAR
18.12.3.3 iteration clauses
repeat integer
- repeat the loop how many times
while condition
- stops the loop when the condition becomes nil
until condition
always condition
- like while except it returns
nil
, andfinally
clauses are not executed. never condition
- counter part for
always
18.12.3.4 accumulation clauses
collect form
- collect into a list and return the list in the end
append form
- collect the lists into a list by appending, and return it in the end
concat form
- for string only
count form
- count how many times form evaluates to non-nil.
sum form
- sum all the values
maximize form
- get the max. If the form is never executed, result is undefined
minimize form
18.12.3.5 Other clauses
with var = value
- set the value one-time at the beginning of the loop.
Often used as return variable.
The spaces around
=
is essential!. if condition clause [else clause]
when condition clause
- same as if
unless condition clause
- similar
initially [do] forms...
- execute before the loop begins, but after the
for
andwith
variable bindings.do
is optional. finally [do] forms...
- execute after the loop finishes
finally return form
- finally return it …
do forms...
- execute as an implicit
progn
in the body return form
- this is often used in
if
orunless
, because put it in top level will cause the loop always execute only once.
18.12.4 cl-lib other
Of course, cl-lib provides much more than just loops …
incf PLACE
- is
i++
18.13 Debugging
18.13.1 lisp debugger
The simplest debugger is called lisp debugger
.
You can turn on the debug-or-error
flag,
but I found inserting the (debug)
command useful.
Simply insert (debug)
where you want program to suspend, and run it.
You will enter the debugger at that point.
In the debugger buffer, the following commands are available:
c
- continue run program
d
- step
e
- evaluate an prompt expression
R
- like
e
, but also save the result in*Debugger-record*
q
- quit
v
- toggle display of local variables ???
18.13.2 Edebug
For this to work, first you need to instrument the code.
You can instrument the defun by C-u C-M-x
.
Actually this is adding a prefix before eval-defun
,
which instrument, and then evaluate the defun.
After instrumentation, running the defun will cause the program to stop at the first stop point of the function. The stop points are
- before and after each subexpression that is a list
- after each variable reference
18.13.2.1 breakpoints
b
- set a breakpoint
u
- unset a breakpoint
x CONDITION
- set a conditional breakpoint
You can also set the source breakpoints, by adding (edebug)
.
18.13.2.2 Moving of point
B
- move point to the next breakpoint
w
- move point back to the current stop point
18.13.2.3 executions
<SPC>
- run to next stop point
g
- execute until next breakpoint
q
- exit
S
- stop and wait for Edebug commands
n
- evaluate a sexp and stop at stop point
t
- trace, pause one second at each stop point …
T
- rapid trace. Update the display at each stop point but don't actually pause …
c
- pause one second at each breakpoint
C
- rapid continue.
G
- run and ignore breakpoints (but you can stop it by
S
) h
- proceed to the stop point near the point …
f
- run one expression
o
- step out the containing expression
i
- step in
18.13.2.4 evaluation
e EXP
- evaluate a prompt expression
C-x C-e
- evaluate an expression at point
18.13.2.5 other commands
?
- show help
r
- redisplay the most recent sexp result
d
- display the backtrace
18.14 Unit Testing
Use ert
for unit testing.
18.14.1 Write test
(ert-deftest addition-test() "Outline docstring." (should (= (+ 1 2) 4)))
The family of functions:
should
shoult-not
should-error
expected failure:
(ert-deftest addition-test() "Outline docstring." :expected-result :failed (should (= (+ 1 2) 4)))
skip test
(ert-deftest addition-test() "Outline docstring." (slip-unless (featurep 'dbusbind')) (should (= (+ 1 2) 4)))
18.14.2 Run test
M-x ert
will run it. The selector of test accept some more fancy staff like regular expression matching.
But in the case of scratch testing, I need to evaluate the deftest and then call ert
.
The nice thing is it supports interactive debugging. In the ert buffer, the following commands are available:
r
- re-run the test
.
- jump to the source code of this test
b
- show back-trace
m
- show the message this test printed
d
- re-run the test with debugger enabled
- instrumentation
- go to source code, type
C-u C-M-x
, and re-run the test. You are able to step!
Also, select test by this:
(ert-run-test (ert-get-test 'my-defined-test))
18.15 Some random code snippets
(cl-prettyprint (font-family-list)) ;; see all font family available on this system
18.15.0.1 Url retrieval
(with-current-buffer (url-retrieve-synchronously "http://scholar.google.com/scholar?q=segmented symbolic analysis") (goto-char (point-min)) (kill-ring-save (point-min) (point-max)) ) (let ((framed-url (match-string 1))) (with-current-buffer (url-retrieve-synchronously framed-url) (goto-char (point-min)) (when (re-search-forward "<frame src=\"\\(http[[:ascii:]]*?\\)\"") (match-string 1))))
18.16 Emacs Related
18.16.1 Buffer
with-temp-buffer
(with-temp-buffer &rest BODY)
Create a temporary buffer, and evaluate BODY there likeprogn
.(insert-file-contents FILENAME &optional VISIT BEG END REPLACE)
: Insert contents of file FILENAME after point.(secure-hash ALGORITHM OBJECT &optional START END BINARY)
: the object can be a buffer. This can be used to compare if a file has changed.(current-buffer)
: Return the current buffer as a Lisp object.(message FORMAT-STRING &rest ARGS)
: Display a message at the bottom of the screen.
There will be many buffers in an Emacs session, and the
current-buffer
returns the current one, which is the default target
for most commands. When you want to make something interesting to some
other buffer, you will need to set-buffer
to set that buffer
current. You will likely want to switch back to the original buffer
after those operations, for that, don't use set-buffer
to set back,
because it is not error-safe. Instead, use save-current-buffer
, or
better with-current-buffer
. with-temp-buffer
don't need a provided
buffer object, but creates a temporary one. The temporary buffer will
be killed at the end of execution of body. All of these 3 form does
not display the buffer, just make it current.
A buffer has a name, retrieved by buffer-name
. The name can be set
using rename-buffer
. Buffers can be obtained by name via
get-buffer
. Buffers are also likely to be associated with a file,
and the non-directory file name is buffer-file-name
. You can also
get the buffer using the file name via get-file-buffer
. Since it
just the filename, there must be multiple ones, and this function
returns the first.
To create a buffer, use get-buffer-create
, which returns the new
buffer, or an existing buffer. It does not make that buffer current.
Create a new unique buffer name by generate-new-buffer-name
. It is
not typically directly used though. The function generate-new-buffer
uses that function to generate new name (by post-fixing <N>), if the
provided name is in use.
Obtain all the live buffers using buffer-list
. The order of list
matters. The newly created buffer is added to the end of list, the
current displayed buffer moves to the front. When a buffer is buried,
it is moved to the end. other-buffer
returns the first in the list
that is not current one. last-buffer
returns the last (end) in the
list. bury-buffer
and unbury-buffer
moves a buffer to the end and
switch buffer to the last buffer respectively. A buffer is killed by
kill-buffer
, in which case it is removed from the list.
18.16.2 Position
A position is the index in a buffer. There of course will be a character before and one after the position. When we say "at position", we mean after position. Position in a buffer starts from 1, while position in a string starts from 0.
The point is the current cursor position. point
returns the current
point, point-min
and point-max
returns the beginning and end
point.
There are many commands to move point. goto-char
moves by position,
and all other commands build upon it. I'm omitting the opposite
version, e.g. forward v.s. backward, up v.s. down., beginning v.s. end
- moves by characters:
forward-char
- moves by word:
forward-word
- buffer:
beginning-of-buffer
moves topoint-min
- line:
beginning-of-line
andend-of-line
,forward-line
andbackward-line
- screen: you can also count the current vertical screen lines, and move the corresponding lines accordingly.
- balanced expression:
forward-list
,up-list
,forward-sexp
,end-of-defun
- skipping:
skip-chars-forward
skips over a list of chars represented by a pattern string. It is like regular expression, but is put implicitly inside brackets. Thus you can use for example"a-zA-Z"
.
It is useful to temporarily move to some position, do some tasks, and
move back. It is called execursion, and is done via
save-execursion
.
Narrowing works with two positions. narrow-to-region
does the
narrowing, and widen
undoes it. This creates the following effects:
- determine the accessible portion of the buffer, but don't alter the position of the actual buffer.
- The point cannot move outside the positions
- no texts outside are displayed
- most (?) functions refuse to operate on outside text
18.16.3 Faces
http://ergoemacs.org/emacs/elisp_define_face.html
You probably don't want to define a face from scratch. Try use the default ones:
- default
- bold
- italic
- bold-italic
- underline
- fixed-pitch
- variable-pitch
- shadow
- link
- link-visited
- highlight
- match
- isearch
- lazy-highlight
- error
- warning
- success
Or the ones defined in font-lock-mode:
- font-lock-builtin-face
- font-lock-comment-delimiter-face
- font-lock-comment-face
- font-lock-constant-face
- font-lock-doc-face
- font-lock-function-name-face
- font-lock-keyword-face
- font-lock-negation-char-face
- font-lock-preprocessor-face
- font-lock-regexp-grouping-backslash
- font-lock-regexp-grouping-construct
- font-lock-string-face
- font-lock-type-face
- font-lock-variable-name-face
- font-lock-warning-face
18.16.4 Marker
A marker has two component: the buffer it is in, and the position in
the buffer. They can be retrieved by marker-position
and
marker-buffer
.
The position is updated automatically when the text changes. The invariant is the surrounding two characters. The updating of marker position takes time, especially there are a lot of them. Thus, remove the marker if you know you won't use if any more.
You can make a marker by 4 functions, which differs only its initial
point. make-marker
, point-marker
, point-min-marker
,
point-max-marker
. You can also copy-markder
from existing one. A
marker can be moved by set-marker
.
There's one special marker, designated the mark, whose position is
returned by mark
. To return the actual marker, use mark-marker
,
but this is dangerous, try to avoid it. The mark is mainly used to
provide a default region for a command. The text between point and the
mark is called the region. The beginning and end of it can be
obtained by region-beginning
and region-end
. When using
(interactive)
to define a command, the "r"
code will give the
command two numeric values as the (point) and the mark, the smaller
first. This region is used for most region based command by
default.
Some command will set the mark, and when it does this, it will
typically save the old mark on the mark ring. set-mark
set the
position of the mark, but it is not commonly used, because it discard
the previous mark. Instead, push-mark
and pop-mark
handles the
mark ring automatically.
18.16.5 Process
Elisp can create async or sync processes. There are three primitives
to create subprocess: make-process
for async, call-process
and
call-process-region
for sync. All others are built upon them.
To get a list of current live async processes, use
list-processes
. This seems to be for display purpose, and
process-list
seems to return process objects. You can also get
process by its name via get-process
. Process information can be
retrieved by process-command
, process-id
, process-name
,
process-status
, process-live-p
, process-type
,
process-exit-status
.
You also want to communicate with the subprocess: either send input,
receive output, or send signals. To send string as input, use
process-send-string
, process-send-region
, process-send-eof
. To
send signals, use interrupt-process
, kill-process
, quit-process
,
stop-process
, continue-process
, or the general one
signal-process
.
The output of a subprocess is inserted into a associated buffer,
called the process buffer. This buffer serves two purposes: receive
the output, and kill the process by kill the buffer. process-buffer
returns the buffer with a particular process, and get-buffer-process
returns the process object associated with the buffer. The position to
insert is determined by the process mark, which is always set to the
end of the buffer. You can set process buffer by set-process-buffer
.
Network connection is also represented by a process object, but it is
not a child process, has no process id, cannot be killed or sent
signal. You can only send and receive data, or close the
connection. make-network-process
creates network connection. It
seems to be a primitive, able to create TCP, UDP, or a
server. Alternatively, open-network-stream
creates TCP specifically.
18.16.6 File System Related
18.16.6.1 Traversing
(directory-files DIRECTORY &optional FULL MATCH NOSORT)
Return a list of names of files in DIRECTORY.
Usage example:
(bib-files (directory-files bib-dir t ".*\.bib$"))
18.16.6.2 Predicates
directory-files
will throw error if the directory does not exist.
So a safe way is to check if the directory exists first.
This predicate does this:
(file-exists-p FILENAME)
Directory is also a file.
Other predicates includes:
file-readable-p file-executable-p file-writable-p file-accessible-directory-p
18.16.7 Other
(defalias SYMBOL DEFINITION &optional DOCSTRING)
: Set SYMBOL's function definition to DEFINITION. E.g.(defalias 'helm-bibtex-get-value 'bibtex-completion-get-value)
, serves as a temporary patch forhelm-bibtex
update its API tobibtex-completion
18.16.7.1 make-obsolete-variable
(make-obsolete-variable OBSOLETE-NAME CURRENT-NAME WHEN &optional ACCESS-TYPE)
Make the byte-compiler warn that OBSOLETE-NAME is obsolete.
helm-bibte
used it when it refactored the "helm" part off into a module,
to support different backend other than helm
.
As a result, most helm-bibtex-
prefixes are changed to bibtex-completion-
ones.
But they want the end user's configuration will not break,
and at the same time warn them to update to the new name.
Here's the code, and the last line is what actually uses the function.
The actual effect is the user's configuration will be marked as warning,
the mini-buffer will describe the obsolete detail.
(cl-loop for var in '("bibliography" "library-path" "pdf-open-function" "pdf-symbol" "format-citation-functions" "notes-path" "notes-template-multiple-files" "notes-template-one-file" "notes-key-pattern" "notes-extension" "notes-symbol" "fallback-options" "browser-function" "additional-search-fields" "no-export-fields" "cite-commands" "cite-default-command" "cite-prompt-for-optional-arguments" "cite-default-as-initial-input" "pdf-field") for oldvar = (intern (concat "helm-bibtex-" var)) for newvar = (intern (concat "bibtex-completion-" var)) do (defvaralias newvar oldvar) (make-obsolete-variable oldvar newvar "2016-03-20"))
19 Reference
Sacha's super long Emacs Config: http://pages.sachachua.com/.emacs.d/Sacha.html Some emacs.d I started with https://github.com/jordonbiondo/.emacs.d/blob/master/init.el C++ IDE and some tutorials: http://tuhdo.github.io/