The pages where I write about Emacs. It doesn’t happen very often. I think you’re probably best off following Planet Emacsen.
I saw Andrew Hyatt post on Google+:
I skimmed my
~/.emacs and looked at all the little settings I think would make better defaults… For the complete file, see my current config file for Emacs on Windows.
(show-paren-mode 1) (winner-mode 1) (windmove-default-keybindings) (column-number-mode 1) (savehist-mode 1) (iswitchb-mode 1) (global-set-key (kbd "C-x C-b") 'bs-show) (require 'dired-x) (setq dired-recursive-deletes 'top dired-recursive-copies 'top dired-dwim-target t) (setq sentence-end-double-space nil) (dolist (hook '(emacs-lisp-mode-hook lisp-mode-hook rcirc-mode change-log-mode texinfo-mode-hook)) (add-hook hook (lambda () (eldoc-mode 1) (set (make-local-variable 'sentence-end-double-space) t)))) (setq eshell-save-history-on-exit t) (setq cperl-hairy t cperl-electric-parens 'null) (add-hook 'cperl-mode-hook (lambda () (local-set-key (kbd "C-h f") 'cperl-perldoc))) (add-hook 'rcirc-mode-hook (lambda () (rcirc-track-minor-mode 1))) (defun describe-hash (variable &optional buffer) "Display the full documentation of VARIABLE (a symbol). Returns the documentation as a string, also. If VARIABLE has a buffer-local value in BUFFER (default to the current buffer), it is displayed along with the global value." (interactive (let ((v (variable-at-point)) (enable-recursive-minibuffers t) val) (setq val (completing-read (if (and (symbolp v) (hash-table-p (symbol-value v))) (format "Describe hash-map (default %s): " v) "Describe hash-map: ") obarray (lambda (atom) (and (boundp atom) (hash-table-p (symbol-value atom)))) t nil nil (if (hash-table-p v) (symbol-name v)))) (list (if (equal val "") v (intern val))))) (with-output-to-temp-buffer (help-buffer) (maphash (lambda (key value) (pp key) (princ " => ") (pp value) (terpri)) (symbol-value variable)))) (define-key isearch-mode-map (kbd "C-h") 'isearch-highlight-phrase) (put 'narrow-to-region 'disabled nil) (put 'not-modified 'disabled t) (put 'upcase-region 'disabled nil) (put 'downcase-region 'disabled nil)
Sometimes I wonder whether nicks on IRC give too much away. Sex, cultural background, … So here’s an experiment. Do you treat the people the same if you can’t see their nick names?
Google Reader was shut down. Luckily Google Takeout allowed you to download all of your data before the shut it down. I did that. I wanted to extract all the URLs to the articles I starred in order to post them on this blog… maybe.
Here’s how I did it. First, take a look at the file
(setq starred-items (with-current-buffer "starred.json (Google Reader-takeout.zip)" (goto-char (point-min)) (json-read))) (mapcar (lambda (item) (car item)) starred-items) ⇒ (items direction updated author title id)
I’m interested in
items, which happens to be an array. Let’s see what each item contains.
(mapcar (lambda (item) (car item)) (aref (cdr (assoc-string "items" starred-items)) 0)) ⇒ (origin annotations comments author content replies alternate updated published title categories id timestampUsec crawlTimeMsec)
As it happens, the URL I’m interested in is part of
alternate. Let’s make sure there’s always exactly one entry:
(mapc (lambda (item) (when (not (= 1 (length (cdr (assoc-string "alternate" item))))) (error "%S" item))) (cdr (assoc-string "items" starred-items)))
Phew! Let’s produce a first list of URLs and the respective titles:
(mapc (lambda (item) (let ((href (cdr (assoc-string "href" (aref (cdr (assoc-string "alternate" item)) 0)))) (title (cdr (assoc-string "title" item)))) (insert (format "* [%s %s]\n" href title)))) (cdr (assoc-string "items" starred-items)))
I hate feedproxy URLs and so I absolutely wanted to get rid of all the URLs starting with
http://feedproxy.google.com/. This required a bit more code since neither
url-retrieve do exactly what I want.
(defun redirection-target (url) (save-match-data (let ((url-request-method "HEAD") (retrieval-done nil) (spinner "-\|/") (n 0)) (url-retrieve url (lambda (status &rest ignore) (setq retrieval-done t url (plist-get status :redirect) url (replace-regexp-in-string "blogspot\\.ch" "blogspot.com" url) url (replace-regexp-in-string "\\?utm.*" "" url)))) (while (not retrieval-done) (sit-for 1) (message "Waiting... %c" (aref spinner (setq n (mod (1+ n) (length spinner)))))) url)))
Now I can run the following search an replace operation in the buffer where I generated my list:
(while (re-search-forward "http://feedproxy\\.google\\.com/\\S-+" nil t) (replace-match (redirection-target (match-string 0))))
Phew, thank you, Emacs!
This topic ties together two topics that probably don’t see too much overlap.
The problem: the party of characters my players run is huge. Even if there are usually only around ten characters that are part of a single session, there are more than thirty primary and secondary characters on the status page. Given the wiki table for the status page, how can I quickly add up the correct XP and gold values? Any XP gained is shared equally amongst the characters that took part in the session but any gold gained is distributed according to each characters share. Primary characters get a full share, secondary characters get a third of a share.
I used Emacs widget mode to create a page like this:
XP total: 805 Gold total: 7191 [X] Schalk [ ] Uluf [ ] Witschik [X] Schachtmann [ ] Sirius [X] Logard [X] Arnd [X] Tinaya [ ] Pyrula [ ] Pijo [ ] Garo [X] Zeta [ ] Pipo [X] Fusstritt [ ] Thor [ ] Jack [ ] Gloria [ ] Hermann [ ] Urs [ ] Alpha [ ] Beta [ ] Gamma [ ] Boden [ ] Basel [ ] Bern [X] Nuschka [ ] Moranor [ ] Axirios Hectaxius [Go!]
And here’s the code to do it:
(defconst fünf-winde-regexp "^\\(|\\[\\[\\(.*?\\)\\]\\][ \t]*|[ \t]*\\(1\\|1/3\\)[ \t]*\\)|\\([ \t]*[0-9]+[ \t]*\\)|\\([ \t]*[0-9]+[ \t]*\\)" "Regular expression to parse the Status page. \(let ((str (match-string 1)) (name (match-string 2)) (share (match-string 3)) (xp (match-string 4)) (gold (match-string 5))) ...\)") (defvar fünf-winde-buf nil "Source buffer.") (defvar fünf-winde-xp nil "XP share.") (defvar fünf-winde-gold nil "Gold share.") (defvar fünf-winde-party nil "Charakters in the party.") (defun fünf-winde-xp-and-gold () "Hand out Gold and XP." (interactive) (let ((buf (current-buffer)) (names)) (save-excursion (goto-char (point-min)) (while (re-search-forward fünf-winde-regexp nil t) (setq names (cons (match-string 2) names)))) (switch-to-buffer "*Fünf Winde*") (kill-all-local-variables) (set (make-local-variable 'fünf-winde-buf) buf) (make-local-variable 'fünf-winde-xp) (make-local-variable 'fünf-winde-gold) (make-local-variable 'fünf-winde-party) (let ((inhibit-read-only t)) (erase-buffer)) (remove-overlays) (setq fünf-winde-xp (widget-create 'integer :size 13 :format "XP total: %v\n" 0)) (setq fünf-winde-gold (widget-create 'integer :size 13 :format "Gold total: %v\n" 0)) (setq fünf-winde-party (apply 'widget-create 'checklist (mapcar (lambda (name) `(item ,name)) (nreverse names)))) (widget-insert "\n") (widget-create 'push-button :notify (lambda (&rest ignore) (fünf-winde-process fünf-winde-buf (widget-value fünf-winde-xp) (widget-value fünf-winde-gold) (widget-value fünf-winde-party))) "Go!") (widget-insert "\n") (use-local-map widget-keymap) (local-set-key (kbd "q") 'bury-buffer) (local-set-key (kbd "SPC") 'widget-button-press) (local-set-key (kbd "<left>") 'widget-backward) (local-set-key (kbd "<up>") 'widget-backward) (local-set-key (kbd "<right>") 'widget-forward) (local-set-key (kbd "<down>") 'widget-forward) (widget-setup) (goto-char (point-min)) (widget-forward 1))) (defun fünf-winde-process (buf total-xp total-gold party) (message "(fünf-winde-process (get-buffer \"%s\") %d %d '%S)" buf total-xp total-gold party) (switch-to-buffer buf) (save-excursion (let ((xp-shares 0) (xp-share nil) (gold-shares 0) (gold-share nil)) (goto-char (point-min)) (while (re-search-forward fünf-winde-regexp nil t) (let ((name (match-string 2)) (share (match-string 3))) (when (member name party) (setq gold-shares (+ gold-shares (cond ((string= share "1/2") 0.5) ((string= share "1/3") (/ 1.0 3)) (t (string-to-number share)))) xp-shares (1+ xp-shares))))) (setq gold-share (/ total-gold gold-shares) xp-share (/ total-xp xp-shares)) (goto-char (point-min)) (while (re-search-forward fünf-winde-regexp nil t) (let ((str (match-string 1)) (name (match-string 2)) (share (match-string 3)) (xp (match-string 4)) (gold (match-string 5))) (when (member name party) (setq gold (format (concat "%9d") (+ (string-to-number gold) (* gold-share (cond ((string= share "1/2") 0.5) ((string= share "1/3") (/ 1.0 3)) (t (string-to-number share)))))) xp (format (concat "%9d") (+ (string-to-number xp) xp-share))) (replace-match (concat str "|" xp "|" gold))))))))
I’m not sure I’m spending my time wisely, but there you go. I used to have a simpler piece of code that helped me distribute XP and gold separately. The drawback was that it would ask me for every person in the table “was this character in the party? (y/n)” and that’s a lot of yes and no replies if you go through the list twice.
It’s also a stark reminder that simpler old rules doesn’t automatically mean less work for the referee. With D&D 3.5, I had a spreadsheet to compute the XP gained based on challenge rating and character level. It wasn’t something to do quickly without a book in front of me. Now the complexity of the task has been reduced, but the number of characters has exploded to compensate!
I finally installed the new theme for Emacs Wiki. Feel free to leave comments on the Talk page. Bootstrap allows me to make all the changes at run-time, ie. add a few scripts including a script that changes the wiki’s HTML (emacs-bootstrap.js) and a new CSS file (bootstrap.css).
Since no changes to the script are necessary I can continue to provide the old theme for those that don’t feel like switching.
In the anonymous rant The Wikemacs Experiment: 300 Days Later, the author claims “The biggest problem is that it is insecure. […] Anyone can edit any of the pages that contain Elisp code.” The same sentiment was expressed by Alex Bennée in a comment on Google+: “What is really needed is a way to be sure that the source for the emacs extension your updating hasn’t been subverted by someone else with ill intent.”
Experiences and ideas of “what is really necessary” vary. As for myself, I’ve installed code from all over the Internet without reviewing the source. Installing it from a gist or git repo is hardly a different experience. If you want to figure out whether a source is trustworthy, you do the usual things: do people link to the code, how long has it been around, what about recent checkins, that sort of thing. Or you get into the crypto business of signing releases.
You could of course say that every day that passes without a problem increases our false sense of security… I have no answer to that. All I can say is that if security is your problem, using gists and github is not the solution (as you say yourself). The source of the insecurity is our habits, our culture of downloading and installing anything and everything. I’m not sure how you’ll ever make sure “that the source for the emacs extension your updating hasn’t been subverted by someone else with ill intent.” That seems pretty impossible to me unless you limit yourself to the core Emacs distribution (and even that’s not a guarantee).
People on the #emacs channel keep asking “is there way to do X” and thus my impression is that finding stuff is a more pressing problem. I feel that encouraging people to create a page on the wiki saying “here is code to help you do something” is the solution to that problem.
But then again, I guess we all differ in what we consider to be the most pressing problem.
Alex Bennée the correctly points out that using “a user locked solution like a gist or git repo you can at least be assured what you’re installing has come through one person who you’ve trusted to a degree before.” I guess that’s true. We’ll see whether people start switching over to using gists instead of editing wiki pages. I said in an earlier comment:
I added gist support […] because it was easy to do, not because it will encourage existing authors to move their elisp code on wiki pages to github. If at all, it might encourage future elisp authors to transclude a gist… But then again, there’s nothing preventing them from linking to a gist right now. Perhaps it’s also a generational thing. People that have been living without github and gists don’t feel a particular need to start using it.
I just read a rant about Emacs Wiki and it’s alternative: The Wikemacs Experiment: 300 Days Later. Check out How Emacs Wiki Works for some context from my point of view. Anyway, the anonymous author says: “Maybe someone could work with Alex to add gist-style code snippets to Oddmuse, and make it so that code can be cited inline on Wiki pages, so that anyone visiting the page is automatically looking at the most up to date version of the code.”
(setq abg-elisp-external-dir (expand-file-name "external" abg-elisp-dir)) ; ... ; Add external projects to load path (dolist (project (directory-files abg-elisp-external-dir t "\\w+")) (when (file-directory-p project) (add-to-list 'load-path project)))
Actually, I added an Emacs Wiki feature using two lines of code that add support for fancy inclusion:
<include gist "https://gist.github.com/1236665">
It only works over there, however. See EmacsWiki:Gists.
Anyway, the same also works for Lisppaste:
<include text "http://paste.lisp.org/display/134703/raw">
;; Set XTERM resources as so ;; ;; metaSendsEscape: false ;; altSendsEscape: false ;; eightBitInput: true ;; Verify with cat > /dev/null command that pressing alt-a ;; alt-b and so on produces single >128bit char (will look ;; like a with a hat ;; once above is working in emacs do ;; Prevent pressing esc O from triggering binding (define-key (get-input-decode-map) "\eO" nil) ;; tell emacs Meta is 8th bit (cond ((fboundp 'set-input-meta-mode) (set-input-meta-mode t)) (t (set-input-mode t nil t)))
I don’t think there’s a nice way to include the colored version, unfortunately.
Update: I added support and minimal Lisp highlighting for the following:
<include lisppaste "http://paste.lisp.org/display/134703">
It only works over there, of course.
I was looking at tabular data on a wiki page:
|[[...]] | 1 | 6563| 3796| |[[...]] | — | |[[...]] | 1/3 | 2315| 1259| |[[...]] | — | |[[...]] | 1/3 | 159| 607| |[[...]] | — | |[[...]] | 1/3 | 159| 597| |[[...]] | — |
I wanted to add 56 to some of the values in the third column.
Emacs to the rescue:
M-C-% to run
query-replace-regexp and search for
^\(|[^|]*|[^|]*|[^|0-9]*\)\([0-9]+\) and replace it with
\1\,(+ (string-to-number \2) 56)) – I was surprised at how easy it was once I had remembered to use
\, in the replacement pattern.
Update: EmacsWiki:PierreGaston tells me that I could have used
\#2 instead of
(string-to-number \2). I guess I should have finished reading that paragraph on the Info page.
I’m using Emacs on Mac OSX.
Apparently the correct solution for using
man and all the related tools is to make sure your
/etc/man.conf file is correct. Mine was missing the following line:
You can ignore the rest of this page.
Thank you, Phil Hudson.
In my /.bashrc:
# MANPATH # there's no MANPATH by default, and manpath(1) just prints /usr/share/man if [ -z "$MANPATH" ]; then export MANPATH=/opt/local/man:/usr/local/man:/usr/local/share/man:/usr/X11R6/man:/usr/share/man fi
In my /.emacs:
;; man (unless (getenv "MANPATH") (setenv "MANPATH" (with-temp-buffer (insert-file-contents-literally "~/.bashrc") (when (re-search-forward "MANPATH=\\(.*\\)" nil t) (match-string 1)))))
And finally my little rebinding of
C-h f for Perl mode works for modules as well:
(add-hook 'cperl-mode-hook (lambda () (local-set-key (kbd "C-h f") 'cperl-perldoc)))
perldoc which in turn calls
which uses .
(TL;DR: People that don’t like the wiki as it is ought look at the official Emacs documentation instead. I wrote this so that I’d have something to link to in the future. This post was inspired by EmacsWiki:2012-03-20.)
Every year or so, I read about suggested changes to the Emacs Wiki. The complaints are the same, year after year.
The solutions invariably have nothing to do with the problem.
Why are these suggestions not helpful?
The first problem is the mistaken belief that technology can substitute for social change. Yes, the wiki is badly organized and many of the pages are outdated. Changing the wiki engine, the backend or the formatting rules will not change this, however.
The backend used by the wiki engine can influence performance and resource use, it can the software harder or easier to maintain and backup – but it will not induce somebody to edit a messy page and fix it.
The second problem is the mistaken belief that moderation can be commanded. You can complain about bad editing and a lack of moderation all day. But since nobody is paying people to do a boring job, we must rely on obsessive compulsive people to fix typos and tag pages.
Maybe we could attract more people by gamifying the experience—offer rewards, badges, scores. But Stack Overflow already does this. It’s the best social question answering machine currently known. The wiki doesn’t need to imitate something better. The wiki needs to do what it does best. We’ll come to that.
The third problem is the mistaken belief that quality control and volunteers go well together. Just compare Wikipedia and Citizendium and consider the animosity generated by Deletionism on Wikipedia. How will you encourage authors to contribute if you are telling them that their contributions are lacking the quality you are looking for instead of simply accepting their text and working on it?
You fight spam, you rework text occasionally, you encourage others, you welcome newbies, you lead by example. That’s how you lead.
An abrasive personality, radical change involving a lot of work—those are not the tools you are looking for.
Let me return to the issue of commanding change. Things people have said:
The critics can be unhappy about it all they want, and they can complain about it all they want—but in the end, one needs to understand the forces at work, here. There is no chain of command.
It works just like a free software project. If it doesn’t scratch someone’s itch, nobody is going to add it. I think it’s a fundamental issue with our business model: there is no pay for boring stuff. Plus, documentation is of no direct use for anything—unlike code. Thus, people are mostly motivated to keep their own code and its documentation up to date. I don’t think there is anything we can do about that. That’s why the Emacs Wiki Mission Statement does not mention organization and quality. It cannot be commanded.
Once we accept that this is the sand upon which we are building our house, we necessarily need to scale down our expectations. Personally, I think the wiki exists somewhere between the official documentation, Stack Overflow, the FAQ, the newsgroups, the mailing lists, and IRC. It’s certainly nowhere near the quality of organization and writing that the Emacs documentation has—and I don’t think this is the right medium to aim for this level of quality. I think the people willing to invest that amount of energy to write quality stuff ought to be writing the real Emacs documentation—and they probably are.
What remains are the people using Emacs Wiki for their own pet projects, questions asked, answers given, sometimes organized, sometimes rewritten, sometimes linked to the rest of the site.
Wikipedia works because of its universal appeal. When I added an image to an obscure Indian temple we visited when I was staying in Mysore, the photo was terrible. But it was a start, and enough people cared about the page and it grew, and it found people to tend it, and now it’s big and beautiful.
There just aren’t enough Emacs users and authors out there and the best of us will be contributing to the official Emacs documentation. The wiki exists somewhere between the official documentation and the mailing lists. Lower your expectations.
Given all that, why does the wiki exist at all?
When I started it, I had several reasons:
I think this last point bears consideration: I was creating pages or adding information to pages because it was pertinent on IRC. An index, linking to the page, categorization, returning to the page later and reworking it, all these quality related tasks were not pertinent on IRC. All I needed was a pastebin that I could go back to and rewrite if I felt like it. Often I did not—and I still don’t.
The wiki being on the web, updated every now and then, with pertinent answers to specialized questions, unorganized and raw, ended up being a good resource for the search engines out there. These search engines bring new people to the site. People that don’t understand how wikis work in general and how this wiki grew to be where it is in particular. They are shocked. So many pages outdated! Such a mess in style and quality!
I think those people are better served reading the official documentation. They don’t want this mess, they don’t benefit from it’s loose rules, they don’t understand how cool it is to have a site with no login required. They are better served elsewhere.
I’m sure that one day the Emacs Wiki will have become irrelevant. But just like the old newsgroups never disappeared entirely, so will the wiki transform into something else and remain part of our information landscape.
Perhaps one of the Emacs Wiki critics will one day set up an alternate site, pull all the pages (more than 8500 pages last time I checked), extract the quality content—or rewrite it from scratch—and produce something better. Perhaps they will build an organization that can keep the quality up, encourage new authors to join, provide more value to their readers. But I don’t think complaining about the existing Emacs Wiki is a step in the right direction. Build it, and they will come—elsewhere.
Define external redirect: LaunchPad