Archive for the 'Emacs' Category

Emacs quoted insert

Good morning folks out there,

I’ve got another neat little feature of emacs for you today, it’s called quoted insert.
I stumbled on this, because I use spaces for code indentation in my emacs, but I needed to insert an actual TAB character.
So, in this situation, the combination C-q <TAB> is the way to go, which interprets the next typed character in a quoted fashion.

Also, refer to this link for further reading.

Start Emacs with GDB directly

Hey folks out there,

as we all know, Emacs has a very powerful (graphical) interface to our beloved debugger GDB. Until five minutes ago, I used to start a program in debug mode by first starting emacs and then invoking M-x gdb, which can take a long time to navigate to the desired binary. Furthermore, the directory where the binary resides isn’t the actual runtime-path in many cases. Fortunately, Emacs can be started in GDB-mode directly, by calling it with the --eval parameter on the command-line. What we want to evaluate during startup is the (gdb) function. Its only parameter is a string describing how gdb should be invoked. Thus, we can write the following bash function:

debug () {
    emacs --eval "(gdb \"gdb --annotate=3 --cd=`pwd` $*\")" &
}

Here, the --annotate option tells gdb to generate annotations that can be interpreted by the Emacs gdb interface (the integer argument is the annotation-level). Furthermore, the --cd parameter instructs gdb to change its working dir to the specified one, which is the current working dir in our case. Thus we can call debug ./bin/prog, for instance.

dot.emacs

This is my .emacs file

Download it .emacs or preview:

;; ##############################################################################
;; Frank Meffert's .emacs file
;; 2010-10-02: Beautifying a bit
;; ##############################################################################
 
;; ------------------------------------------------------------------ (load path)
(add-to-list 'load-path "~/.emacs.d/")
 
;; ------------------------------------------------------------------- (ido mode)
(require 'ido)
(ido-mode 1)
 
;; --------------------------------------------------------------- (line numbers)
(require 'linum)
(global-linum-mode 1)
(setq linum-ncols 4)
(setq linum-format (concat "%" (number-to-string linum-ncols) "d"))
 
;; -------------------------------------------------------------------- (tab bar)
(require 'tabbar)
(tabbar-mode)
(setq tabbar-buffer-groups-function
	  (lambda ()
		(list "All")))
(global-set-key [M-left] 'tabbar-backward)
(global-set-key [M-right] 'tabbar-forward)
 
(defun cur-buf-name ()
  "Get the name of the current buffer"
  (interactive)
  (buffer-name (current-buffer)))
 
(setq buf-name-rpl
	  '(("*Completions*" . "Completions")
		("cv.html" . "curricvitae")
		("foo.h" . "_FOO_H_")))
 
(defun rename-cur-buf ()
  "Renames the current buffer, if replacement is available in local list"
  (interactive)
  (let ((rpl (cdr (assoc (cur-buf-name) buf-name-rpl))))
	(if rpl
		(rename-buffer rpl))))
(add-hook 'find-file-hook 'rename-cur-buf)
 
;; (defun initial-rename ()
;;   (mapcar #'(lambda (buf)
;; 			  ()
 
;; --------------------------------------------------------------------- (col 80)
;; marks characters beyond column 80. Seriously: I need a solid line!
;(require 'column-marker)
;(add-hook 'foo-mode-hook (lambda () (interactive) (column-marker-1 80)))
 
;; ------------------------------------------------------------ (backup behavior)
;; do not make any backup files, because they suck!
(setq make-backup-files nil)
 
;; ------------------------------------------------------------------- (Doxymacs)
(require 'doxymacs)
(add-hook 'c-mode-common-hook'doxymacs-mode)
 
(setq doxymacs-file-comment-template
 '("/**" > n
   " * " (doxymacs-doxygen-command-char) "file   "
   (if (buffer-file-name)
       (file-name-nondirectory (buffer-file-name))
       "") > n
   " * " (doxymacs-doxygen-command-char) "author " (user-full-name) (doxymacs-user-mail-address) > n
   " * " (doxymacs-doxygen-command-char) "date   " (format-time-string "%A, %B %e, %Y") > n
   " * " > n
   " * " (doxymacs-doxygen-command-char) "brief  " > n
   " * " > n
   " */" > n))
 
(defun my-javadoc-return () 
  "Advanced C-m for Javadoc multiline comments.
   Inserts `*' at the beggining of the new line if 
   unless return was pressed outside the comment"
  (interactive)
  (setq last (point))
  (setq is-inside
	(if (search-backward "*/" nil t)
	  ;; there are some comment endings - search forward
	  (if (search-forward "/*" last t)
		't
	    'nil)
	  ;; it's the only comment - search backward
	  (goto-char last)
	  (if (search-backward "/*" nil t)
	    't
	    'nil)))
  ;; go to last char position
  (goto-char last)
  ;; the point is inside some comment, insert `*'
  (if is-inside
    (progn 
	  (insert "\n* ")
	  (indent-for-tab-command))
    ;; else insert only new-line
    (insert "\n")))
 
(add-hook 'c-mode-common-hook (lambda () 
  (local-set-key "\r" 'my-javadoc-return)))
 
;; ----------------------------------------------------------------- (Smart-HOME)
(defun smart-beginning-of-line ()
  "Forces the cursor to jump to the first none whitespace char of the current line when pressing HOME"
  (interactive)
  (let ((oldpos (point)))
    (back-to-indentation)
    (and (= oldpos (point))
         (beginning-of-line))))
(put 'smart-beginning-of-line 'CUA 'move)
(global-set-key [home] 'smart-beginning-of-line)
 
;; --------------------------------------------------- (resize window to 80 cols)
(defun win-eighty ()
  "Sets the width of the window to 80 columns"
  (interactive)
  (set-frame-height (selected-frame) (/ (- (x-display-pixel-height) 100) (frame-char-height)))
  (set-frame-width (selected-frame) (+ 81 linum-ncols)))
(add-hook 'after-init-hook 'win-eighty)
 
(defun win-dual ()
  "Splits the screen horizontally and sets the widthd of each window to 80 cols"
  (interactive)
  (set-frame-width (selected-frame) 175)
  (split-window-horizontally (+ 85 linum-ncols)))
 
;; ------------------------------------------------------- (custom set variables)
(custom-set-variables
  ;; custom-set-variables was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(column-number-mode t)
 '(user-full-name "Frank Meffert")
 '(user-mail-address "frank.meffert@gmail.com")
 '(cua-mode t nil (cua-base))
 '(custom-buffer-indent 4)
 '(delete-selection-mode nil)
 '(display-time-24hr-format t)
 '(display-time-day-and-date 1)
 '(display-time-mode t)
 '(global-font-lock-mode t nil (font-lock))
 '(inhibit-startup-buffer-menu t)
 '(inhibit-startup-screen t)
 '(pc-select-meta-moves-sexps t)
 '(pc-select-selection-keys-only t)
 '(pc-selection-mode t nil (pc-select))
 '(scroll-bar-mode (quote right))
 '(show-paren-mode t)
 '(standard-indent 4)
 '(uniquify-buffer-name-style (quote forward) nil (uniquify)))
 
;; ----------------------------------------------------------------------- (misc)
(setq-default tab-width 4)
(setq-default indent-tabs-mode t)
(setq c-basic-offset 4)
(setq frame-title-format (concat "Emacs <" user-login-name "@" system-name ">: <%b> %+%+ <%f>"))
 
;; Highlighting of the current line
(global-hl-line-mode 1)
(set-face-background 'hl-line "#E8F2FE")
(tool-bar-mode -1)
 
(defalias 'yes-or-no-p 'y-or-n-p)
(display-time)
(set-language-environment "Latin-1")
(put 'scroll-left 'disabled nil)
 
;; ---------------------------------------------------------- (LaF of the cursor)
;; Change cursor color according to mode
(setq djcb-read-only-color       "gray")
;; valid values are t, nil, box, hollow, bar, (bar . WIDTH), hbar,
;; (hbar. HEIGHT); see the docs for set-cursor-type
(setq djcb-read-only-cursor-type 'hbar)
(setq djcb-overwrite-color       "red")
(setq djcb-overwrite-cursor-type 'box)
(setq djcb-normal-color          "black")
(setq djcb-normal-cursor-type    'box)
 
;; ------------------------------------------------------------------------------
;; Helper functions
;; ------------------------------------------------------------------------------
(defun djcb-set-cursor-according-to-mode ()
  "change cursor color and type according to some minor modes."
  (cond
    (buffer-read-only
      (set-cursor-color djcb-read-only-color)
      (setq cursor-type djcb-read-only-cursor-type))
    (overwrite-mode
      (set-cursor-color djcb-overwrite-color)
      (setq cursor-type djcb-overwrite-cursor-type))
    (t 
      (set-cursor-color djcb-normal-color)
      (setq cursor-type djcb-normal-cursor-type))))
(add-hook 'post-command-hook 'djcb-set-cursor-according-to-mode)
 
(defun mouse-stay-and-copy (click)
  "leaves cursor at current position, allows to drag a region which 
is yanked at cursor position"
  (interactive "e")
  (let ((selected nil)
	(win (selected-window)))
    (save-excursion
      (mouse-drag-track click)
      (if mark-active
	  (progn (kill-new (buffer-substring (region-beginning) (region-end)))
		 (setq selected 1))))
    (select-window win)
    (if selected 
	(progn 
	  (if mark-active (delete-region (region-beginning) (region-end)))
	  (yank)
	  (redraw-display)))))
 
(defun mouse-stay-and-kill (click)
  "leaves cursor at current position, allows to drag a region which 
is moved to cursor position"
  (interactive "e")
  (let ((selected nil)
	(win (selected-window)))
    (save-excursion
      (mouse-drag-track click)
      (if mark-active 
	  (progn (kill-region (region-beginning) (region-end))
		 (setq selected t))))
    (select-window win)
    (if selected 
	(progn (if mark-active (delete-region (region-beginning) (region-end)))
	       (yank)
	       (redraw-display)))))
 
(defun mouse-stay-and-swap (click)
  "leaves cursor at current position, allows to drag a region which 
is swapped with the original selection"
  (interactive "e")
  (let ((selected nil)
	(win (selected-window))
	(obuf nil)
	(olen nil)
	(opos nil))
    (save-excursion
      (mouse-drag-track click)
      (if mark-active 
	  (progn (setq olen (- (region-end) (region-beginning)))
		 (kill-region (region-beginning) (region-end))
		 (setq obuf (current-buffer))
		 (setq opos (point))
		 (setq selected t))))
    (select-window win)
    (if selected
	(progn (if (and (eq obuf (current-buffer)) (> opos (point)))
		   (setq opos (+ opos olen 
				 (if mark-active (- (region-beginning) (region-end)) 0))))
	       (if mark-active
		   (kill-region (region-beginning) (region-end))
		 (kill-region (point) (point)))
	       (rotate-yank-pointer 1) (yank)
	       (set-buffer obuf) (goto-char opos)
	       (rotate-yank-pointer -1) (yank)
	       (redraw-display)))))
 
(defun mouse-yank-and-kill (click)
  "yanks selection at mouse click and kills original"
  (interactive "e")
  (if mark-active
      (let ((beg (region-beginning))
	    (end (region-end))
	    (pos (event-start click)))
	(kill-region beg end)
	(select-window (posn-window pos))
	(goto-char (posn-point pos))
	(yank))
    (mouse-set-point click)))
 
(defun my-query-replace (str1 str2)
  (interactive
   (let ((str (read-string "Query replace: " 
			   (if mark-active 
			       (let ((h (buffer-substring (point) (mark))))
				 (if (< (mark) (point)) (exchange-point-and-mark))
				 (kill-new h)
				 h)
			     ""))))
     (setq mark-active nil)
     (list str (read-string (format "Query replace: %s with: " str)))))
  (query-replace str1 str2 current-prefix-arg))
 
(defun my-query-replace-word (str1 str2)
  (interactive
   (let ((str (read-string "Query replace word: " 
			   (if mark-active 
			       (let ((h (buffer-substring (point) (mark))))
				 (if (< (mark) (point)) (exchange-point-and-mark))
				 (kill-new h)
				 (concat "\\<" (regexp-quote h) "\\>"))
			     ""))))
     (setq mark-active nil)
     (list str (read-string (format "Query replace word: %s with: " str)))))
  (query-replace-regexp str1 str2 current-prefix-arg))
 
(defun my-query-replace-regexp (str1 str2)
  (interactive
   (let ((str (read-string "Query replace regexp: " 
			   (if mark-active 
			       (let ((h (buffer-substring (point) (mark))))
				 (if (< (mark) (point)) (exchange-point-and-mark))
				 (kill-new h)
				 (regexp-quote h))
			     ""))))
     (setq mark-active nil)
     (list str (read-string (format "Query replace regexp: %s with: " str)))))
  (query-replace-regexp str1 str2 current-prefix-arg))
 
(defun convert-to-regexp-pattern (a o)
  (interactive "r")
  (let ((h (buffer-substring a o)))
    (delete-region a o)
    (insert (cond ((string-match "^\\s-+$" h) "\\(\\s-+\\)")
		  ((string-match "^[0-9]+$" h) "\\([0-9]+\\)")
		  ((string-match "^[A-Za-z_][0-9A-Za-z_]*$" h) "\\([A-Za-z_][0-9A-Za-z_]*\\)")
		  ((string-match "^\\S-+$" h) "\\(\\S-+\\)")
		  (t "\\(.+\\)")))))
 
;; ------------------------------------------------------------------------------
;; Key bindings
;; ------------------------------------------------------------------------------
(define-key global-map '[C-right] 'forward-sexp)
(define-key global-map '[C-left] 'backward-sexp)
(define-key global-map '[s-left] 'windmove-left)
(define-key global-map '[s-right] 'windmove-right)
(define-key global-map '[s-up] 'windmove-up)
(define-key global-map '[s-down] 'windmove-down)
(define-key global-map '[S-down-mouse-1] 'mouse-stay-and-copy)
(define-key global-map '[C-M-S-down-mouse-1] 'mouse-stay-and-swap)
(define-key global-map '[S-mouse-2] 'mouse-yank-and-kill)
(define-key global-map '[C-S-down-mouse-1] 'mouse-stay-and-kill)
;; replaced with windows key, see above
;;(define-key global-map '[M-down] (lambda () (interactive) (other-window 1)))
;;(define-key global-map '[M-up] (lambda () (interactive) (other-window -1)))
(define-key global-map "*"     'my-query-replace-regexp)
(define-key global-map "%"     'my-query-replace)
(define-key global-map "+"     'my-query-replace-word)
(define-key global-map "&"     'my-replace-string)
(define-key global-map "^" 'convert-to-regexp-pattern)
(define-key global-map "\C-a" 'mark-whole-buffer)
 
;; ------------------------------------------------------------------------------
;; Compilation
;; ------------------------------------------------------------------------------
(defvar current-compilation-buffer nil)
(define-key global-map "\215" 	;; META-RET; compile
  (lambda (prefix) (interactive "P")
    (condition-case nil (kill-compilation) (error nil))
    (if prefix (setq current-compilation-buffer (current-buffer)))
    (save-excursion 
      (set-buffer
       (if (buffer-live-p current-compilation-buffer)
           current-compilation-buffer (current-buffer)))
      (call-interactively 'compile))))
(define-key minibuffer-local-map "\215" 'exit-minibuffer)
(define-key minibuffer-local-map "#" 'minibuffer-keyboard-quit)
 
(define-key ctl-x-map  "." 
  '(lambda() (interactive)
     (condition-case nil (next-error 1)
       (error (condition-case nil (next-error 0) (error (next-error nil)))))))
 
(define-key ctl-x-map  "," 'previous-error)
 
;; ------------------------------------------------------------------------------
;; Debugger
;; ------------------------------------------------------------------------------
(defun gud-break-eval-cont (cmd)
  (interactive "sEnter command:")
  (comint-interrupt-subjob)
  (gud-basic-call cmd)
  (gud-cont nil))
 
(defun gud-gdb-reload ()
  (interactive)
  (let ((nm (buffer-name)))
    (if (string-match "^\\*...-\\(.+\\)\\*$" nm)
	(progn (gud-basic-call (format "file %s" (substring nm (match-beginning 1) (match-end 1))))
	(message "reloaded debugger file")))))
 
(setq gdb-mode-hook
      '((lambda ()
          (define-key gud-mode-map "s" 'gud-step)
          (define-key gud-mode-map '[f5] 'gud-step)
          (define-key gud-mode-map '[f6] 'gud-next)
          (define-key gud-mode-map '[f7] 'gud-finish)
          (define-key gud-mode-map '[f8] 'gud-cont)
          (define-key gud-mode-map '[f9] 'gud-up)
          (define-key gud-mode-map '[f10] 'gud-down)
 
          (define-key gud-mode-map "n" 'gud-next)
          (define-key gud-mode-map "k" 'gud-cont)
          (define-key gud-mode-map "e" 'gud-break-eval-cont)
          (define-key gud-mode-map "f" 'gud-finish)
          (define-key gud-mode-map "u" 'gud-up)
          (define-key gud-mode-map "d" 'gud-down)
          (define-key gud-mode-map "r" 'gud-gdb-reload)

Emacs + Doxygen = Doxymacs

doxymacs

In fact, most developers around the world probably dislike writing comments within their programs, no matter which language is considered. However, exhaustive code documentation improves the overall code quality, and thus also the software quality. Moreover, code documentation is essential in projects where teams with several people work on the same code base. Thus, the motivation to simplify the writing of comments/code documentation is very high, because the developer wants to focus on the essentials, namely the semantic and contents of the documentation and not any kind of syntax (/* ... */). Since the eclipse IDE has an inherent high comfort concerning auto-completion of javadoc and doxygen comments, I was a bit disappointed when I switched to emacs, because there is no such thing in emacs by default. Fortunately, there’s an emacs extension called Doxymacs, which can be obtained from this link.

Installation

If you are using ubuntu, then you’re lucky, since ubuntu has a dedicated package called doxymacs

Configuration and Usage

After successful installation, you should modify your ~/.emacs file to include doxymacs:

1
2
3
4
5
6
(require 'doxymacs)
(add-hook 'c-mode-common-hook 'doxymacs-mode)
(defun my-doxymacs-font-lock-hook ()
    (if (or (eq major-mode 'c-mode) (eq major-mode 'c++-mode))
        (doxymacs-font-lock)))
(add-hook 'font-lock-mode-hook 'my-doxymacs-font-lock-hook)

where the second line automatically activates doxymacs for the c-mode, which is most likely what you want. Furthermore, the function and its invocation in lines 3-6 enables pretty fontification for doxygen keywords (e.g. param)

The defaults key-bindings are as follows:

  • C-c d ? will look up documentation for the symbol under the point.
  • C-c d r will rescan your Doxygen tags file.
  • C-c d f will insert a Doxygen comment for the next function.
  • C-c d i will insert a Doxygen comment for the current file.
  • C-c d ; will insert a Doxygen comment for a member variable on the current line (likeĀ M-;).
  • C-c d m will insert a blank multi-line Doxygen comment.
  • C-c d s will insert a blank single-line Doxygen comment.
  • C-c d @ will insert grouping comments around the current region.

Additions

I found the following function that automatically inserts an asterisk (*) whenever one is hitting return within a multiline comment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(defun my-javadoc-return () 
  "Advanced C-m for Javadoc multiline comments.   
Inserts `*' at the beggining of the new line if 
unless return was pressed outside the comment"
  (interactive)
  (setq last (point))
  (setq is-inside
	(if (search-backward "*/" nil t)
	    ;; there are some comment endings - search forward
	    (if (search-forward "/*" last t)
		't
	      'nil)
	  ;; it's the only comment - search backward
	  (goto-char last)
	  (if (search-backward "/*" nil t)
	      't
	    'nil
	    )
	  )
	)
  ;; go to last char position
  (goto-char last)
  ;; the point is inside some comment, insert `*'
  (if is-inside
      (progn 
	(insert "\n*")
	(indent-for-tab-command))
    ;; else insert only new-line
    (insert "\n")))
(add-hook 'c++-mode-hook (lambda () 
  (local-set-key "\r" 'my-javadoc-return)))

Links