Bash prompt customizations

Some paths can be really long and annoying. Here's how you fix it.
NOTE: I am using 14.04. Your mileage may vary.

Reduce the size of the prompt

This simple trick checks if the length of the current directory path is greater than 30. In that case, it breaks it up into two chunks -- first 12 letters and the last 15.

__update_prompt1()                                                                                                                                                                     
{                                                                                                                                                                                     
   DIR=`pwd | sed -e "s!$HOME!~!"`                                                                                                                                                   
   if [ ${#DIR} -gt 30 ]; then                                                                                                                                                       
     CurDir=${DIR:0:12}....${DIR:${#DIR}-15}                                                                                                                                       
   else                                                                                                                                                                              
     CurDir=$DIR                                                                                                                                                                   
   fi                                                                                                                                                                                
} 

Before:
[user@hostname:/local/mnt/workspace/somefolder1/foldera/test]$
After:
[user@hostname:/local/mnt/w....a/test/]$


Personally, I like the one below. It replaces the folder names with a single letter.


__update_prompt2()                                                                                                                                                                    
{                                                                                                                                                                                     
    CurDir=`pwd | sed -e "s!$HOME!~!" | sed -re "s!([^/])[^/]+/!\1/!g"`                                                                                                               
} 

Before:
[user@hostname:/local/mnt/workspace/somefolder1/foldera/test]$
After:
[user@hostname:/l/m/w/s/f/test]$

All we need to do is update the PROMPT_COMMAND and PS1


PROMPT_COMMAND=__update_prompt2                                                                                                                                                       
export PROMPT_COMMAND=${PROMPT_COMMAND}                                                                                                                                                                                                                           
PS1='[\u@\h:${CurDir}]\$ '                                                                                                                                     
export PS1 

There is one other thing I like to do -- move the cursor to the newline
PS1='[\u@\h:${CurDir}]\n\$ '

The prompt looks like,

[user@hostname:/l/m/w/s/f/test]
$ ls


Adding git branch information to prompt along with git completion


First things first, download the git-completion.bash and git-prompt.sh files from https://github.com/git/git/tree/master/contrib/completion

Add these do the .bashrc


source ~/.git-completion.bash
source ~/.git-prompt.sh 

And finally, update the PS1

PS1='[\u@\h:${CurDir}]$(__git_ps1 " (%s)")\n\$ '

When the folder is a git repository it will automatically show the current git branch.

[user@hostname:/l/m/w/s/f/myrepo] (master)
$ ls -a
. .. .git hello 

You get git completion for free as well.

[user@hostname:/l/m/w/s/f/myrepo] (master)
$ git che [TAB]
check-mailmap   checkout        cherry          cherry-pick


Preserving the history across terminals



This can be done in three simple steps
  1. history -a : Append the new history lines (history lines entered since the beginning of the current Bash session) to the history file
  2. history -c : Clear the history list. This may be combined with the other options to replace the history list completely
  3. history -r : Read the history file and append its contents to the history list

Let's do this part of the PROMPT_COMMAND

PROMPT_COMMAND=__update_prompt2
export PROMPT_COMMAND="history -a; history -c; history -r; ${PROMPT_COMMAND}"

That's it!

[Vimdiff] cheat sheet

Sometimes I prefer using vimdiff especially when using it as a mergetool.  mattratleph has a handy cheatsheet.

git mergetool

In the middle file (future merged file), you can navigate between conflicts with ]c and [c.
Choose which version you want to keep with :diffget //2 or :diffget //3 (the //2 and //3 are unique identifiers for the target/master copy and the merge/branch copy file names).

:diffupdate (to remove leftover spacing issues)
:only (once you’re done reviewing all conflicts, this shows only the middle/merged file)
:wq (save and quit)
git add .
git commit -m “Merge resolved”

If you were trying to do a git pull when you ran into merge conflicts, type git rebase –continue.

vimdiff commands

]c :        - next difference
[c :        - previous difference
do          - diff obtain
dp          - diff put
zo          - open folded text
zc          - close folded text
:diffupdate - re-scan the files for differences
 

[Emacs] ediff marked files in dired

Found an awesome trick online to run ediff on marked files in dired.

(defun dired-ediff-marked-files ()
    "Run ediff on marked ediff files."
    (interactive)
    (set 'marked-files (dired-get-marked-files))
    (when (= (safe-length marked-files) 2)
        (ediff-files (nth 0 marked-files) (nth 1 marked-files)))

    (when (= (safe-length marked-files) 3)
        (ediff3 (buffer-file-name (nth 0 marked-files))
                (buffer-file-name (nth 1 marked-files))
                (buffer-file-name (nth 2 marked-files)))))


Another way (link)

(defun mkm/ediff-marked-pair ()
  "Run ediff-files on a pair of files marked in dired buffer"
  (interactive)
  (let* ((marked-files (dired-get-marked-files nil nil))
         (other-win (get-window-with-predicate
                     (lambda (window)
                       (with-current-buffer (window-buffer window)
                         (and (not (eq window (selected-window)))
                              (eq major-mode 'dired-mode))))))
         (other-marked-files (and other-win
                                  (with-current-buffer (window-buffer other-win)
                                    (dired-get-marked-files nil)))))
    (cond ((= (length marked-files) 2)
           (ediff-files (nth 0 marked-files)
                        (nth 1 marked-files)))
          ((and (= (length marked-files) 1)
                (= (length other-marked-files) 1))
           (ediff-files (nth 0 marked-files)
                        (nth 0 other-marked-files)))
          (t (error "mark exactly 2 files, at least 1 locally")))))

[Git] Remove files from last commit

You made a commit which has files that should not have been there. Worry not!

git reset --soft HEAD~1   // to soft reset (preserve changes)
git reset HEAD  /files/you/wish/to/unstage


You can now commit the staged files and checkout the unstaged files

git commit 
git checkout /files/you/wish/to/checkout


That's it!

[Emacs] Keyboard Macros!

Emacs keyboard macros are fun to use.

C-x ( to start recording
C-x ) to stop recording
C-x e to execute


If you want to repeat the macro N number of times,

C-u N C-x e

[Emacs] xterm mouse mode

Found another gem -- in order to use mouse in console mode (emacs -nw) use:

M-x xterm-mouse-mode

Provides basic functionality like scrolling and window selection. Best use when using gdb

[Emacs] Enable line numbers

Add the following to the .emacs file.

;; Show line numbers
(global-linum-mode t)
;; Separate text with space and |
(setq linum-format "%4d \u2502 ")

[Emacs] How to insert newline when replacing strings

To insert newline with replace-string use C-q C-j

e.g.

This;is;a;test

M-x replace-string <RET> ; <RET> C-q C-j

This
is
a
test

[emacs] Assign keyboard shortcuts to adjust buffer width and height

These are f*ucking handy!

(global-set-key (kbd "<f5>") 'balance-windows)
(global-set-key (kbd "<f6>") 'shrink-window)
(global-set-key (kbd "<f7<") 'enlarge-window)
(global-set-key (kbd "<f8>") 'enlarge-window-horizontally)
(global-set-key (kbd "<f9>") 'shrink-window-horizontally)

[emacs] Toggle read only mode

To ensure you don't accidentally change a file, enable the read-only mode.

M-x toggle-read-only

OR

C-x C-q

Very useful when using gdb

[emacs] Unwrap long line

To unwrap long lines

M-x toggle-truncate-lines

[emacs] search within a file

To search within a file

M-x occur
.. and it takes regular expressions as well.

[emacs] diff between buffers

To diff between buffers:

M-x ediff-buffers

Get rid of ESC[ in shell

When connected over putty and using screen I find that the output of less contains the "ESC[" character all over.

To fix this, add the following in your .bashrc

$ export LESS="-eirMX"

[Emacs] Fun with windows

An emacs window is different from the regular windows people are used to in a GUI. When you start emacs you create a "frame" which can be split horizontally and vertically into windows.

If you use emacs in the shell ("emacs -nw") then it is a pain to use the default keyboard shortcuts to change to window sizes. Solution is very simple. Map those commands to other shortcuts like the function keys.

(Use C-x e or eval-buffer to execute the lisp change in the .emacs file)

;; Resize the windows
(global-set-key [f5] 'balance-windows)
(global-set-key [f6] 'shrink-window)
(global-set-key [f7] 'enlarge-window)
(global-set-key [f8] 'enlarge-window-horizontally)
(global-set-key [f9] 'shrink-window-horizontally)

[Emacs] Playing with buffers and windows

I always work with two windows in split mode under a single Emacs frame which are split vertically. I wanted to create an easy way to toggle between the horizontal and vertical splits for two windows and also have the capability of swapping the buffers in the two windows.

Here are two functions that do the same. Note that these will only work for two windows.

;; Swap windows
(defun swap-windows ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
             (next-win-buffer (window-buffer (next-window))))
        (set-window-buffer (next-window) this-win-buffer)
        (set-window-buffer (selected-window) next-win-buffer))))

(define-key ctl-x-4-map "s" 'swap-windows)

The swap-windows() function swaps the buffers between the two windows while the toogle-window-split() toogles between the vertical and horizontal split. I think I found the toogle-window-split() on StackOverflow and wrote the swap-windows() based on that.


;; Toggle buffer splits from vertical to horizontal
(defun toggle-window-split ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
             (next-win-buffer (window-buffer (next-window)))
             (this-win-edges (window-edges (selected-window)))
             (next-win-edges (window-edges (next-window)))
             (this-win-2nd (not (and (<= (car this-win-edges)
                                         (car next-win-edges))
                                     (<= (cadr this-win-edges)
                                         (cadr next-win-edges)))))
             (splitter
              (if (= (car this-win-edges)
                     (car (window-edges (next-window))))
                  'split-window-horizontally
                'split-window-vertically)))
        (delete-other-windows)
        (let ((first-win (selected-window)))
          (funcall splitter)
          (if this-win-2nd (other-window 1))
          (set-window-buffer (selected-window) this-win-buffer)
          (set-window-buffer (next-window) next-win-buffer)
          (select-window first-win)
          (if this-win-2nd (other-window 1))))))

(define-key ctl-x-4-map "t" 'toggle-window-split)

Backup of .emacs



(global-set-key "%" 'match-paren)
(defun match-paren (arg)
   "Go to the matching paren if on a paren; otherwise insert %."
     (interactive "p")
     (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
         ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
         (t (self-insert-command (or arg 1)))))

(defun my-linux-c-mode ()
   "C mode with adjusted defaults for use with the linux kernel."
   (c-set-style "linux"))

(add-hook 'c-mode-hook 'my-linux-c-mode)

(server-start)

(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.
   '(show-paren-mode t)
   '(transient-mark-mode t))
(custom-set-faces
   ;; custom-set-faces 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.
)

Update: 05/23/2013

Over the last six years I have made many more changes to the .emacs file. Latest update for backup!

;; ================
;; General settings
;; ================

;; Display the time
(setq display-time-day-and-date t
      display-time-24hr-format t)
(display-time)

;; Inhibit startup splash screen
(setq inhibit-startup-message t)

;; enable row and column numner mode
(setq line-number-mode t)
(setq column-number-mode t)

;; Disable automatic backups
(setq backup-inhibited t)

;; show trailing whitespace
(setq-default show-trailing-whitespace t)

;; enable global clipboard to copy, paste into emacs
(setq x-select-enable-clipboard t)
(setq interprogram-paste-function 'x-cut-buffer-or-selection-value)

;; Disable tool-bar-mode and other custom changes!
(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.
 '(comint-scroll-show-maximum-output nil)
 '(ediff-merge-split-window-function (quote split-window-vertically))
 '(ediff-split-window-function (quote split-window-vertically))
 '(tool-bar-mode nil)
 '(delete-selection-mode t))

;; Start the server for emacsclient -n to work
(server-start)

(set-background-color "black")
(set-foreground-color "DarkOliveGreen3")
(set-cursor-color "green yellow")

;; full screen mode using [F11]
(defun toggle-fullscreen (&optional f)
  (interactive)
  (let ((current-value (frame-parameter nil 'fullscreen)))
    (set-frame-parameter nil 'fullscreen
             (if (equal 'fullboth current-value)
                 (if (boundp 'old-fullscreen) old-fullscreen nil)
               (progn (setq old-fullscreen current-value)
                  'fullboth)))))
(global-set-key [f11] 'toggle-fullscreen)


;;
;; Map M-_ to delete trailing whitespace
;;
(define-key global-map (kbd "M-_") 'delete-trailing-whitespace)


;; Make new frames fullscreen by default. Note: this hook doesn't do
;; anything to the initial frame if it's in your .emacs, since that file is
;; read _after_ the initial frame is created.
;; NOTE: This is screwing up the emacsclient connections for new frames!

;; (add-hook 'after-make-frame-functions 'toggle-fullscreen)

;; Set c-x p as previous-multiframe-window
(global-set-key (kbd "C-x p") 'previous-multiframe-window)

;; Set a 10pt font
(set-face-attribute 'default nil :height 100)

;; Disable upcase-region
(put 'upcase-region 'disabled nil)

;; Kill process without query!
(add-hook 'comint-exec-hook
      (lambda ()
        (process-kill-without-query (get-buffer-process (current-buffer)))))

;; ====================
;; Programming settings
;; ====================




;; highlight text beyond 80 characters!  Love this one!!
(setq whitespace-style '(trailing lines-tail space-before-tab
                                  indentation space-after-tab)
      whitespace-line-column 80)
(global-whitespace-mode 1)


;; Paren mode
(show-paren-mode 1)

;; Use vim style parenthesis matching
(global-set-key "%" 'match-paren)
(defun match-paren (arg)
  "Go to the matching paren if on a paren; otherwise insert %."
  (interactive "p")
  (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
    ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
    (t (self-insert-command (or arg 1)))))

;; Insert spaces instead of tabs
(setq-default indent-tabs-mode nil)

;; Use TABs on Makefile mode
(defun my-makefile-mode-hook()
  (setq indent-tabs-mode t))
(add-hook 'makefile-mode-hook 'my-makefile-mode-hook)

;; Custom C\C++ style at work!
(c-add-style "my-style"
             '("bsd"
               (c-basic-offset . 2)
               (c-offsets-alist . (
                                   (topmost-intro . 0)
                                   (substatement . +)
                                   (substatement-open . 0)
                                   (case-label . +)
                                   (access-label . -)
                                   (inclass . +)
                                   (inline-open . 0)))))


;; Use my-style for C and C++ modes. Also enable hungry state to
;; eat out any trailing whitespace
(defun my-c++-mode-hook ()
  (c-set-style "my-style")
  (auto-fill mode)
  (c-toggle-hungry-state 1))

(defun my-c-mode-hook ()
  (c-set-style "my-style")

  (auto-fill mode)
  (c-toggle-hungry-state 1))


(add-hook 'c++-mode-hook 'my-c++-mode-hook)
(add-hook 'c-mode-hook   'my-c-mode-hook)

;; set gtags-mode by default for C and C++ modes
(add-hook 'c-mode-hook
          '(lambda ()
             (gtags-mode t)
             ))

(add-hook 'c++-mode-hook
          '(lambda ()
             (gtags-mode t)
             ))

;; Use C++-mode to edit *.h files (not C-mode)
(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))

;; Use my-style indentation for MDL files
(setq auto-mode-alist (cons '("\\.mdl\\'" . c-mode) auto-mode-alist))

[Emacs] Fun with rectangles

Lets have some fun with emacs rectangles. Lets assume you have the following text:

012345678901234567890123456789
      val1 = 10;
      val2 = 20;
      val3 = 30;

Now, you need to add "(int)" in front of all the numbers. You can do it one line at a time, or you could use rectangles in emacs. Move the cursor to the start of 10, set mark, make the selection until start of 30. Hint: To set the mark, just hit Ctrl+Space and take your cursor to where you need to stop. Something like this,

012345678901234567890123456789
      val1 = 10;
      val2 = 20;
      val3 = 30;

Ok, now lets insert the string using "string-insert-rectangle" and enter the string that we want to be inserted, in our case "(int)"

M-x string-insert-rectangle
String insert rectangle (default void ): (int)

012345678901234567890123456789
      val1 = (int)10;
      val2 = (int)20;
      val3 = (int)30;

Now, say you wanted to give a space between the (int) and the number. Mark the rectangle as show below:

012345678901234567890123456789
      val1 = (int)10;
      val2 = (int)20;
      val3 = (int)30;

We will use the "open-rectangle" command now.

M-x open-rectangle

012345678901234567890123456789
      val1 = (int) 10;
      val2 = (int) 20;
      val3 = (int) 30;

Cool, now let's delete the spaces in the front using "delete-rectangle". Make the rectangle and...

012345678901234567890123456789
      val1 = (int) 10;
      val2 = (int) 20;
      val3 = (int) 30;

M-x delete-rectangle

012345678901234567890123456789
val1 = (int) 10;
val2 = (int) 20;
val3 = (int) 30;

Now, just for fun, we are going to cut a rectangle and yank it somewhere else. Lets remove 1,2,3 from the variable names and put them in the front (bad idea, I know). Lets select the rectangle and call the "kill-rectangle" command

012345678901234567890123456789
val1 = (int) 10;
val2 = (int) 20;
val3 = (int) 30;

M-x kill-rectangle

 012345678901234567890123456789
|val = (int) 10;
 val = (int) 20;
 val = (int) 30;

Move the cursor (show above as | ) to where you want to yank the rectangle now (in our case, the beginning of the word) and run "yank-rectangle"

M-x yank-rectangle

012345678901234567890123456789
1val = (int) 10;
2val = (int) 20;
3val = (int) 30;

Now, of course there are key-binding available (its Emacs for heaven's sake, even if there is no key-binding you can make your own).

From the Emacs manual
C-x r k
Kill the text of the region-rectangle, saving its contents as the “last killed rectangle” (kill-rectangle).
C-x r d
Delete the text of the region-rectangle (delete-rectangle).
C-x r y
Yank the last killed rectangle with its upper left corner at point (yank-rectangle).
C-x r o
Insert blank space to fill the space of the region-rectangle (open-rectangle). This pushes the previous contents of the region-rectangle to the right.
C-x r N
Insert line numbers along the left edge of the region-rectangle (rectangle-number-lines). This pushes the previous contents of the region-rectangle to the right.
C-x r c
Clear the region-rectangle by replacing all of its contents with spaces (clear-rectangle).
M-x delete-whitespace-rectangle
Delete whitespace in each of the lines on the specified rectangle, starting from the left edge column of the rectangle.
C-x r t string
Replace rectangle contents with string on each line (string-rectangle).
M-x string-insert-rectangle string
Insert string on each line of the rectangle.
Enjoy!

Using Shift+Arrow keys in Emacs from GNU screen

While inside screen, when using the Shift+Left, Shift-Right, etc keys in Emacs (1) to mark and select, if you see the 2A 2B 2C and 2D characters instead you are probably still using the default TERM which is set to "screen".

Simple solution, use xterm-vt220 or xterm-color instead. You can either create an alias for emacs or change your .screenrc file.

$ alias em='export TERM=xterm-vt220 && emacs -nw'

OR in your ~/.screenrc add,

term xterm-vt220

----------------------------------------------------------------
(1) You need to use Emacs 23 or above.

[Bash] Sending stdout and stderr to single file

Remember: To send both the stdout and stderr messages from the console to a file do:

$ app > log.file 2>&1

If you want to send everything to a black-hole just replace log.file with /dev/null.

$ app > /dev/null 2>&1

If ever confused about the syntax, do man bash and search for REDIRECTION for more gyan

Update:
It is good idea to use tee, which lets you see the output as well as write it to a file.

$ app 2>&1 | tee file.log