Update.
[elisp.git] / emacs.el
1 ;; -*- mode: Emacs-Lisp; mode: rainbow; -*-
2
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;; This program is free software; you can redistribute it and/or         ;;
5 ;; modify it under the terms of the GNU General Public License as        ;;
6 ;; published by the Free Software Foundation; either version 3, or (at   ;;
7 ;; your option) any later version.                                       ;;
8 ;;                                                                       ;;
9 ;; This program is distributed in the hope that it will be useful, but   ;;
10 ;; WITHOUT ANY WARRANTY; without even the implied warranty of            ;;
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      ;;
12 ;; General Public License for more details.                              ;;
13 ;;                                                                       ;;
14 ;; You should have received a copy of the GNU General Public License     ;;
15 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.  ;;
16 ;;                                                                       ;;
17 ;; Written by and Copyright (C) Francois Fleuret                         ;;
18 ;; Contact <francois@fleuret.org> for comments & bug reports             ;;
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
21 ;; It's better to set the preferences in the .Xresources so that the
22 ;; window is not first displayed with the wrong options
23
24 ;; Emacs.menuBar:            off
25 ;; Emacs.verticalScrollBars: off
26 ;; Emacs.toolBar:            off
27 ;; Emacs.internalBorder:     1
28 ;; Emacs.FontBackend: xft
29 ;; Xft.dpi: 96
30 ;; Xft.hinting: true
31 ;; Xft.antialias: true
32 ;; Xft.rgba: rgb
33
34 (set-default-font "Inconsolata 15")
35
36 ;; (set-default-font "Bitstream vera sans mono-12")
37 ;; (set-default-font "Liberation Mono-13")
38 ;; (set-default-font "DejaVu sans mono 15")
39 ;; (set-default-font "Droid sans mono 13")
40 ;; (set-default-font "Opensans 10")
41
42 (when (fboundp 'horizontal-scroll-bar-mode)
43   (horizontal-scroll-bar-mode -1))
44
45 ;; This is where I put most of my emacs-related files
46 (setq ff/emacs-dir "~/private/emacs")
47 (unless (file-exists-p ff/emacs-dir)
48   (mkdir ff/emacs-dir t))
49
50 ;; Give the focus to the emacs window if we are under a windowing
51 ;; system
52
53 (when window-system
54   ;; (x-focus-frame nil)
55   (set-mouse-pixel-position (selected-frame) 4 4))
56
57 ;; Where I keep my own scripts
58
59 (add-to-list 'load-path "~/sources/gpl/elisp")
60 (add-to-list 'load-path "~/sources/elisp")
61 (add-to-list 'load-path "~/local/elisp")
62
63 ;; No, I do not like menus
64 (menu-bar-mode -1)
65
66 ;; Nor fringes
67 ;; (when (functionp 'fringe-mode) (fringe-mode '(0 . 0)))
68 ;; (when (functionp 'fringe-mode) (fringe-mode '(0 . 1)))
69 (when (functionp 'fringe-mode) (fringe-mode 10))
70
71 ;; And I do not like scrollbar neither
72 (when (functionp 'scroll-bar-mode) (scroll-bar-mode -1))
73
74 ;; Make all "yes or no" prompts be "y or n" instead
75 (fset 'yes-or-no-p 'y-or-n-p)
76
77 ;; The space bar acting as "yes" has been several times really
78 ;; problematic.
79 (define-key query-replace-map (kbd "SPC") nil)
80
81 ;; Show the matching parenthesis and do it immediately, we are in a
82 ;; hurry
83 (setq show-paren-delay 0)
84 (show-paren-mode t)
85
86 ;; use colorization for all modes
87 (global-font-lock-mode t)
88
89 (setq font-lock-maximum-decoration 3
90       ;;'((latex-mode . 2) (t . 2))
91       )
92
93 ;; Activate the dynamic completion of buffer names
94 ;; (iswitchb-mode 1)
95 ;; (load "lcomplete")
96
97 ;; Save the minibuffer history
98 (setq savehist-file (concat ff/emacs-dir "/savehist"))
99 (when (functionp 'savehist-mode) (savehist-mode 1))
100
101 ;; And allow minibuffer recursion
102 (setq enable-recursive-minibuffers t)
103 (minibuffer-depth-indicate-mode 1)
104
105 ;; I do not like tooltips
106 (when (functionp 'tooltip-mode) (tooltip-mode nil))
107
108 ;; Activate the dynamic completion in the mini-buffer
109 (icomplete-mode 1)
110
111 ;; (setq highlight-current-line-globally t
112 ;; highlight-current-line-ignore-regexp "Faces\\|Colors\\| \\*Mini\\|\\*media\\|INBOX")
113
114 ;; (highlight-current-line-minor-mode 1)
115 ;; (highlight-current-line-set-bg-color "gray75")
116
117 (defun ff/compile-when-needed (name)
118   "Compiles the given file only if needed. Adds .el if required, and
119 uses `load-path' to find it."
120   (if (not (string-match "\.el$" name))
121       (ff/compile-when-needed (concat name ".el"))
122     (mapc (lambda (dir)
123             (let* ((src (concat dir "/" name)))
124               (when (file-newer-than-file-p src (concat src "c"))
125                 (if (let ((byte-compile-verbose nil))
126                       (condition-case nil
127                           (byte-compile-file src)
128                         (error nil)))
129                     (message (format "Compiled %s" src ))
130                   (message (format "Failed compilation of %s" src))))))
131           load-path)))
132
133 ;; This is useful when using the same .emacs in many places
134
135 (defun ff/load-or-alert (name &optional compile-when-needed)
136   "Tries to load the specified file and insert a warning message in a
137 load-warning buffer in case of failure."
138
139   (when compile-when-needed (ff/compile-when-needed name))
140
141   (if (load name t nil) t
142     (let ((buf (get-buffer-create "*loading warnings*")))
143       (display-buffer buf)
144       (set-buffer buf)
145       (insert (propertize "Warning:" 'face 'font-lock-warning-face) " could not load '" name "'\n")
146       (fit-window-to-buffer (get-buffer-window buf))
147       (set-buffer-modified-p nil))
148     nil))
149
150 ;; This is the default in emacs 22.1 and later
151 ;; (auto-compression-mode 1)
152
153 ;; make emacs use the clipboard so that copy/paste works for other
154 ;; x-programs. I have no clue how all that clipboard thing works.
155
156 ;; (setq x-select-enable-clipboard t)
157 ;; (setq interprogram-paste-function 'x-cut-buffer-or-selection-value)
158 ;; (setq x-select-enable-primary t)
159 ;; (setq x-select-enable-clipboard t)
160 ;; (global-set-key "\C-y" 'clipboard-yank)
161
162 (setq
163
164  message-log-max 1000
165
166  ;; avoid GC as much as possible
167  gc-cons-threshold 2500000
168
169  ;; no startup message
170  inhibit-startup-screen t
171
172  ;; no message in the scratch buffer
173  initial-scratch-message nil
174
175  ;; do not fill my buffers, you fool
176  next-line-add-newlines nil
177
178  ;; keep the window focused on the messages during compilation
179  compilation-scroll-output t
180
181  ;; Keep the highlight on the compilation error
182  next-error-highlight t
183
184  ;; blink the screen instead of beeping
185  ;; visible-bell t
186
187  ;; take the CR when killing a line
188  kill-whole-line t
189
190  ;; I prefer to move between lines as defined in the buffer, not
191  ;; visually
192  line-move-visual nil
193
194  ;; I comment empty lines, too (does not seem to work, though)
195  comment-empty-lines t
196
197  ;; We want long lines to be truncated instead of displayed on several lines
198  ;; truncate-lines t
199  ;; Show all lines, even if the window is not as large as the frame
200  ;; truncate-partial-width-windows nil
201  ;; truncate-partial-width-windows t
202
203  ;; Do not keep tracks of the autosaved files
204  auto-save-list-file-prefix nil
205
206  ;; Show me empty lines at the end of the buffer
207  default-indicate-empty-lines t
208
209  ;; Show me the region until I do something on it
210  transient-mark-mode t
211
212  ;; Do not color stuff which are clickable when hovering over it
213  mouse-highlight nil
214
215  ;; Don't bother me with questions even if "unsafe" local variables
216  ;; are set
217  enable-local-variables :all
218
219  ;; I have no problem with small windows
220  window-min-height 1
221
222  ;; I am not a fan of develock
223  develock-auto-enable nil
224
225  ;; I do not like women to open windows
226  woman-use-own-frame nil
227
228  ;; I am not that paranoid, contrary to what you think
229  epa-file-cache-passphrase-for-symmetric-encryption t
230  ;; And I like ascii files
231  epa-armor t
232
233  ;; tramp-default-method "ssh"
234  tramp-default-method "scp"
235
236  ;; I have no problem with files having their own local variables
237  enable-local-eval t
238
239  mail-from-style 'angles
240  browse-url-mozilla-program "firefox"
241  mc-encrypt-for-me t
242  mc-use-default-recipients t
243
244  ;; browse-url-new-window-flag t
245
246  ;; I do not like compilation to automatically split the active window
247  ;; vertically, even when the said window is very wide
248  split-height-threshold 0
249  split-width-threshold nil
250
251  )
252
253 ;; The backups
254
255 (setq
256  temporary-file-directory "/tmp/"
257  vc-make-backup-files t
258  backup-directory-alist '((".*" . "~/misc/emacs.backups/"))
259  version-control t ;; Use backup files with numbers
260  kept-new-versions 10
261  kept-old-versions 2
262  delete-old-versions t
263  backup-by-copying-when-linked t
264  )
265
266 (setq tramp-backup-directory-alist backup-directory-alist)
267
268 (setq user-emacs-directory "~/misc/emacs.d/")
269
270 (setq
271  abbrev-file-name (concat user-emacs-directory "abbrev_defs")
272  server-auth-dir (concat user-emacs-directory "server/")
273  custom-theme-directory user-emacs-directory
274  )
275
276 ;; Stop this crazy blinking cursor
277 (blink-cursor-mode 0)
278
279 ;; (setq blink-cursor-delay 0.05
280 ;; blink-cursor-blinks 0
281 ;; blink-cursor-interval 0.25)
282
283 ;; (set-terminal-coding-system 'utf-8)
284
285 ;; (unless window-system
286 ;; (xterm-mouse-mode 1)
287 ;;   (if (string= (getenv "TERM") "xterm-256color")
288 ;;       (ff/load-or-alert "xterm-256color" t))
289 ;; )
290
291 (setq-default
292
293  ;; Show white spaces at the end of lines
294  show-trailing-whitespace t
295
296  ;; Do not show the cursor in non-active window
297  cursor-in-non-selected-windows nil
298
299  use-dialog-box nil
300  use-file-dialog nil
301
302  ;; when on a TAB, the cursor has the TAB length
303  x-stretch-cursor t
304
305  ;; This is the default coding system when toggle-input-method is
306  ;; invoked (C-\)
307  default-input-method "latin-1-prefix"
308
309  ;; do not put tabs when indenting
310  indent-tabs-mode nil
311  ;; Stop indenting automatically, that's annoying
312  electric-indent-chars nil
313
314  ;; And yes, we have a fast display / connection / whatever
315  baud-rate 524288
316  ;; baud-rate 10
317
318  ;; To keep the cursor always visible when it moves (thanks
319  ;; snogglethrop!)
320  redisplay-dont-pause t
321
322  ;; I want to see the keys I type instantaneously
323  echo-keystrokes 0.1
324  )
325
326 ;; Show the column number
327 (column-number-mode 1)
328
329 ;; What modes for what file extentions
330 (add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
331
332 (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
333
334 (require 'org-table)
335
336 (add-to-list 'auto-mode-alist '("\\.txt\\'" . (lambda()
337                                                 (text-mode)
338                                                 (orgtbl-mode)
339                                                 ;; (auto-fill-mode)
340                                                 (flyspell-mode))))
341
342 (add-hook 'c++-mode-hook 'flyspell-prog-mode)
343 (add-hook 'log-edit-mode-hook 'flyspell-mode)
344
345 ;; I am a power-user
346
347 (put 'narrow-to-region 'disabled nil)
348 (put 'upcase-region 'disabled nil)
349 (put 'downcase-region 'disabled nil)
350 ;; (put 'scroll-left 'disabled nil)
351 ;; (put 'scroll-right 'disabled nil)
352
353 ;; My selector is clearer than that
354 ;; (when (load "ido" t) (ido-mode t))
355
356 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
357
358 ;; Makes buffer names more explicit then <2>, <3> etc. when there are
359 ;; several identical filenames
360
361 (when (load "uniquify" t)
362   (setq uniquify-buffer-name-style 'post-forward-angle-brackets))
363
364 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365 ;; Appearance
366 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
367
368 (when (boundp 'x-display-name)
369
370   (setq-default
371
372    ;; If the display is :0.0, we make the assumption that we are
373    ;; running the emacs locally, and we do not show the
374    ;; hostname. Otherwise, show @host.
375
376    frame-title-format (concat "emacs" ;;invocation-name
377                               (unless (string= x-display-name ":0.0")
378                                 (concat "@" system-name))
379                               " (%b)")
380
381    ;; Use the same for the icone
382
383    icon-title-format frame-title-format
384    ))
385
386 ;; "tool" bar? Are you kidding?
387 (when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
388
389 ;; My funky setting of face colors. Basically, we switch to a sober
390 ;; look and darken a bit the colors which need to (because of the
391 ;; darker background)
392
393 (defun ff/configure-faces (fl)
394   "Set face attributes and create faces when necessary"
395   (mapc (lambda (f)
396           (unless (boundp (car f)) (make-empty-face (car f)))
397           (eval `(set-face-attribute (car f) nil ,@(cdr f))))
398         fl))
399
400 ;; Not the same in xterm (which is gray in my case) and in
401 ;; X-window
402
403 (when window-system
404
405   (ff/configure-faces
406    '(
407      ;; (escape-glyph :foreground "#c0c0c0" :weight 'bold)
408      (escape-glyph :foreground "green3" :weight 'bold)
409      (default :background "gray90" :foreground "black")
410      (cperl-array-face :background "gray90" :foreground "blue" :weight 'bold)
411      (cperl-hash-face :background "gray90" :foreground "purple" :weight 'bold)
412      (message-cited-text :foreground "red4")
413      (diff-mode :background "gray90" :weight 'bold)
414      (diff-added :background "gray90" :foreground "green4" :weight 'bold)
415      (diff-removed :background "gray90" :foreground "red2" :weight 'bold)
416      (diff-changed :background "gray90" :foreground "blue" :weight 'bold)
417      (diff-file-header :background "white" :foreground "black"
418                        :weight 'bold)
419      (diff-header :background "white" :foreground "black")
420      (diff-hunk-header :background "white" :foreground "black")
421      (font-lock-builtin-face :foreground "deeppink3")
422      (font-lock-string-face :foreground "dark olive green")
423      (font-lock-variable-name-face :foreground "sienna")
424      ;; (font-lock-function-name-face :foreground "blue" :weight 'bold)
425      (font-lock-function-name-face :foreground "blue")
426      ;; (font-lock-comment-delimiter-face :foreground "dark violet")
427      ;; (font-lock-comment-face :foreground "dark violet")
428      (flyspell-incorrect :background "#ff0000" :foreground "black")
429      (flyspell-duplicate :background "#ff9000" :foreground "black")
430      (hl-line :background "white")
431      (sh-heredoc :foreground "black" :background "#fff0f0")
432      (sh-heredoc-face :foreground "black" :background "#fff0f0")
433      (header-line :background "gray65")
434      (highlight :background "turquoise")
435      (message-cited-text-face :foreground "firebrick")
436      (isearch :background "yellow" :foreground "black")
437      (isearch-lazy-highlight-face' :background "yellow3" :foreground "black")
438      (region :background "#b8b8e0" :foreground "black")
439      ;; (region :background "plum" :foreground "black")
440      (show-paren-match-face :background "gold" :foreground "black")
441      (show-paren-mismatch-face :background "red" :foreground "black")
442      (trailing-whitespace :background "gray65")
443      (cursor :inverse-video t)
444      (enotes/list-title-face :foreground "blue" :weight 'bold)
445      (mode-line :background "#b0b0ff" :foreground "black" :box nil
446                 :inverse-video nil)
447      (header-line :background "cornflowerblue" :foreground "black" :box nil
448                   :inverse-video nil)
449      (mode-line-inactive :background "gray80" :foreground "black" :box nil
450                          :inverse-video nil)
451      ;; (fringe :background "black" :foreground "gray90")
452      (fringe :background "gray80")
453      (ff/date-info-face :foreground "white")
454      (ff/battery-info-face :foreground "black")
455      ;; (ff/mail-alarm-face :foreground "white" :background "red2")
456      ;; (alarm-vc-face :foreground "black" :background "yellow" :weight 'normal)
457      (gui-button-face :background "green" :foreground "black")
458      ))
459   )
460
461 (unless window-system
462   ;; (xterm-mouse-mode 1)
463   (ff/configure-faces
464    '((italic :underline nil)
465      (info-title-2 :foreground "green")
466      (font-lock-comment-delimiter-face :foreground "green")
467      (font-lock-comment-face :foreground "green")
468      (cperl-array-face :background "gray90" :foreground "blue" :weight 'bold)
469      (cperl-hash-face :background "gray90" :foreground "purple" :weight 'bold)
470      (diff-added :background "gray90" :foreground "green4" :weight 'bold)
471      (diff-removed :background "gray90" :foreground "red2" :weight 'bold)
472      (diff-changed :background "gray90" :foreground "blue" :weight 'bold)
473      (diff-file-header-face :background "white" :foreground "black"
474                             :weight 'bold)
475      (diff-header-face :background "white" :foreground "black")
476      (diff-hunk-header-face :background "white" :foreground "black")
477      (diff-indicator-removed :foreground "red" :weight 'bold)
478      (diff-removed :foreground "red" :weight 'bold)
479      (diff-indicator-added :foreground "blue" :weight 'bold)
480      (diff-added :foreground "blue" :weight 'bold)
481      (font-lock-string-face :foreground "green")
482      (font-lock-variable-name-face :foreground "blue")
483      (font-lock-constant-face :foreground "blue")
484      (font-lock-preprocessor-face :foreground "green")
485      (font-lock-function-name-face :foreground "cyan")
486      (flyspell-incorrect :foreground "red2")
487      (flyspell-duplicate :foreground "OrangeRed2")
488      (hl-line :background "white")
489      (sh-heredoc :foreground "black" :background "#fff0f0")
490      (sh-heredoc-face :foreground "black" :background "#fff0f0")
491      (font-lock-keyword-face :foreground "blue")
492      (highlight :background "darkseagreen3")
493      (isearch :background "orange" :foreground "black")
494      (isearch-lazy-highlight-face' :background "yellow" :foreground "black")
495      ;; (display-time-mail-face :background "white")
496      (show-paren-match-face :background "gold" :foreground "black")
497      (show-paren-mismatch-face :background "red" :foreground "black")
498      (trailing-whitespace :background "white")
499      (mode-line :background "cornflowerblue" :foreground "black" :box nil
500                 :inverse-video nil)
501      (header-line :background "cornflowerblue" :foreground "black" :box nil
502                   :inverse-video nil)
503      (mode-line-inactive :background "gray60" :foreground "black" :box nil
504                          :inverse-video nil)
505      (region :background "white" :foreground "black")
506      (ff/date-info-face :foreground "white" :weight 'bold)
507      (ff/battery-info-face :foreground "black")
508      ;; (ff/mail-alarm-face :foreground "red" :weight 'bold)
509      (selector/selection :background "yellow")
510      (gui-button-face :background "green" :foreground "white")
511      (enotes/information-face :foreground "cyan")
512
513      (file-name-shadow :foreground "black")
514      (shadow :foreground "black")
515      (warning :foreground "black" :background "red")
516      ))
517   )
518
519 ;; When we are root, put the modeline in red
520
521 (when (string= (user-real-login-name) "root")
522   (ff/configure-faces
523    '((mode-line :background "red3" :foreground "black" :box nil
524                 :inverse-video nil))
525    ))
526
527 ;; Why should I have to do this?
528 (add-hook 'sh-mode-hook
529           (lambda ()
530             (set-face-attribute 'sh-heredoc nil
531                                 :foreground "#604000"
532                                 :background "white"
533                                 :italic t)
534             (set-face-attribute 'sh-heredoc-face nil
535                                 :foreground "#604000"
536                                 :background "white"
537                                 :italic t)
538             ))
539
540 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
541 ;; Move the window on the buffer without moving the cursor
542 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
543
544 (defun ff/scroll-down ()
545   "Scroll the buffer down one line and keep the cursor at the same location."
546   (interactive)
547   (condition-case nil
548       (scroll-down 1)
549     (error nil)))
550
551 (defun ff/scroll-up ()
552   "Scroll the buffer up one line and keep the cursor at the same location."
553   (interactive)
554   (condition-case nil
555       (scroll-up 1)
556     (error nil)))
557
558 (defun ff/scroll-left ()
559   "Scroll the buffer left one column and keep the cursor at the same location."
560   (interactive)
561   (condition-case nil
562       (scroll-left 2)
563     (error nil)))
564
565 (defun ff/scroll-right ()
566   "Scroll the buffer right one column and keep the cursor at the same location."
567   (interactive)
568   (condition-case nil
569       (scroll-right 2)
570     (error nil)))
571
572 (define-key global-map [(meta up)] 'ff/scroll-down)
573 (define-key global-map [(meta down)] 'ff/scroll-up)
574
575 (define-key global-map [(meta shift up)]
576   (lambda () (interactive) (condition-case nil (scroll-down 10) (error nil))))
577
578 (define-key global-map [(meta shift down)]
579   (lambda () (interactive) (condition-case nil (scroll-up 10) (error nil))))
580
581 ;; (define-key global-map [(meta shift up)] (lambda () (interactive) (ff/scroll-down 10)))
582 ;; (define-key global-map [(meta shift down)] 'ff/scroll-up)
583
584 (define-key global-map [(meta p)] 'ff/scroll-down)
585 (define-key global-map [(meta n)] 'ff/scroll-up)
586 (define-key global-map [(meta right)] 'ff/scroll-left)
587 (define-key global-map [(meta left)] 'ff/scroll-right)
588
589 (defun ff/delete-trailing-whitespaces-and-indent ()
590   (interactive)
591   (delete-trailing-whitespace)
592   (indent-region (point-min) (point-max) nil))
593
594 (define-key global-map [(control c) (control q)] 'ff/delete-trailing-whitespaces-and-indent)
595
596 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
597 ;; Playing sounds
598 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
599
600 (defun ff/alsa-sound (file)
601   "Plays a sound with ALSA."
602   (interactive)
603   (process-kill-without-query (start-process-shell-command "aplay"
604                                                            nil
605                                                            "aplay" "-q" file)))
606
607 (if (and (boundp 'x-display-name) (string= x-display-name ":0.0"))
608     (defalias 'ff/play-sound-async 'ff/alsa-sound)
609   (defalias 'ff/play-sound-async 'ding))
610
611 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
612 ;; I comment stuff often, let's be efficient. shift + down comments
613 ;; the current line and goes down, and shift + up uncomments the line
614 ;; and goes up (they are not the dual of each other, but moving and
615 ;; then uncommenting would be very counter-intuitive).
616 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
617
618 (defun ff/comment-and-go-down (arg)
619   "Comments and goes down ARG lines."
620   (interactive "p")
621   (condition-case nil
622       (comment-region (point-at-bol) (point-at-eol)) (error nil))
623   (next-line 1)
624   (if (> arg 1) (ff/comment-and-go-down (1- arg))))
625
626 (defun ff/uncomment-and-go-up (arg)
627   "Uncomments and goes up ARG lines."
628   (interactive "p")
629   (condition-case nil
630       (uncomment-region (point-at-bol) (point-at-eol)) (error nil))
631   (next-line -1)
632   (if (> arg 1) (ff/uncomment-and-go-up (1- arg))))
633
634 (define-key global-map [(shift down)] 'ff/comment-and-go-down)
635 (define-key global-map [(shift up)] 'ff/uncomment-and-go-up)
636
637 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
638 ;; Counting various entities in text
639 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
640
641 (defun ff/word-occurences ()
642   "Display in a new buffer the list of words sorted by number of
643 occurrences "
644   (interactive)
645
646   (let ((buf (get-buffer-create "*word counting*"))
647         (map (make-sparse-keymap))
648         (nb (make-hash-table))
649         (st (make-hash-table))
650         (result nil))
651
652     ;; Collects all words in a hash table
653
654     (save-excursion
655       (goto-char (point-min))
656       (while (re-search-forward "\\([\\-a-zA-Z\\\\]+\\)" nil t)
657         (let* ((s (downcase (match-string-no-properties 1)))
658                (k (sxhash s)))
659           (puthash k s st)
660           (puthash k (1+ (gethash k nb 0)) nb))))
661
662     ;; Creates the result buffer
663
664     (define-key map "q" 'kill-this-buffer)
665     (display-buffer buf)
666     (set-buffer buf)
667     (setq show-trailing-whitespace nil)
668     (erase-buffer)
669
670     ;; Builds a list from the hash table
671
672     (maphash
673      (lambda (key value)
674        (setq result (cons (cons value (gethash key st)) result)))
675      nb)
676
677     ;; Sort and display it
678
679     (mapc (lambda (x)
680             (if (and (> (car x) 3)
681                      ;; No leading backslash and at least four characters
682                      (string-match "^[^\\]\\{4,\\}" (cdr x))
683                      )
684                 (insert (number-to-string (car x)) " " (cdr x) "\n")))
685           (sort result (lambda (a b) (> (car a) (car b)))))
686
687     ;; Adjust the window size and stuff
688
689     (fit-window-to-buffer (get-buffer-window buf))
690     (use-local-map map)
691     (set-buffer-modified-p nil))
692   )
693
694 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
695 ;; Printing
696 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
697
698 (load "ps-print")
699
700 (setq ps-print-color-p nil
701       ps-paper-type 'letter
702       ;; ps-paper-type 'a4
703       ;; ps-top-margin (* 1.75 56.692)
704       ;; ps-left-margin 56.692
705       ;; ps-bottom-margin 56.692
706       ;; ps-right-margin 56.692
707
708       ;; Simple header. Remove that silly frame shadow.
709       ps-print-header nil
710       ps-print-header-frame nil
711       ps-header-line-pad 0.3
712       ps-header-font-family 'Courier
713       ps-header-title-font-size '(8.5 . 10)
714       ;; ps-header-font-size '(6 . 7)
715       ps-header-font-size '(10 . 12)
716       ps-font-size '(7 . 8)
717       )
718
719 (ps-put 'ps-header-frame-alist 'back-color 1.0)
720 (ps-put 'ps-header-frame-alist 'shadow-color 1.0)
721 (ps-put 'ps-header-frame-alist 'border-color 0.0)
722 (ps-put 'ps-header-frame-alist 'border-width 0.0)
723
724 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
725
726 ;; http://blog.tuxicity.se/elisp/emacs/2010/03/26/rename-file-and-buffer-in-emacs.htm
727
728 (defun rename-file-and-buffer ()
729   "Renames current buffer and file it is visiting."
730   (interactive)
731   (let ((name (buffer-name))
732         (filename (buffer-file-name)))
733     (if (not (and filename (file-exists-p filename)))
734         (message "Buffer '%s' is not visiting a file!" name)
735       (let ((new-name (read-file-name "New name: " filename)))
736         (cond ((get-buffer new-name)
737                (message "A buffer named '%s' already exists!" new-name))
738               (t
739                (rename-file name new-name 1)
740                (rename-buffer new-name)
741                (set-visited-file-name new-name)
742                (set-buffer-modified-p nil)))))))
743
744 (global-set-key (kbd "C-c r") 'rename-file-and-buffer)
745
746 (defun ff/non-existing-filename (dir prefix suffix)
747   "Returns a filename of the form DIR/PREFIX[.n].SUFFIX whose file does
748 not exist"
749   (let ((n 0)
750         (f (concat prefix suffix)))
751     (while (file-exists-p (concat dir "/" f))
752       (setq n (1+ n)
753             f (concat prefix "." (prin1-to-string n) suffix)))
754     f))
755
756 (defun ff/print-buffer-or-region-with-faces (&optional file)
757
758   ;; I am fed up with spell checking highlights
759   (when (and flyspell-mode
760              ;; (or ispell-minor-mode flyspell-mode)
761              (not (y-or-n-p "The spell checking is on, still print ? ")))
762     (error "Printing cancelled, the spell-checking is on"))
763
764   (unless
765       (condition-case nil
766           (ps-print-region-with-faces (region-beginning) (region-end) file)
767         (error nil))
768     (ps-print-buffer-with-faces file)))
769
770 (defun ff/print-to-file (file)
771   "Prints the region if selected or the whole buffer in postscript
772 into FILE."
773   (interactive
774    (list
775     (read-file-name
776      "PS file: " "/tmp/" nil nil
777      (ff/non-existing-filename
778       "/tmp"
779       (replace-regexp-in-string "[^a-zA-Z0-9_.-]" "_" (file-name-nondirectory
780                                                        (buffer-name)))
781       ".ps"))
782     ))
783   (ff/print-buffer-or-region-with-faces file))
784
785 (defun ff/print-to-printer ()
786   "Prints the region if selected or the whole buffer to a postscript
787 printer."
788   (interactive)
789   (message "Printing to '%s'" (getenv "PRINTER"))
790   (ff/print-buffer-or-region-with-faces))
791
792 ;; Can you believe it? There is a "print" key on PC keyboards ...
793
794 (define-key global-map [(print)] 'ff/print-to-file)
795 (define-key global-map [(shift print)] 'ff/print-to-printer)
796
797 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
798 ;; Dealing with the laptop battery
799 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
800
801 (defcustom ff/battery-dirs '("/sys/class/power_supply/BAT0"
802                              "/sys/class/power_supply/BAT1")
803   "*Where to gather the battery information")
804
805 (defcustom ff/temperature-files '("/sys/class/thermal/thermal_zone0/temp"
806                                   "/sys/class/thermal/thermal_zone1/temp")
807   "*Where to gather the thermal information")
808
809 (defun ff/file-first-line (file)
810   (with-temp-buffer
811     (insert-file-contents-literally file)
812     (buffer-substring (point-at-bol) (point-at-eol))))
813
814 (defun ff/battery-discharging (l)
815   (and l (or (string= (ff/file-first-line (concat (car l) "/status")) "Discharging")
816              (ff/battery-discharging (cdr l)))))
817
818 ;; If there is one "Discharging" among the states of all the
819 ;; batteries, the global state is 'discharging. Otherwise, if there is
820 ;; a "Charging", the state is 'charging. If none is true, it is
821 ;; 'unknown
822 (defun ff/battery-state (l)
823   (if l
824       (let ((u (ff/file-first-line (concat (car l) "/status"))))
825         (if (string= u "Discharging") 'discharging
826           (let ((s (ff/battery-state (cdr l))))
827             (if (eq s 'discharging) 'discharging
828               (if (or (eq s 'charging) (string= u "Charging"))
829                   'charging
830                 'unknown))
831             )
832           )
833         )
834     'unknown))
835
836 (defun ff/sum-values-from-files (list-files prefix)
837   (apply '+
838          (mapcar
839           (lambda (f)
840             (condition-case nil
841                 (string-to-number (ff/file-first-line (format "%s/%s" f prefix)))
842               (error 0))
843             )
844           list-files)))
845
846 (defun ff/battery-percent ()
847   (condition-case nil
848       (/ (* 100 (ff/sum-values-from-files ff/battery-dirs "energy_now"))
849          (ff/sum-values-from-files ff/battery-dirs "energy_full"))
850     (error -1))
851   )
852
853 (defun ff/temp-info-string () (interactive)
854        (condition-case nil
855            ;; The temperature
856
857            (let ((temp (/
858                         (apply 'max (mapcar
859                                      (lambda (f) (string-to-number (ff/file-first-line f)))
860                                      ff/temperature-files))
861                         1000)))
862
863              (if (> temp 50)
864                  (let ((s (format "%dC " temp)))
865                    (if (> temp 70)
866                        (propertize s 'face 'font-lock-warning-face)
867                      s)
868                    )
869                )
870              )
871
872          (error nil))
873        )
874
875 (defun ff/battery-info-string () (interactive)
876        (condition-case nil
877            (pcase (ff/battery-state ff/battery-dirs)
878              ;; (`charging (format "c%d%%" (ff/battery-percent)))
879              ;; (`discharging (format "d%d%%" (ff/battery-percent)))
880              ;; (`unknown "f")
881              (`charging (format "↑%d%%" (ff/battery-percent)))
882              (`discharging (format "↓%d%%" (ff/battery-percent)))
883              ;; (`unknown "✱")
884              (`unknown "F")
885              (_ "?"))
886          (error nil))
887        )
888
889 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
890
891 (defun ff/system-info () (interactive)
892
893        (let ((buf (get-buffer-create "*system info*"))
894              (map (make-sparse-keymap)))
895
896          (define-key map "q" 'kill-this-buffer)
897          (display-buffer buf)
898          (set-buffer buf)
899          (setq show-trailing-whitespace nil)
900          (erase-buffer)
901
902          (let ((highlight nil))
903
904            (mapc (lambda (x)
905                    (insert
906                     (if (setq highlight (not highlight))
907                         (propertize
908                          (with-temp-buffer (apply 'call-process x)
909                                            (buffer-string))
910                          'face '(:background "#d0d0ff"))
911                       (with-temp-buffer (apply 'call-process x)
912                                         (buffer-string))
913                       ))
914                    )
915
916                  '(
917                    ("hostname" nil t nil "-f")
918                    ("acpi" nil t)
919                    ("df" nil t nil "-h")
920                    ;; ("mount" nil t)
921                    ("ifconfig" nil t)
922                    ("ssh-add" nil t nil "-l")
923                    )))
924
925          (goto-char (point-min))
926          (while (re-search-forward "^$" nil t) (backward-delete-char 1))
927
928          (fit-window-to-buffer (get-buffer-window buf))
929          (use-local-map map)
930          (set-buffer-modified-p nil)
931          ))
932
933 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
934 ;; Display time
935 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
936
937 (setq
938
939  display-time-interval 10 ;; Check every 10s
940
941  display-time-string-forms `(
942
943                              load
944
945                              " "
946
947                              ,@(when (ff/battery-info-string)
948                                  '((ff/temp-info-string)))
949
950                              ,@(when (ff/battery-info-string)
951                                  '((propertize
952                                     (ff/battery-info-string)
953                                     'face 'ff/battery-info-face)))
954
955                              " "
956
957                              (propertize
958                               (concat ;;" ˌ"
959                                24-hours ":" minutes
960                                " "
961                                ;; dayname " "
962                                monthname " " day
963                                ;;"ˌ"
964                                )
965                               'face 'ff/date-info-face)
966
967                              )
968
969  ;; display-time-format "%b %a %e %H:%M"
970  ;; display-time-mail-face nil
971  )
972
973 ;; Show the time, mail and stuff
974 (display-time)
975
976 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
977 ;; Moving through buffers
978 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
979
980 (defun ff/next-buffer ()
981   "Switches to the next buffer in cyclic order."
982   (interactive)
983   (let ((buffer (current-buffer)))
984     (switch-to-buffer (other-buffer buffer))
985     (bury-buffer buffer)))
986
987 (defun ff/prev-buffer ()
988   "Switches to the previous buffer in cyclic order."
989   (interactive)
990   (let ((list (nreverse (buffer-list)))
991         found)
992     (while (and (not found) list)
993       (let ((buffer (car list)))
994         (if (and (not (get-buffer-window buffer))
995                  (not (string-match "\\` " (buffer-name buffer))))
996             (setq found buffer)))
997       (setq list (cdr list)))
998     (switch-to-buffer found)))
999
1000 ;; (define-key global-map [?\C-x right] 'ff/next-buffer)
1001 ;; (define-key global-map [?\C-x left] 'ff/prev-buffer)
1002 ;; (define-key global-map [?\M-\]] 'ff/next-buffer)
1003 ;; (define-key global-map [?\M-\[] 'ff/prev-buffer)
1004
1005 (define-key global-map [(meta right)] 'ff/next-buffer)
1006 (define-key global-map [(meta left)] 'ff/prev-buffer)
1007
1008 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1009 ;; There is actually a decent terminal emulator in emacs!
1010 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1011
1012 (load "term")
1013
1014 (defun ff/kill-associated-buffer (process str) (interactive)
1015        (let ((buffer (process-buffer process)))
1016          (kill-buffer buffer))
1017        (message "Process finished (%s)" (replace-regexp-in-string "\n$" "" str)))
1018
1019 (defun ff/kill-associated-buffer-and-delete-windows (process str) (interactive)
1020        (let ((buffer (process-buffer process)))
1021          (delete-windows-on buffer)
1022          (kill-buffer buffer))
1023        (message "Process finished (%s)" (replace-regexp-in-string "\n$" "" str)))
1024
1025 (defun ff/shell-new-buffer (buffername program &rest param)
1026   "Start a terminal-emulator in a new buffer with the shell PROGRAM,
1027 optionally invoked with the parameters PARAM. The process associated
1028 to the shell can be killed without query."
1029
1030   (interactive)
1031
1032   (let ((n 1)
1033         (bn buffername))
1034
1035     (while (get-buffer (concat "*" bn "*"))
1036       (setq n (1+ n)
1037             bn (format "%s<%d>" buffername n)))
1038
1039     (set-buffer (apply 'make-term (append (list bn program nil) param)))
1040
1041     (setq show-trailing-whitespace nil)
1042     (term-char-mode)
1043     (message "C-c C-k term-char-mode, C-c C-j term-line-mode. \
1044 In line mode: M-p previous line, M-n next line.")
1045
1046     ;; A standard setup of the face above is not enough, I have to
1047     ;; force them here. Since I have a gray90 background, I like
1048     ;; darker colors.
1049
1050     (when window-system
1051       (ff/configure-faces
1052        '((term-green :foreground "green3")
1053          (term-cyan :foreground "cyan3")
1054          (term-default-fg-inv :foreground "gray90" :background "black")
1055          )))
1056
1057     (term-set-escape-char ?\C-x)
1058
1059     ;; I like the shell buffer and windows to be deleted when the
1060     ;; shell process terminates. It's a bit of a mess to acheive this.
1061
1062     (let ((process (get-buffer-process (current-buffer))))
1063       (process-kill-without-query process)
1064       (set-process-sentinel process
1065                             ;; 'ff/kill-associated-buffer-and-delete-windows
1066                             'ff/kill-associated-buffer
1067                             ))
1068
1069     ;; (switch-to-buffer-other-window (concat "*" bn "*"))
1070     (switch-to-buffer (concat "*" bn "*"))
1071     ))
1072
1073 (defcustom ff/default-bash-commands '("ssh")
1074   "*List of commands to be used for completion when invoking a new
1075 bash shell with `ff/bash-new-buffer'.")
1076
1077 (defun ff/bash-new-buffer (universal)
1078   "Starts a bash in a new buffer. When invoked with a universal
1079 argument, asks for a command to execute in that bash shell. The list
1080 of commands in `ff/default-bash-commands' is used for auto-completion"
1081   (interactive "P")
1082
1083   (if universal
1084       (let ((cmd (completing-read
1085                   "Command: "
1086                   (mapcar (lambda (x) (cons x t)) ff/default-bash-commands))))
1087         (ff/shell-new-buffer cmd "/bin/bash" "-c" cmd))
1088
1089     (ff/shell-new-buffer "bash" "/bin/bash")))
1090
1091 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1092 ;; vc stuff for CVS
1093 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1094
1095 (setq ;; Always follow links if the file is under version control
1096  vc-follow-symlinks t
1097  )
1098
1099 (when (load "vc-git" nil t)
1100   (add-to-list 'vc-handled-backends 'GIT))
1101
1102 ;; alarm-vc.el is one of my own scripts, check my web page
1103
1104 (when (ff/load-or-alert "alarm-vc" t)
1105   (setq alarm-vc-mode-exceptions "^VM"))
1106
1107 (when (ff/load-or-alert "git")
1108   (setq git-show-unknown nil)
1109   )
1110
1111 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1112 ;; Makes .sh and others files executable automagically
1113 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1114
1115 ;; Please consider the security-related consequences of using it
1116
1117 ;; (defun ff/make-shell-scripts-executable (&optional filename)
1118 ;; (setq filename (or filename (buffer-name)))
1119 ;; (when (and (string-match "\\.sh$\\|\\.pl$\\|\\.rb" filename)
1120 ;; (not (file-executable-p filename))
1121 ;; )
1122 ;; (set-file-modes filename 493)
1123 ;; (message "Made %s executable" filename)))
1124
1125 ;; (add-hook 'after-save-hook 'ff/make-shell-scripts-executable)
1126
1127 (add-hook 'after-save-hook
1128           'executable-make-buffer-file-executable-if-script-p)
1129
1130 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1131 ;; Cool stuff to navigate in emacs-lisp sources
1132 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1133
1134 (load "find-func")
1135
1136 (defun ff/goto-function-definition (&optional goback)
1137   "Go directly to the definition of the function at point. With
1138 goback argument, go back where we were."
1139   (interactive "P")
1140   (if goback
1141       (if (not (and (boundp 'goto-function-history) goto-function-history))
1142           (error "We were nowhere, buddy")
1143         (message "Come back")
1144         (switch-to-buffer (car (car goto-function-history)))
1145         (goto-char (cdr (car goto-function-history)))
1146         (setq goto-function-history (cdr goto-function-history)))
1147
1148     (let ((function (function-called-at-point)))
1149       (when function
1150         (let ((location (find-function-search-for-symbol
1151                          function nil
1152                          (symbol-file function))))
1153           (setq goto-function-history
1154                 (cons (cons (current-buffer) (point))
1155                       (and (boundp 'goto-function-history)
1156                            goto-function-history)))
1157           (pop-to-buffer (car location))
1158           (goto-char (cdr location)))))))
1159
1160 (define-key global-map [(meta g)] 'ff/goto-function-definition)
1161 (define-key global-map [(meta G)] (lambda () (interactive)
1162                                     (ff/goto-function-definition t)))
1163
1164 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1165 ;; The big stuff (bbdb, mailcrypt, etc.)
1166 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1167
1168 ;; Failsafe version if we can't load bbdb
1169 (defun ff/explicit-name (email) email)
1170
1171 (load "vc-git")
1172
1173 (when (ff/load-or-alert "bbdb")
1174
1175   (setq
1176    ;; Stop asking (if not t or nil, will not ask)
1177    bbdb-offer-save 'never
1178    ;; I hate when bbdb decides to mess up my windows
1179    bbdb-use-pop-up nil
1180    ;; I have no problem with bbdb asking me if the sender email
1181    ;; does not match exactly the address we have in the database
1182    bbdb-quiet-about-name-mismatches 0
1183    ;; I have european friends, too
1184    bbdb-north-american-phone-numbers-p nil
1185    ;; To cycle through all possible addresses
1186    bbdb-complete-name-allow-cycling t
1187    ;; Cycle with full names only, not through all net-addresses alone too
1188    bbdb-dwim-net-address-allow-redundancy t
1189    ;; Do not add new addresses automatically
1190    bbdb-always-add-addresses nil
1191    )
1192
1193   (defface ff/known-address-face
1194     '((t (:foreground "blue2")))
1195     "The face to display known mail identities.")
1196
1197   (defface ff/unknown-address-face
1198     '((t (:foreground "gray50")))
1199     "The face to display unknown mail identities.")
1200
1201   (defun ff/explicit-name (email)
1202     "Returns a string identity for the first address in EMAIL. The
1203 identity is taken from bbdb if possible or from the address itself
1204 with mail-extract-address-components. The suffix \"& al.\" is added if
1205 there are more than one address.
1206
1207 If no bbdb record is found, the name is propertized with the face
1208 ff/unknown-address-face. If a record is found and contains a note
1209 'face, the associated face is used, otherwise
1210 ff/known-address-face is used."
1211
1212     (and email
1213          (let* ((data (mail-extract-address-components email))
1214                 (name (car data))
1215                 (net (cadr data))
1216                 (record (bbdb-search-simple nil net)))
1217
1218            (concat
1219
1220             (condition-case nil
1221                 (propertize (bbdb-record-name record)
1222                             'face
1223                             (or (cdr (assoc 'face
1224                                             (bbdb-record-raw-notes record)))
1225                                 'ff/known-address-face))
1226               (error
1227                (propertize (or (and data (concat "<" net ">"))
1228                                "*undefined*")
1229                            'face 'ff/unknown-address-face)
1230                ))
1231             (if (string-match "," (mail-strip-quoted-names email)) " & al.")
1232             )))
1233     )
1234
1235   (ff/configure-faces '((ff/robot-address-face :foreground "green4")
1236                         (ff/personal-address-face :foreground "dark magenta" :weight 'bold)
1237                         (ff/important-address-face :foreground "red3"
1238                                                    :weight 'bold
1239                                                    )))
1240
1241   )
1242
1243 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1244 ;; An encrypted file to put secure stuff (passwords, ...)
1245 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1246
1247 (when (ff/load-or-alert "mailcrypt")
1248   (mc-setversion "gpg")
1249   ;; Keep the passphrase for 10min
1250   (setq mc-passwd-timeout 600
1251         ff/secure-note-file "~/private/secure-notes.gpg")
1252   )
1253
1254 (defface ff/secure-date
1255   '((t (:background "white" :weight bold)))
1256   "The face to display the dates in the modeline.")
1257
1258 (defun ff/secure-note-add () (interactive)
1259
1260        (unless
1261            (let ((b (find-buffer-visiting ff/secure-note-file)))
1262              (and b (switch-to-buffer b)))
1263          (find-file ff/secure-note-file)
1264          ;; Adds a new entry (i.e. date and a bunch of empty lines)
1265          (goto-char (point-min))
1266          (insert "-- "
1267                  (format-time-string "%Y %b %d %H:%M:%S" (current-time))
1268                  " --\n\n")
1269          (previous-line 1)
1270          )
1271
1272        ;; Colorizes the dates
1273
1274        (save-excursion
1275          (goto-char (point-min))
1276          (while (re-search-forward
1277                  "^-- [0-9]+ [a-z]+ [0-9]+ [0-9]+:[0-9]+:[0-9]+ -+$"
1278                  nil t)
1279            (add-text-properties
1280             (match-beginning 0) (1+ (match-end 0))
1281             '(face ff/secure-date rear-nonsticky t))))
1282
1283        (set-buffer-modified-p nil)
1284        (setq buffer-undo-list nil)
1285        )
1286
1287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1288 ;; Spelling
1289 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1290
1291 (setq ;; For french, aspell is far better than ispell
1292  ispell-program-name "aspell"
1293  ;; To avoid ispell errors in figure filenames, labels, references.
1294  ;;       ispell-tex-skip-alists
1295  ;;       (list
1296  ;;        (append (car ispell-tex-skip-alists)
1297  ;;                '(("\\\\citep"           ispell-tex-arg-end) ;; JMLR
1298  ;;                  ("\\\\cite"            ispell-tex-arg-end)
1299  ;;                  ("\\\\nocite"          ispell-tex-arg-end)
1300  ;;                  ("\\\\includegraphics" ispell-tex-arg-end)
1301  ;;                  ("\\\\author"          ispell-tex-arg-end)
1302  ;;                  ("\\\\ref"             ispell-tex-arg-end)
1303  ;;                  ("\\\\label"           ispell-tex-arg-end)
1304  ;;                  ))
1305  ;;        (cadr ispell-tex-skip-alists))
1306
1307  ;; So that reftex follows the text when moving in the summary
1308  reftex-toc-follow-mode nil
1309  ;; So that reftex visits files to follow
1310  reftex-revisit-to-follow t
1311  )
1312
1313 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1314 ;; Used in a \includegraphics runs xfig with the corresponding .fig
1315 ;; file or gimp with the corresponding bitmap picture
1316 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1317
1318 (defun ff/run-eps-edition (prefix rules &optional force)
1319   (if rules
1320       (let ((filename (concat prefix (car (car rules)))))
1321         (if (or force (file-exists-p filename))
1322             (start-process "latex-eps-editor" nil (cdr (car rules)) filename)
1323           (ff/run-eps-edition prefix (cdr rules) force)))
1324     (message "No original file found for %seps" prefix)))
1325
1326 (defcustom ff/xdvi-for-latex-options nil
1327   "*Options to pass to xdvi when invoking `ff/run-viewer'")
1328
1329 (defun ff/run-viewer (universal)
1330
1331   "Starts an editor for the .eps at point (either xfig or gimp,
1332 depending with the original file it can find), or starts xdvi for
1333 the current .tex if no .eps is found at point. When run with a
1334 universal argument starts xfig even if the .fig does not exist"
1335
1336   (interactive "P")
1337
1338   (if (and (save-excursion
1339              (and (re-search-backward "{" (point-at-bol) t)
1340                   (or (re-search-forward "{\\([^{}]*.\\)eps}" (point-at-eol) t)
1341                       (re-search-forward "{\\([^{}]*.\\)pdf}" (point-at-eol) t)
1342                       (re-search-forward "{\\([^{}]*.\\)pdf_t}" (point-at-eol) t)
1343                       (re-search-forward "{\\([^{}]*.\\)png}" (point-at-eol) t)
1344                       (re-search-forward "{\\([^{}]*.\\)jpg}" (point-at-eol) t)
1345                       )))
1346            (and (<= (match-beginning 1) (point))
1347                 (>= (match-end 1) (- (point) 2))))
1348
1349       (ff/run-eps-edition (match-string-no-properties 1)
1350                           '(("fig" . "xfig")
1351                             ("jpg" . "gimp" )
1352                             ("png" . "gimp") ("pgm" . "gimp") ("ppm" . "gimp")
1353                             ("jpg" . "xv"))
1354                           universal)
1355
1356     (if (not (and (buffer-file-name) (string-match "\\(.*\\)\.tex$"
1357                                                    (buffer-file-name))))
1358         (message "Not a latex file!")
1359       (condition-case nil (kill-process xdvi-process) (error nil))
1360       (let ((dvi-name (concat (match-string 1 (buffer-file-name)) ".dvi")))
1361         (if (not (file-exists-p dvi-name)) (error "Can not find %s !" dvi-name)
1362           (message "Starting xdvi with %s" dvi-name)
1363           (setq xdvi-process (apply 'start-process
1364                                     (append '("xdvi-for-latex" nil "xdvi")
1365                                             ff/xdvi-for-latex-options
1366                                             (list dvi-name))))
1367           (process-kill-without-query xdvi-process))))
1368     ))
1369
1370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1371 ;; Tex mode
1372
1373 ;; When working on a tex file with other people, I can just change
1374 ;; ff/tex-command in the -*- part of the file so that I don't mess up
1375 ;; other's people configuration.
1376
1377 (defadvice tex-file (around ff/set-my-own-tex-command () activate)
1378   (let ((tex-command
1379          (or (and (boundp 'ff/tex-command)
1380                   ff/tex-command)
1381              tex-command)))
1382     ad-do-it))
1383
1384 ;; This is a bit hardcore, but really I can't bear the superscripts in
1385 ;; my emacs window and could not find another way to deactivate them.
1386
1387 (load "tex-mode")
1388 (defun tex-font-lock-suscript (pos) ())
1389
1390 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1391 ;; Prevents many errors from beeping and makes the others play a nifty
1392 ;; sound
1393 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1394
1395 (defun ff/ring-bell ()
1396   (unless (memq this-command
1397                 '(isearch-abort
1398                   abort-recursive-edit
1399                   exit-minibuffer
1400                   keyboard-quit
1401                   backward-delete-char-untabify
1402                   delete-backward-char
1403                   minibuffer-complete-and-exit
1404                   previous-line next-line
1405                   backward-char forward-char
1406                   scroll-up scroll-down
1407                   enlarge-window-horizontally shrink-window-horizontally
1408                   enlarge-window shrink-window
1409                   minibuffer-complete
1410                   ))
1411     ;; (message "command [%s]" (prin1-to-string this-command))
1412     ;; (ff/play-sound-async "~/local/sounds/short_la.wav")
1413     ))
1414
1415 (setq ring-bell-function 'ff/ring-bell)
1416
1417 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1418 ;; Past the content of the url currently in the kill-ring with
1419 ;; shift-click 2
1420 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1421
1422 (defun ff/insert-url (&optional url)
1423   "Downloads an URL with lynx and inserts it after the point."
1424   (interactive "MUrl: ")
1425   (when url
1426     (message "Inserting %s" url)
1427     (insert (concat "from: " url "\n\n"))
1428     ;; (call-process "lynx" nil t nil "-nolist" "-dump" url))
1429     (call-process "w3m" nil t nil "-dump" url))
1430   )
1431
1432 (define-key global-map [(shift mouse-2)]
1433   (lambda () (interactive) (ff/insert-url (current-kill 0))))
1434
1435 ;; lookup-dict is one of my own scripts, check my web page
1436
1437 (when (ff/load-or-alert "lookup-dict" t)
1438   (define-key global-map [(control \?)] 'lookup-dict))
1439
1440 ;; (defun ff/generate-password () (interactive)
1441 ;; (let ((c "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"))
1442 ;; (nth (random (length c)) c))
1443
1444 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1445 ;; Automatization of things I do often
1446 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1447
1448 (defun ff/snip () (interactive)
1449        (let ((start (condition-case nil (region-beginning) (error (point))))
1450              (end (condition-case nil (region-end) (error (point)))))
1451          (goto-char end)
1452          (insert "----------------------------- snip snip -----------------------------\n")
1453          (goto-char start)
1454          (insert "----------------------------- snip snip -----------------------------\n")
1455          ))
1456
1457 (defun ff/start-latex ()
1458   "Adds all that stuff to start a new LaTeX document."
1459   (interactive)
1460   (goto-char (point-min))
1461   (insert "%% -*- mode: latex; mode: reftex; mode: flyspell; coding: utf-8; tex-command: \"pdflatex.sh\" -*-
1462
1463 \\documentclass[12pt,a4paper,twoside]{article}
1464 \\usepackage[a4paper,top=2.5cm,bottom=2cm,left=2.5cm,right=2.5cm]{geometry}
1465 \\usepackage[utf8]{inputenc}
1466 \\usepackage{amsmath}
1467 \\usepackage{amssymb}
1468 \\usepackage[pdftex]{graphicx}
1469 \\usepackage{microtype}
1470 \\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue,citecolor=blue]{hyperref}
1471
1472 \\setlength{\\parindent}{0cm}
1473 \\setlength{\\parskip}{12pt}
1474 \\renewcommand{\\baselinestretch}{1.3}
1475
1476 \\def\\argmax{\\operatornamewithlimits{argmax}}
1477 \\def\\argmin{\\operatornamewithlimits{argmin}}
1478
1479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 %% Open sans font
1481 %%\\usepackage[default]{opensans}
1482 %%\\usepackage{cmbright}
1483 %%\\renewcommand{\\familydefault}{fos}
1484 %%\\renewcommand{\\seriesdefault}{l}
1485 %%\\renewcommand{\\bfdefault}{sb}
1486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487 %% The \\todo command
1488 \\newcounter{nbdrafts}
1489 \\setcounter{nbdrafts}{0}
1490 \\makeatletter
1491 \\newcommand{\\checknbdrafts}{
1492 \\ifnum \\thenbdrafts > 0
1493 \\@latex@warning@no@line{*WARNING* The document contains \\thenbdrafts \\space draft note(s)}
1494 \\fi}
1495 \\newcommand{\\todo}[1]{\\addtocounter{nbdrafts}{1}{\\color{red} #1}}
1496 \\makeatother
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1498
1499 \\begin{document}
1500
1501 ")
1502   (save-excursion
1503     (goto-char (point-max))
1504     (insert "
1505
1506 \\end{document}
1507 "))
1508   (latex-mode))
1509
1510 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1511
1512 (defun ff/add-copyrights ()
1513   "Adds two lines for the (C) at the beginning of current buffer."
1514   (interactive)
1515
1516   (let ((comment-style 'plain))
1517
1518     (goto-char (point-min))
1519
1520     ;; If this is a script, put the copyrights after the first line
1521
1522     (when (re-search-forward "^#!" nil t)
1523       (beginning-of-line)
1524       (next-line 1))
1525
1526     (let ((start (point))
1527           (comment-style 'box))
1528       (insert
1529        (concat
1530
1531         "\nSTART_IP_HEADER\n"
1532
1533         (when (boundp 'user-full-name)
1534           (concat "\nWritten by " user-full-name "\n"))
1535
1536         (when (boundp 'user-mail-address)
1537           (concat "Contact <" user-mail-address "> for comments & bug reports\n"))
1538
1539         "\nEND_IP_HEADER\n"
1540         ))
1541
1542       (comment-region start (point)))
1543
1544     ))
1545
1546 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1547
1548 (defun ff/remove-ip-header () (interactive)
1549        (save-excursion
1550          (goto-char (point-min))
1551          (when (and (re-search-forward "START_IP_HEADER" nil t)
1552                     (re-search-forward "END_IP_HEADER" nil t))
1553            (message "yep"))
1554          ))
1555
1556 (defun ff/add-gpl ()
1557   "Adds the GPL statements at the beginning of current buffer."
1558   (interactive)
1559   (let ((comment-style 'box)
1560         (gpl
1561          (concat
1562
1563           ;;           "
1564           ;; This program is free software; you can redistribute it and/or
1565           ;; modify it under the terms of the GNU General Public License
1566           ;; version 2 as published by the Free Software Foundation.
1567
1568           ;; This program is distributed in the hope that it will be useful, but
1569           ;; WITHOUT ANY WARRANTY\; without even the implied warranty of
1570           ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1571           ;; General Public License for more details.
1572           ;; "
1573
1574           "
1575 START_IP_HEADER
1576
1577 This program is free software: you can redistribute it and/or modify
1578 it under the terms of the version 3 of the GNU General Public License
1579 as published by the Free Software Foundation.
1580
1581 This program is distributed in the hope that it will be useful, but
1582 WITHOUT ANY WARRANTY; without even the implied warranty of
1583 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1584 General Public License for more details.
1585
1586 You should have received a copy of the GNU General Public License
1587 along with this program. If not, see <http://www.gnu.org/licenses/>.
1588
1589 "
1590           (when (boundp 'user-full-name)
1591             (concat "Written by and Copyright (C) " user-full-name "\n"))
1592
1593           (when (boundp 'user-mail-address)
1594             (concat "Contact <" user-mail-address "> for comments & bug reports\n"))
1595
1596           "
1597 END_IP_HEADER
1598 "
1599
1600           )))
1601
1602     (goto-char (point-min))
1603
1604     ;; If this is a script, put the gpl after the first line
1605     (when (re-search-forward "^#!" nil t)
1606       (beginning-of-line)
1607       (next-line 1))
1608
1609     (let ((start (point)))
1610       (insert gpl)
1611       (comment-region start (point)))
1612     ))
1613
1614 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1615
1616 (defun ff/start-c ()
1617   "Adds the header to start a C program."
1618   (interactive)
1619   ;;   (beginning-of-buffer)
1620   (insert
1621    "
1622 #include <stdio.h>
1623 #include <stdlib.h>
1624
1625 int main(int argc, char **argv) {
1626   exit(EXIT_SUCCESS);
1627 }
1628 ")
1629   (previous-line 2)
1630   )
1631
1632 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1633
1634 (defun ff/start-c++ ()
1635   "Adds the header to start a C++ program."
1636   (interactive)
1637   ;;   (beginning-of-buffer)
1638   (insert
1639    "
1640 #include <iostream>
1641 #include <fstream>
1642 #include <cmath>
1643 #include <stdio.h>
1644 #include <stdlib.h>
1645
1646 using namespace std;
1647
1648 int main(int argc, char **argv) {
1649
1650 }
1651 ")
1652   (previous-line 2)
1653   )
1654
1655 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1656
1657 (defun ff/headerize ()
1658   "Adds the #define HEADER_H, etc."
1659   (interactive)
1660   (let ((flag-name (replace-regexp-in-string
1661                     "[\. \(\)]" "_"
1662                     (upcase (file-name-nondirectory (buffer-file-name))))))
1663     (goto-char (point-max))
1664     (insert "\n#endif\n")
1665     (goto-char (point-min))
1666     (insert (concat "#ifndef " flag-name "\n"))
1667     (insert (concat "#define " flag-name "\n"))
1668     )
1669   )
1670
1671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1672
1673 (defun ff/start-html ()
1674   "Adds all that stuff to start a new HTML file."
1675   (interactive)
1676   (goto-char (point-min))
1677   (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1678 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
1679
1680 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
1681
1682 <head>
1683 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
1684 <title></title>
1685 <style type=\"text/css\">
1686 p {
1687  color:#009900;
1688 }
1689 </style>
1690 </head>
1691
1692 <body>
1693 ")
1694   (goto-char (point-max))
1695   (insert "
1696 </body>
1697
1698 </html>
1699 ")
1700   (html-mode))
1701
1702 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1703
1704 ;; Insert a line showing all the variables written on the current line
1705 ;; and separated by commas
1706
1707 (defun ff/cout-var (arg)
1708   "Invoked on a line with a list of variables names,
1709 it inserts a line which displays their values in cout, or cerr if
1710 the function is invoked with a universal arg"
1711   (interactive "P")
1712   (let ((line (if arg "cerr" "cout")))
1713     (goto-char (point-at-bol))
1714     ;; Regexp syntax sucks moose balls, honnest. To match '[', just
1715     ;; put it as the first char in the [...] ... This leads to some
1716     ;; obvious things like the following
1717     (while (re-search-forward "\\([][a-zA-Z0-9_.:\(\)]+\\)" (point-at-eol) t)
1718       (setq line
1719             (concat line " << \" "
1720                     (match-string 1) " = \" << " (match-string 1))))
1721     (goto-char (point-at-bol))
1722     (kill-line)
1723     (insert line " << endl\;\n")
1724     (indent-region (point-at-bol 0) (point-at-eol 0) nil)
1725     ))
1726
1727 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1728
1729 (defun ff/clean-article ()
1730   "Cleans up an article by removing the leading blanks on each line
1731 and refilling all the paragraphs."
1732   (interactive)
1733   (let ((fill-column 92))
1734     (goto-char (point-min))
1735     (while (re-search-forward "^\\ +" nil t)
1736       (replace-match "" nil nil))
1737     (fill-individual-paragraphs (point-min) (point-max) t)))
1738
1739 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1740
1741 (defun ff/start-slide ()
1742   (interactive)
1743   (insert "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744
1745 \\begin{frame}{")
1746
1747   (save-excursion (insert "}{}
1748
1749 \\end{frame}
1750
1751 "))
1752   )
1753
1754 (add-hook
1755  'latex-mode-hook
1756  (lambda ()
1757    (define-key latex-mode-map [(meta S)] 'ff/start-slide)
1758    (define-key latex-mode-map [(control c) (control a)] 'align-current)
1759    (define-key latex-mode-map [(control end)] 'tex-close-latex-block)
1760    (define-key latex-mode-map [(control tab)] 'ispell-complete-word)
1761    (copy-face 'default 'tex-verbatim)
1762    ;; (ff/configure-faces '((tex-verbatim :background "gray95")))
1763    ))
1764
1765 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1766
1767 (defun ff/start-test-code ()
1768   (interactive)
1769   (let ((start (point)))
1770     (insert "
1771 { // ******************************* START ***************************
1772 #warning Test code added on "
1773             (format-time-string "%04Y %b %02d %02H:%02M:%02S" (current-time))
1774             "
1775
1776 } // ******************************** END ****************************
1777
1778 ")
1779     (indent-region start (point) nil))
1780   (previous-line 3)
1781   (c-indent-command))
1782
1783 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1784
1785 (defun ff/code-to-html () (interactive)
1786        (save-restriction
1787          (narrow-to-region (region-beginning) (region-end))
1788          (replace-string "\"" "&quot;" nil (point-min) (point-max))
1789          (replace-string " " "&nbsp;" nil (point-min) (point-max))
1790          (replace-string ">" "&gt;" nil (point-min) (point-max))
1791          (replace-string "<" "&lt;" nil (point-min) (point-max))
1792          (replace-string "\e" "^[" nil (point-min) (point-max))
1793          (replace-string "\7f" "^?" nil (point-min) (point-max))
1794          (replace-string "\1f" "^_" nil (point-min) (point-max))
1795          (replace-regexp "$" "<br />" nil (point-min) (point-max))
1796          )
1797        )
1798
1799 (defun ff/downcase-html-tags () (interactive)
1800        (save-excursion
1801          (beginning-of-buffer)
1802          (while (re-search-forward "<\\([^>]+\\)>" nil t)
1803            (downcase-region (match-beginning 1) (match-end 1)))
1804          )
1805        )
1806
1807 ;; If we enter html mode and there is no makefile around, create a
1808 ;; compilation command with tidy (this is cool stuff)
1809
1810 (add-hook 'html-mode-hook
1811           (lambda ()
1812             (unless (or (not (buffer-file-name))
1813                         (file-exists-p "makefile")
1814                         (file-exists-p "Makefile"))
1815               (set (make-local-variable 'compile-command)
1816                    (let ((fn (file-name-nondirectory buffer-file-name)))
1817                      (format "tidy -utf8 %s > /tmp/%s" fn fn))))))
1818
1819 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1820
1821 (defun ff/count-words-region (beginning end)
1822   "Print number of words in the region.
1823 Words are defined as at least one word-constituent character
1824 followed by at least one character that is not a
1825 word-constituent.  The buffer's syntax table determines which
1826 characters these are."
1827
1828   (interactive "r")
1829   (message "Counting words in region ... ")
1830   (save-excursion
1831     (goto-char beginning)
1832     (let ((count 0))
1833       (while (< (point) end)
1834         (re-search-forward "\\w+\\W+")
1835         (setq count (1+ count)))
1836       (cond ((zerop count) (message "The region does NOT have any word."))
1837             ((= 1 count) (message "The region has 1 word."))
1838             (t (message "The region has %d words." count))))))
1839
1840 ;; (add-hook 'html-mode-hook 'flyspell-mode)
1841
1842 (defun ff/tidy-html ()
1843   "Run tidy in on the content of the current buffer, put the result in
1844 a file in /tmp"
1845   (interactive)
1846   (call-process-region (point-min) (point-max)
1847                        "/usr/bin/tidy"
1848                        nil
1849                        (list nil (make-temp-file "/tmp/tidy-html."))))
1850
1851 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1852
1853 ;; Create the adequate embryo of a file if it does not exist
1854
1855 (defun ff/start-file () (interactive)
1856        (let ((filename (buffer-file-name)))
1857          (when filename
1858
1859            (when (string-match "\\.sh$" filename)
1860              (sh-mode)
1861              (insert "#!/bin/bash\n\nset -e\nset -o pipefail\n\n")
1862              (save-excursion
1863                (ff/add-copyrights))
1864              )
1865
1866            (when (string-match "\\.html$" filename)
1867              (html-mode)
1868              (ff/start-html)
1869              (previous-line 4)
1870              )
1871
1872            (when (string-match "\\.h$" filename)
1873              (c++-mode)
1874              (ff/headerize)
1875              (save-excursion
1876                (ff/add-copyrights)
1877                (newline))
1878              (newline)
1879              (newline)
1880              (previous-line 1)
1881              )
1882
1883            (when (string-match "\\.c$" filename)
1884              (c-mode)
1885              (ff/add-copyrights)
1886              (ff/start-c))
1887
1888            (when (string-match "\.\\(cc\\|cpp\\)$" filename)
1889              (c++-mode)
1890              (ff/add-copyrights)
1891              (let ((headername  (replace-regexp-in-string "\\.\\(cc\\|cpp\\)$" ".h"
1892                                                           filename)))
1893                (if (file-exists-p headername)
1894                    (insert (concat "\n#include \"" (file-name-nondirectory headername) "\"\n"))
1895                  (ff/start-c++))
1896                ))
1897
1898            (when (string-match "\\.tex$" filename)
1899              (latex-mode)
1900              (ff/start-latex)
1901              ))
1902          )
1903        (set-buffer-modified-p nil)
1904        )
1905
1906 (if (>= emacs-major-version 22)
1907     (add-to-list 'find-file-not-found-functions 'ff/start-file)
1908   (add-to-list 'find-file-not-found-hooks 'ff/start-file))
1909
1910 (when (>= emacs-major-version 24)
1911   (define-obsolete-function-alias 'make-local-hook 'ignore "21.1")
1912   (setq send-mail-function 'sendmail-send-it) ;; emacs 24.x stuff
1913
1914   (custom-set-faces
1915    '(diff-added ((default (:background "gray90" :foreground "green4" :weight bold))))
1916    '(diff-removed ((default (:background "gray90" :foreground "red2" :weight bold))))
1917    '(diff-changed ((default (:background "gray90" :foreground "blue" :weight bold))))
1918    )
1919   )
1920
1921 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1922
1923 (define-key global-map [f8] 'ff-find-other-file)
1924 (define-key global-map [(shift f8)] (lambda () (interactive) (ff-find-other-file t)))
1925
1926 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1927 ;; The compilation hacks
1928 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1929
1930 ;; If we enter c++ mode and there is no makefile around, we create a
1931 ;; make command on the fly for the specific object file
1932
1933 (add-hook 'c++-mode-hook
1934           (lambda ()
1935             (unless (or (file-exists-p "makefile") (file-exists-p "Makefile"))
1936               (set (make-local-variable 'compile-command)
1937                    (concat
1938                     "make -k "
1939                     (file-name-sans-extension
1940                      (file-name-nondirectory buffer-file-name)))))))
1941
1942 ;; <f1> runs the compilation according to the compile-command (and
1943 ;; thus does not ask any confirmation), shows the compilation buffer
1944 ;; during compilation and delete all windows showing the compilation
1945 ;; buffer if the compilation ends with no error
1946
1947 ;; <shift-f1> asks for a compilation command and runs the compilation
1948 ;; but does not restore the window configuration (i.e. the compilation
1949 ;; buffer's window will still be visible, as usual)
1950
1951 ;; <f2> goes to the next compilation error (as C-x ` does on the
1952 ;; standard configuration)
1953
1954 (defun ff/restore-windows-if-no-error (buffer msg)
1955   "Delete the windows showing the compilation buffer if msg
1956   matches \"^finished\"."
1957
1958   (when (string-match "^finished" msg)
1959     ;;     (delete-windows-on buffer)
1960     (if (boundp 'ff/window-configuration-before-compilation)
1961         (set-window-configuration ff/window-configuration-before-compilation))
1962     )
1963   )
1964
1965 (add-to-list 'compilation-finish-functions 'ff/restore-windows-if-no-error)
1966
1967 (defun ff/fast-compile ()
1968   "Compiles without asking anything."
1969   (interactive)
1970   (let ((compilation-read-command nil))
1971     (setq ff/window-configuration-before-compilation (current-window-configuration))
1972     (compile compile-command)))
1973
1974 (setq compilation-read-command t
1975       compile-command "make -j -k"
1976       compile-history '("make clean" "make DEBUG=yes -j -k" "make -j -k")
1977       )
1978
1979 (defun ff/universal-compile () (interactive)
1980        (funcall (or (cdr (assoc major-mode
1981                                 '(
1982                                   (latex-mode . tex-file)
1983                                   (html-mode . browse-url-of-buffer)
1984                                   ;; Here you can add other mode -> compile command
1985                                   )))
1986                     'ff/fast-compile         ;; And this is the failsafe
1987                     )))
1988
1989 (define-key global-map [f1] 'ff/universal-compile)
1990 (define-key global-map [(shift f1)] 'compile)
1991 (define-key global-map [f2] 'next-error)
1992
1993 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1994 ;; Related to mail
1995 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1996
1997 ;; (when (ff/load-or-alert "flyspell-timer" t)
1998 ;;   (add-hook 'flyspell-mode-hook 'flyspell-timer-ensure-idle-timer))
1999
2000 (defun ff/start-flyspell () (interactive)
2001        (ff/configure-faces
2002         '(
2003           ;; (flyspell-incorrect :background "#ff0000" :foreground "black")
2004           ;; (flyspell-duplicate :background "#ff9000" :foreground "black")
2005           (flyspell-incorrect :foreground "#ff0000" :weight 'bold)
2006           (flyspell-duplicate :foreground "#ff9000" :weight 'bold)
2007           ))
2008        ;; (flyspell-buffer)
2009        )
2010
2011 (add-hook 'flyspell-mode-hook 'ff/start-flyspell)
2012
2013 (defun ff/pick-dictionnary () (interactive)
2014        (when (and (boundp 'flyspell-mode) flyspell-mode)
2015          (if (and current-input-method (string-match "latin" current-input-method))
2016              (ispell-change-dictionary "francais")
2017            (ispell-change-dictionary "american"))
2018          ;;     (flyspell-buffer)
2019          )
2020        )
2021
2022 (defadvice toggle-input-method (after ff/switch-dictionnary nil activate)
2023   (ff/pick-dictionnary))
2024
2025 ;; (add-hook 'message-mode-hook 'auto-fill-mode)
2026 ;; (add-hook 'message-mode-hook 'flyspell-mode)
2027
2028 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2029 ;; Delete all windows which are in the same "column", which means
2030 ;; whose xmin and xmax are bounded by the xmin and xmax of the
2031 ;; currently selected column
2032 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2033
2034 ;; This is from emacs23 ! better than my old ff/delete-other-windows-in-column
2035
2036 (unless (fboundp 'delete-other-windows-vertically)
2037
2038   (defun delete-other-windows-vertically (&optional window)
2039     "Delete the windows in the same column with WINDOW, but not WINDOW itself.
2040 This may be a useful alternative binding for \\[delete-other-windows]
2041  if you often split windows horizontally."
2042     (interactive)
2043     (let* ((window (or window (selected-window)))
2044            (edges (window-edges window))
2045            (w window) delenda)
2046       (while (not (eq (setq w (next-window w 1)) window))
2047         (let ((e (window-edges w)))
2048           (when (and (= (car e) (car edges))
2049                      (= (caddr e) (caddr edges)))
2050             (push w delenda))))
2051       (mapc 'delete-window delenda)))
2052   )
2053
2054 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2055 ;; Misc things
2056 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2057
2058 ;; Entropy is cool
2059
2060 (defun ff/entropy (l)
2061   (apply '+
2062          (mapcar
2063           (lambda (x)
2064             (if (= x 0.0) 0.0
2065               (* (- x) (/ (log x) (log 2)))))
2066           l)
2067          )
2068   )
2069
2070 ;; Usefull to deal with results in latex files
2071
2072 (defun ff/round-floats-in-region () (interactive)
2073        (save-restriction
2074          (condition-case nil
2075              (narrow-to-region (region-beginning) (region-end))
2076            (error (thing-at-point 'word)))
2077          (save-excursion
2078            (goto-char (point-min))
2079            (while (re-search-forward "[0-9\.]+" nil t)
2080              (let ((value (string-to-number (buffer-substring (match-beginning 0) (match-end 0)))))
2081                (delete-region (match-beginning 0) (match-end 0))
2082                (insert (format "%0.3f" value)))))))
2083
2084 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2085 ;; Keymaping
2086 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2087
2088 (load "info" nil t)
2089
2090 (define-key global-map [(shift iso-lefttab)] 'ispell-complete-word)
2091 ;; shift-tab going backward is kind of standard
2092 (define-key Info-mode-map [(shift iso-lefttab)] 'Info-prev-reference)
2093
2094 ;; (define-key global-map [(control x) (control a)] 'auto-fill-mode)
2095
2096 ;; Put back my keys, you thief!
2097 (define-key global-map [(home)] 'beginning-of-buffer)
2098 (define-key global-map [(end)] 'end-of-buffer)
2099 ;; (define-key global-map [(insertchar)] 'overwrite-mode)
2100 (define-key global-map [(delete)] 'delete-char)
2101
2102 ;; Cool shortcuts to move to the end / beginning of block keen
2103 (define-key global-map [(control right)] 'forward-sexp)
2104 (define-key global-map [(control left)] 'backward-sexp)
2105
2106 ;; Wheel mouse moves up and down 2 lines (and DO NOT BEEP when we are
2107 ;; out of the buffer)
2108
2109 (define-key global-map [mouse-4]
2110   (lambda () (interactive) (condition-case nil (scroll-down 2) (error nil))))
2111 (define-key global-map [mouse-5]
2112   (lambda () (interactive) (condition-case nil (scroll-up 2) (error nil))))
2113
2114 ;; with shift it goes faster
2115 (define-key global-map [(shift mouse-4)]
2116   (lambda () (interactive) (condition-case nil (scroll-down 50) (error nil))))
2117 (define-key global-map [(shift mouse-5)]
2118   (lambda () (interactive) (condition-case nil (scroll-up 50) (error nil))))
2119
2120 ;; Meta-? shows the properties of the character at point
2121 (define-key global-map [(meta ??)]
2122   (lambda () (interactive)
2123     (message (prin1-to-string (text-properties-at (point))))))
2124
2125 ;; Compiles the latex file in the current buffer
2126
2127 (setq tex-start-commands "\\input")
2128 (define-key global-map [f3] 'tex-file)
2129 (define-key global-map [(shift f3)] 'tex-bibtex-file)
2130
2131 ;; To run xdvi on the dvi associated to the .tex in the current
2132 ;; buffer, and to edit the .fig or bitmap image used to generate the
2133 ;; .eps at point
2134
2135 (define-key global-map [f4] 'ff/run-viewer)
2136
2137 ;; Closes the current \begin{}
2138
2139 ;; Meta-/ remaped (completion)
2140
2141 (define-key global-map [(shift right)] 'dabbrev-expand)
2142 (define-key global-map [(meta =)] 'dabbrev-expand)
2143
2144 ;; Change the current window.
2145
2146 (defun ff/next-same-frame-window () (interactive)
2147        (select-window (next-window (selected-window)
2148                                    (> (minibuffer-depth) 0)
2149                                    nil)))
2150
2151 (defun ff/previous-same-frame-window () (interactive)
2152        (select-window (previous-window (selected-window)
2153                                        (> (minibuffer-depth) 0)
2154                                        nil)))
2155
2156 (define-key global-map [(shift prior)] 'ff/next-same-frame-window)
2157 (define-key global-map [(shift next)] 'ff/previous-same-frame-window)
2158
2159 (define-key global-map [(control })] 'enlarge-window-horizontally)
2160 (define-key global-map [(control {)] 'shrink-window-horizontally)
2161 (define-key global-map [(control \")] 'enlarge-window)
2162 (define-key global-map [(control :)] 'shrink-window)
2163
2164 ;; (define-key global-map [(control shift prior)] 'next-multiframe-window)
2165 ;; (define-key global-map [(control shift next)] 'previous-multiframe-window)
2166
2167 ;; I have two screens sometime!
2168 ;; (define-key global-map [(meta next)] 'other-frame)
2169 ;; (define-key global-map [(meta prior)] (lambda () (interactive) (other-frame -1)))
2170
2171 ;; (load "winner")
2172 (winner-mode 1)
2173 ;; (define-key global-map [(shift backspace)] 'winner-undo)
2174
2175 ;; (define-key global-map [(shift home)] 'delete-other-windows-vertically)
2176 ;; (define-key global-map [(control +)] 'enlarge-window)
2177 ;; (define-key global-map [(control -)] 'shrink-window)
2178 ;; Goes to next/previous buffer
2179 ;; (define-key global-map [(control prior)] 'ff/next-buffer)
2180 ;; (define-key global-map [(control next)] 'ff/prev-buffer)
2181
2182 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2183 ;; If M-. on a symbol, show where it is defined in another window
2184 ;; without giving focus, cycle if repeated.
2185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2186
2187 (when (ff/load-or-alert "etags")
2188
2189   (defun ff/find-tag-nofocus () (interactive)
2190          "Show in another window the definition of the current tag"
2191          (let ((tag (find-tag-default)))
2192            (display-buffer (find-tag-noselect tag (string= tag last-tag)))
2193            (message "Tag %s" tag)
2194            )
2195          )
2196
2197   (define-key global-map [(meta .)] 'ff/find-tag-nofocus)
2198   )
2199
2200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2201 ;; Destroys the current buffer and its window if it's not the only one
2202 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2203
2204 (defcustom ff/kill-this-buffer-and-delete-window-exceptions ""
2205   "*Regexp matching the buffer names which have to be kept when using
2206 `ff/kill-this-buffer-and-delete-window'.")
2207
2208 (defun ff/kill-this-buffer-and-delete-window (universal)
2209   "Unless its name matches
2210 `ff/kill-this-buffer-and-delete-window-exceptions', kills the
2211 current buffer and deletes the current window if it's not the
2212 only one in the frame. If the buffer has to be kept, go to the
2213 next one. With universal argument, kill all killable buffers."
2214   (interactive "P")
2215   (if universal
2216       (let ((nb-killed 0))
2217         (mapc (lambda (x)
2218                 (unless (string-match ff/kill-this-buffer-and-delete-window-exceptions
2219                                       (buffer-name x))
2220                   (kill-buffer x)
2221                   (setq nb-killed (1+ nb-killed))
2222                   ))
2223               (buffer-list))
2224         (message "Killed %d buffer%s" nb-killed (if (> nb-killed 1) "s" "")))
2225     (if (string-match ff/kill-this-buffer-and-delete-window-exceptions (buffer-name))
2226         (ff/next-buffer)
2227       (kill-this-buffer)))
2228   (unless (one-window-p t) (delete-window))
2229   )
2230
2231 (define-key global-map [(control backspace)] 'ff/kill-this-buffer-and-delete-window)
2232 ;; (define-key calc-mode-map [(control backspace)] 'calc-quit)
2233
2234
2235 (setq ff/kill-this-buffer-and-delete-window-exceptions
2236       "^ \\|\\*Messages\\*\\|\\*scratch\\*\\|\\*Group\\*\\|\\*-jabber-\\*\\|\\*-jabber-process-\\*\\|\\*media\\*")
2237
2238 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2239 ;; Misc stuff
2240 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2241
2242 (defun ff/elisp-debug-on ()
2243   "Switches `debug-on-error' and `debug-on-quit'."
2244   (interactive)
2245   (if debug-on-error
2246       (setq debug-on-error nil
2247             debug-on-quit nil)
2248     (setq debug-on-error t
2249           debug-on-quit t))
2250   (if debug-on-error
2251       (message "elisp debug on")
2252     (message "elisp debug off")))
2253
2254 (defun ff/create-dummy-buffer (&optional universal) (interactive "P")
2255        (find-file (concat "/tmp/" (ff/non-existing-filename "/tmp/" "dummy" "")))
2256        (text-mode)
2257        (if universal (ff/insert-url (current-kill 0)))
2258        (message "New dummy text-mode buffer"))
2259
2260 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2261 ;; Recentf to keep a list of recently visited files. I use it
2262 ;; exclusively with my selector.el
2263 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2264
2265 (load "recentf")
2266
2267 ;; If we just check for file-symlink-p, everytime we start emacs it
2268 ;; will check all the remote files listed in recentf-list, so we check
2269 ;; that they are not remote first
2270 (defun ff/file-not-remote-but-symlink (filename)
2271   (and (not (file-remote-p filename)) (file-symlink-p filename)))
2272
2273 (setq recentf-exclude (append recentf-exclude
2274                               '(
2275                                 ff/file-not-remote-but-symlink
2276                                 "enotes$" "secure-notes$" "media-playlists$"
2277                                 "bbdb$"
2278                                 "svn-commit.tmp$" ".git/COMMIT_EDITMSG$"
2279                                 "\.bbl$" "\.aux$" "\.toc$"
2280                                 ))
2281       recentf-max-saved-items 1000
2282       recentf-save-file (concat ff/emacs-dir "/recentf")
2283       )
2284
2285 (when (boundp 'recentf-keep) (add-to-list 'recentf-keep 'file-remote-p))
2286
2287 (recentf-mode 1)
2288
2289 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2290 ;; My front-end to mplayer
2291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2292
2293 ;; (ff/compile-when-needed "media/mplayer")
2294 ;; (ff/compile-when-needed "media")
2295
2296 (when (ff/load-or-alert "media")
2297
2298   (unless window-system
2299     (ff/configure-faces
2300      '(
2301        (media/mode-string-face
2302         :foreground "blue4" :weight 'bold)
2303
2304        (media/current-tune-face
2305         :foreground "black" :background "yellow" :weight 'normal)
2306
2307        (media/instant-highlight-face
2308         :foreground "black" :background "orange" :weight 'normal)
2309        ))
2310     )
2311
2312   (define-key global-map [(meta \\)] 'media)
2313
2314   (setq media/expert t
2315         media/add-current-song-to-interrupted-when-killing t
2316         media/duration-to-history 30
2317         media/history-size 1000
2318         media/playlist-file (concat ff/emacs-dir "/media-playlists")
2319         media/mplayer/args '(
2320                              "-framedrop"
2321                              "-zoom"
2322                              "-cache" "512"
2323                              "-subfont-osd-scale" "3"
2324                              ;; "-stop-xscreensaver"
2325                              ;; "-osdlevel" "3"
2326                              )
2327         media/mplayer/timing-request-period 1.0
2328         )
2329   )
2330
2331 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2332 ;; A dynamic search
2333 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2334
2335 ;; selector.el is one of my own scripts, check my web page
2336
2337 (when (ff/load-or-alert "selector" t)
2338   ;; (define-key global-map [(shift return)] 'selector/quick-move-in-buffer)
2339   (define-key global-map [(control x) (control b)] 'selector/switch-buffer)
2340
2341   (defun ff/visit-debpkg-file (&optional regexp)
2342     "This function lists all the files found with dpkg -S and
2343 proposes to visit them."
2344     (interactive "sPattern: ")
2345
2346     (selector/select
2347
2348      (mapcar
2349       (lambda (s)
2350         (cons (selector/filename-to-string s) s))
2351       (split-string
2352        (shell-command-to-string (concat "dpkg -S " regexp " | awk '{print $2}'"))))
2353
2354      'selector/find-file
2355      "*selector find-file*"
2356      ))
2357   )
2358
2359 (add-hook 'selector/mode-hook (lambda () (setq truncate-lines t)))
2360
2361 (defun ff/selector-insert-record-callback (r)
2362   (bbdb-display-records (list r))
2363   ;; Weird things will happen if you kill the buffer from which you
2364   ;; invoked ff/selector-mail-from-bbdb
2365   (insert (car (elt r 6)))
2366   )
2367
2368 (defun ff/selector-compose-mail-callback (r)
2369   (vm-compose-mail (car (elt r 6)))
2370   )
2371
2372 (defun ff/selector-mail-from-bbdb () (interactive)
2373        (selector/select
2374         (mapcar
2375          (lambda (r) (cons (concat (elt r 0)
2376                                    " "
2377                                    (elt r 1)
2378                                    " ("
2379                                    (car (elt r 6))
2380                                    ")")
2381                            r))
2382          (bbdb-records))
2383         (if (string= mode-name "Mail")
2384             'ff/selector-insert-record-callback
2385           'ff/selector-compose-mail-callback)
2386         "*bbdb-search*"
2387         )
2388        )
2389
2390 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2391 ;; My script to automatically count the number of words and characters
2392 ;; between two markers
2393
2394 (ff/load-or-alert "text-counters.el")
2395
2396 ;; Display them in the modeline when in text-mode
2397
2398 (add-hook 'text-mode-hook 'tc/add-text-counters-in-modeline)
2399
2400 ;; (add-hook 'text-mode-hook
2401 ;; (lambda ()
2402 ;; (setq comment-start " > ")))
2403
2404 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2405 ;; A function to remove temporary alarm windows
2406 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2407
2408 (defcustom ff/annoying-windows-regexp
2409   "\\*Messages\\*\\|\\*compilation\\*\\|\\*tex-shell\\*\\|\\*Help\\*\\|\\*info\\*\\|\\*Apropos\\*\\|\\*BBDB\\*\\|\\*.*-diff\\*"
2410   "The regexp matching the windows to be deleted by `ff/delete-annoying-windows'"
2411   )
2412
2413 (defun ff/delete-annoying-windows ()
2414   "Close all the windows showing buffers whose names match
2415 `ff/annoying-windows-regexp'."
2416   (interactive)
2417   (when ff/annoying-windows-regexp
2418     (mapc (lambda (w)
2419             (when (and (not (one-window-p w))
2420                        (string-match ff/annoying-windows-regexp
2421                                      (buffer-name (window-buffer w))))
2422               (delete-window w)))
2423           (window-list)
2424           )
2425     (message "Removed annoying windows")
2426     )
2427   )
2428
2429 (setq ff/annoying-windows-regexp
2430       (concat ff/annoying-windows-regexp
2431               "\\|\\*unspooled mails\\*\\|\\*enotes alarms\\*\\|\\*system info\\*"))
2432
2433 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2434 ;; Some handy functions
2435 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2436
2437 (defun ff/twin-horizontal-current-buffer () (interactive)
2438        (delete-other-windows)
2439        (split-window-horizontally)
2440        (balance-windows)
2441        )
2442
2443 (defun ff/twin-vertical-current-buffer () (interactive)
2444        (delete-other-windows)
2445        (split-window-vertically)
2446        (balance-windows)
2447        )
2448
2449 (defun ff/flyspell-mode (arg) (interactive "p")
2450        (if flyspell-mode (flyspell-mode -1)
2451          (flyspell-mode 1)
2452          (flyspell-buffer))
2453        )
2454
2455 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2456 ;; The fridge!
2457 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2458
2459 (defun ff/move-region-to-fridge () (interactive)
2460        "Cut the current region, paste it in a file called ./fridge
2461 with a time tag, and save this file"
2462        (unless (use-region-p) (error "No region selected"))
2463        (let ((bn (file-name-nondirectory (buffer-file-name))))
2464          (kill-region (region-beginning) (region-end))
2465          (with-current-buffer (find-file-noselect "fridge")
2466            (goto-char (point-max))
2467            (insert "\n")
2468            (insert "######################################################################\n")
2469            (insert "\n"
2470                    (format-time-string "%Y %b %d %H:%M:%S" (current-time))
2471                    " (from "
2472                    bn
2473                    ")\n\n")
2474            (yank)
2475            (save-buffer)
2476            (message "Region moved to fridge")
2477            )
2478          )
2479        )
2480
2481 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2482 ;; My own keymap mapped to C-`
2483 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2484
2485 (setq ff/map (make-sparse-keymap))
2486 (define-key global-map [(control \`)] ff/map)
2487
2488 (unless window-system
2489   ;; (define-key global-map [(control @)] ff/map)
2490   (define-key global-map [(meta O) \`] ff/map)
2491   )
2492
2493 (define-key esc-map "`" ff/map)
2494
2495 (defun ff/git-status (&optional dir) (interactive)
2496        (if (buffer-file-name)
2497            (git-status (file-name-directory (buffer-file-name)))
2498          (error "No file attached to this buffer")))
2499
2500 (defun ff/insert-date (&optional universal) (interactive "P")
2501        ;; (insert (format-time-string "\n * %Y %b %d %H:%M:%S\n\n" (current-time)))
2502        ;; (insert (format-time-string "%Y %b %d %H:%M:%S" (current-time)))
2503        ;; (insert (format-time-string "%d.%m.%y" (current-time)))
2504        (if universal
2505            (insert (format-time-string "%d.%m.%Y %H:%M:%S" (current-time)))
2506          (insert (format-time-string "%d.%m.%Y" (current-time))))
2507        )
2508
2509 (define-key ff/map [(control g)] 'ff/git-status)
2510 (define-key ff/map [(control w)] 'server-edit)
2511 (define-key ff/map [(control d)] 'ff/elisp-debug-on)
2512 ;; (define-key ff/map "d" 'diary)
2513 (define-key ff/map "d" 'ff/insert-date)
2514 (define-key ff/map [(control \`)] 'ff/bash-new-buffer)
2515 (define-key ff/map [(control n)] 'enotes/show-all-notes)
2516 (define-key ff/map [(control s)] 'ff/secure-note-add)
2517 (define-key ff/map [(control t)] 'ff/start-test-code)
2518 (define-key ff/map [(control q)] 'ff/create-dummy-buffer)
2519 (define-key ff/map [(control a)] 'auto-fill-mode)
2520 (define-key ff/map [(control i)] 'ff/system-info)
2521 (define-key ff/map "w" 'ff/word-occurences)
2522 (define-key ff/map [(control c)] 'calendar)
2523 ;; (define-key ff/map [(control c)] (lambda () (interactive) (save-excursion (calendar))))
2524 (define-key ff/map [(control l)] 'goto-line)
2525 (define-key ff/map "l" 'longlines-mode)
2526 (define-key ff/map [(control o)] 'selector/quick-pick-recent)
2527 (define-key ff/map "s" 'selector/quick-move-in-buffer)
2528 (define-key ff/map "S" 'selector/search-sentence)
2529 (define-key ff/map "t" (lambda () (interactive) (find-file "~/private/TODO.txt")))
2530 (define-key ff/map "h" 'ff/tidy-html)
2531 (define-key ff/map "c" 'ff/count-char)
2532 (define-key ff/map [(control p)] 'ff/print-to-file)
2533 (define-key ff/map "P" 'ff/print-to-printer)
2534 (define-key ff/map [(control b)] 'bbdb)
2535 (define-key ff/map "m" 'ff/selector-mail-from-bbdb)
2536 (define-key ff/map [(control m)] 'woman)
2537 (define-key ff/map "b" 'bookmark-jump)
2538 (define-key ff/map [(control =)] 'calc)
2539 (define-key ff/map [(control shift b)]
2540   (lambda () (interactive)
2541     (bookmark-set)
2542     (bookmark-save)))
2543 (define-key ff/map "f" 'ff/move-region-to-fridge)
2544 (define-key ff/map [(control f)] 'ff/flyspell-mode)
2545
2546 (define-key ff/map [?\C-0] 'ff/delete-annoying-windows)
2547 (define-key ff/map "1" 'delete-other-windows)
2548 (define-key ff/map [?\C-1] 'delete-other-windows)
2549 (define-key ff/map "2" 'ff/twin-vertical-current-buffer)
2550 (define-key ff/map [?\C-2] 'ff/twin-vertical-current-buffer)
2551 (define-key ff/map "3" 'ff/twin-horizontal-current-buffer)
2552 (define-key ff/map [?\C-3] 'ff/twin-horizontal-current-buffer)
2553
2554 (define-key ff/map " " 'delete-trailing-whitespace)
2555
2556 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2557 ;; Hacks so that all keys are functionnal in xterm and through ssh.
2558 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2559
2560 (unless window-system
2561
2562   ;; One day I will understand these clipboard business. Until then,
2563   ;; so that it works in xterm (yes), let's use xclip. This is a bit
2564   ;; ugly.
2565
2566   ;; (defun ff/yank-with-xclip (&optional arg)
2567   ;; "Paste the content of the X clipboard with the xclip
2568   ;; command. Without ARG converts some of the '\\uxxxx' characters."
2569   ;; (interactive "P")
2570   ;; (with-temp-buffer
2571   ;; (shell-command "xclip -o" t)
2572   ;; (unless arg
2573   ;; (mapc (lambda (x) (replace-string (concat "\\u" (car x)) (cdr x) nil (point-min) (point-max)))
2574   ;; '(("fffd" . "??")
2575   ;; ("2013" . "-")
2576   ;; ("2014" . "--")
2577   ;; ("2018" . "`")
2578   ;; ("2019" . "'")
2579   ;; ("201c" . "``")
2580   ;; ("201d" . "''")
2581   ;; ("2022" . "*")
2582   ;; ("2026" . "...")
2583   ;; ("20ac" . "EUR")
2584   ;; )))
2585   ;; (kill-ring-save (point-min) (point-max)))
2586
2587   ;; (yank))
2588
2589   ;; (define-key global-map [(meta y)] 'ff/yank-with-xclip)
2590
2591   ;;   (set-terminal-coding-system 'iso-latin-1)
2592   ;; (set-terminal-coding-system 'utf-8)
2593
2594   ;; I have in my .Xressource
2595
2596   ;; XTerm.VT100.translations: #override\n\
2597   ;;   <Btn4Down>,<Btn4Up>:scroll-back(2,line)\n\
2598   ;;   <Btn5Down>,<Btn5Up>:scroll-forw(2,line)\n\
2599   ;;   Ctrl<Btn4Down>,Ctrl<Btn4Up>:scroll-back(1,page)\n\
2600   ;;   Ctrl<Btn5Down>,Ctrl<Btn5Up>:scroll-forw(1,page)\n\
2601   ;;   Shift<Btn4Down>,Shift<Btn4Up>:scroll-back(1,halfpage)\n\
2602   ;;   Shift<Btn5Down>,Shift<Btn5Up>:scroll-forw(1,halfpage)\n\
2603   ;;   Alt<KeyPress>:insert-eight-bit()\n\
2604   ;;   !Shift<Key>BackSpace: string("\7f")\n\
2605   ;;   Ctrl<Key>BackSpace: string("\eOZ")\n\
2606   ;;   Shift<Key>Prior: string("\e[5;2~")\n\
2607   ;;   Shift<Key>Next: string("\e[6;2~")\n\
2608   ;;   Shift Ctrl<Key>]: string("\eO}")\n\
2609   ;;   Shift Ctrl<Key>[: string("\eO{")\n\
2610   ;;   Shift Ctrl<Key>/: string("\eO?")\n\
2611   ;;   Ctrl<Key>/: string("\eO/")\n\
2612   ;;   Shift Ctrl<Key>=: string("\eO+")\n\
2613   ;;   Ctrl<Key>=: string("\eO=")\n\
2614   ;;   Shift Ctrl<Key>;: string("\eO:")\n\
2615   ;;   Ctrl<Key>;: string("\eO;")\n\
2616   ;;   Shift Ctrl<Key>`: string("\eO~")\n\
2617   ;;   Ctrl<Key>`: string("\eO`")\n\
2618   ;;   Shift Ctrl<Key>': string("\eO\\\"")\n\
2619   ;;   Ctrl<Key>': string("\eO'")\n\
2620   ;;   Shift Ctrl<Key>.: string("\eO>")\n\
2621   ;;   Ctrl<Key>.: string("\eO.")\n\
2622   ;;   Shift Ctrl<Key>\\,: string("\eO<")\n\
2623   ;;   Ctrl<Key>\\,: string("\eO,")
2624
2625   (define-key function-key-map "\e[2~" [insert])
2626
2627   (define-key function-key-map "\e[Z" [S-iso-lefttab])
2628
2629   (define-key function-key-map "\e[1;2A" [S-up])
2630   (define-key function-key-map "\e[1;2B" [S-down])
2631   (define-key function-key-map "\e[1;2C" [S-right])
2632   (define-key function-key-map "\e[1;2D" [S-left])
2633   (define-key function-key-map "\e[1;2F" [S-end])
2634   (define-key function-key-map "\e[1;2H" [S-home])
2635
2636   (define-key function-key-map "\e[2;2~" [S-insert])
2637   (define-key function-key-map "\e[5;2~" [S-prior])
2638   (define-key function-key-map "\e[6;2~" [S-next])
2639
2640   (define-key function-key-map "\e[1;2P" [S-f1])
2641   (define-key function-key-map "\e[1;2Q" [S-f2])
2642   (define-key function-key-map "\e[1;2R" [S-f3])
2643   (define-key function-key-map "\e[1;2S" [S-f4])
2644   (define-key function-key-map "\e[15;2~" [S-f5])
2645   (define-key function-key-map "\e[17;2~" [S-f6])
2646   (define-key function-key-map "\e[18;2~" [S-f7])
2647   (define-key function-key-map "\e[19;2~" [S-f8])
2648   (define-key function-key-map "\e[20;2~" [S-f9])
2649   (define-key function-key-map "\e[21;2~" [S-f10])
2650
2651   (define-key function-key-map "\e[1;5A" [C-up])
2652   (define-key function-key-map "\e[1;5B" [C-down])
2653   (define-key function-key-map "\e[1;5C" [C-right])
2654   (define-key function-key-map "\e[1;5D" [C-left])
2655   (define-key function-key-map "\e[1;5F" [C-end])
2656   (define-key function-key-map "\e[1;5H" [C-home])
2657
2658   (define-key function-key-map "\e[2;5~" [C-insert])
2659   (define-key function-key-map "\e[5;5~" [C-prior])
2660   (define-key function-key-map "\e[6;5~" [C-next])
2661
2662   (define-key function-key-map "\e[1;9A" [M-up])
2663   (define-key function-key-map "\e[1;9B" [M-down])
2664   (define-key function-key-map "\e[1;9C" [M-right])
2665   (define-key function-key-map "\e[1;9D" [M-left])
2666   (define-key function-key-map "\e[1;9F" [M-end])
2667   (define-key function-key-map "\e[1;9H" [M-home])
2668
2669   (define-key function-key-map "\e[2;9~" [M-insert])
2670   (define-key function-key-map "\e[5;9~" [M-prior])
2671   (define-key function-key-map "\e[6;9~" [M-next])
2672
2673   ;; The following ones are not standard
2674
2675   (define-key function-key-map "\eO}" (kbd "C-}"))
2676   (define-key function-key-map "\eO{" (kbd "C-{"))
2677   (define-key function-key-map "\eO?" (kbd "C-?"))
2678   (define-key function-key-map "\eO/" (kbd "C-/"))
2679   (define-key function-key-map "\eO:" (kbd "C-:"))
2680   (define-key function-key-map "\eO;" (kbd "C-;"))
2681   (define-key function-key-map "\eO~" (kbd "C-~"))
2682   (define-key function-key-map "\eO`" (kbd "C-\`"))
2683   (define-key function-key-map "\eO\"" (kbd "C-\""))
2684   (define-key function-key-map "\eO|" (kbd "C-|"))
2685   (define-key function-key-map "\eO'" (kbd "C-'"))
2686   (define-key function-key-map "\eO>" (kbd "C->"))
2687   (define-key function-key-map "\eO." (kbd "C-."))
2688   (define-key function-key-map "\eO<" (kbd "C-<"))
2689   (define-key function-key-map "\eO," (kbd "C-,"))
2690   (define-key function-key-map "\eO-" (kbd "C--"))
2691   (define-key function-key-map "\eO=" (kbd "C-="))
2692   (define-key function-key-map "\eO+" (kbd "C-+"))
2693
2694   (define-key function-key-map "\eOZ" [C-backspace])
2695
2696   (define-key minibuffer-local-map "\10" 'previous-history-element)
2697   (define-key minibuffer-local-map "\ e" 'next-history-element)
2698
2699   ;; (define-key global-map [(alt prior)] 'ff/prev-buffer)
2700   ;; (define-key global-map [(alt next)] 'ff/next-buffer)
2701
2702   )
2703
2704 ;; I am fed up with Alt-Backspace in the minibuffer erasing the
2705 ;; content of the kill-ring
2706
2707 (defun ff/backward-delete-word (arg)
2708   "Delete characters forward until encountering the end of a word, but do not put them in the kill ring.
2709 With argument ARG, do this that many times."
2710   (interactive "p")
2711   (delete-region (point) (progn (forward-word (- arg)) (point))))
2712
2713 (define-key minibuffer-local-map
2714   [remap backward-kill-word] 'ff/backward-delete-word)
2715
2716 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2717 ;; Privacy
2718 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2719
2720 ;; Where to save the bookmarks and where is bbdb
2721
2722 (setq bookmark-default-file (concat ff/emacs-dir "/bmk")
2723       bbdb-file "~/private/bbdb"
2724       custom-file (concat ff/emacs-dir "/custom"))
2725
2726 ;; enotes.el is one of my own scripts, check my web page
2727
2728 (when (ff/load-or-alert "enotes" t)
2729   (setq enotes/file "~/private/enotes"
2730         enotes/show-help nil
2731         enotes/full-display nil
2732         enotes/default-time-fields "9:30")
2733
2734   (enotes/init)
2735   ;; (add-hook 'enotes/alarm-hook
2736   ;;  (lambda () (ff/play-sound-async "~/local/sounds/three_notes2.wav")))
2737   )
2738
2739 ;; (when (ff/load-or-alert "goto-last-change.el")
2740 ;; (define-key global-map [(control x) (control a)] 'goto-last-change))
2741
2742 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2743 ;; My private stuff (email adresses, mail filters, etc.)
2744 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2745
2746 (ff/load-or-alert "~/private/emacs.perso.el" t)
2747
2748 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2749 ;; emacs server
2750 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2751
2752 ;; Runs in server mode, so that emacsclient works
2753 (server-start)
2754
2755 (defun ff/raise-frame-and-give-focus ()
2756   (when window-system
2757     (raise-frame)
2758     (x-focus-frame (selected-frame))
2759     (set-mouse-pixel-position (selected-frame) 4 4)
2760     ))
2761
2762 ;; Raises the window when the server is invoked
2763
2764 (add-hook 'server-switch-hook 'ff/raise-frame-and-give-focus)