The pages where I write about Emacs. It doesn’t happen very often. I think you’re probably best off following Planet Emacsen.
I have a ton of files I downloaded to my tablet and I have a ton of files on my external harddisk. How can I ever clean it all up? With Emacs, I have dired, but no easy way to figure out which files have changed – specially if the files are not all in the same directory structure. Based on EmacsWiki:JoeBloggs’
dired-dups.el I wrote a new version that did what I wanted it to do.
Now that I think about it, I guess my code does the exact opposite: it find differences, not duplicates. I should change those names…
(As it turns out, there are still bugs in the code. Ouch.)
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 .