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