My personal emacs customization (custom.el)

custom.el is my personal emacs configuration. I use it with my publicized Emacs configuration.

;; I'm in Australia now
;; I'm in Australia now
(setq system-time-locale "C")

;; {{ stardict
(setq sdcv-dictionary-simple-list '("朗道英汉字典5.0"))
(setq sdcv-dictionary-complete-list '("WordNet"))
;; }}

;; {{ elpa-mirror
(setq elpamr-default-output-directory "~/myelpa")
(setq elpamr-repository-name "myelpa")
(setq elpamr-repository-path "https://dl.dropboxusercontent.com/u/858862/myelpa/")
(setq elpamr-email "myname@mydomain.com")
;; }}

;; lock my package
(if (file-readable-p (expand-file-name "~/Dropbox/Public/myelpa/archive-contents"))
     (setq package-archives '(("myelpa" . "~/Dropbox/Public/myelpa/"))))

;; {{ Set up third party tags
(defun insert-into-tags-table-list(e)
  (add-to-list 'tags-table-list e t)
  )
(defun delete-from-tags-table-list (e)
  (setq tags-table-list (delete e tags-table-list))
  )

(defun add-wx-tags (&optional del)
  "Add or delete(C-u) wxWidgets tags into tags-table-list"
  (interactive "P")
  (let (mytags)
    ; here add your third party tags
    (setq mytags (list "~/tags/wx/osx/TAGS"))
    (if del (mapc 'delete-from-tags-table-list mytags)
      (mapc 'insert-into-tags-table-list mytags)
      )
    )
  )
;; }}

;; (getenv "HOSTNAME") won't work because $HOSTNAME is not an env variable
;; (system-name) won't work because as Optus required, my /etc/hosts is changed
(defun my/at-office ()
  (interactive)
  (let ((my-hostname (with-temp-buffer
                       (shell-command "hostname" t)
                       (goto-char (point-max))
                       (delete-char -1)
                       (buffer-string))
                     ))
    (and (string= my-hostname "my-sydney-workpc")
         (not (or (string= my-hostname "sydneypc")
                  (string= my-hostname "ChenBinMacAir")
                  (string= my-hostname "eee")
                  )))
    ))

(defun my/use-office-style ()
  (interactive)
  (let ((dir (if (buffer-file-name)
                 (file-name-directory (buffer-file-name))
               "")))
    (string-match-p "CompanyProject" dir)
    ))

(defun my/setup-develop-environment ()
  (cond
   ((my/use-office-style)
    (message "Office code style!")
    (setq coffee-tab-width 4)
    (setq javascript-indent-level 4)
    (setq js-indent-level 4)
    (setq js2-basic-offset 4)
    (setq web-mode-indent-style 4))
   (t
    (message "My code style!")
    (setq coffee-tab-width 4)
    (setq javascript-indent-level 2)
    (setq js-indent-level 2)
    (setq js2-basic-offset 2)
    (setq web-mode-indent-style 2))
   ))

(add-hook 'js2-mode-hook 'my/setup-develop-environment)
(add-hook 'web-mode-hook 'my/setup-develop-environment)

(my/setup-develop-environment)

;; {{ gnus setup
(require 'nnir)

;; ask encyption password once
(setq epa-file-cache-passphrase-for-symmetric-encryption t)


;;@see http://www.emacswiki.org/emacs/GnusGmail#toc1
;; (add-to-list 'gnus-secondary-select-methods '(nntp "news.gmane.org"))
;; (add-to-list 'gnus-secondary-select-methods '(nntp "news.gwene.org"))
(if (my/at-office)
    (add-to-list 'gnus-secondary-select-methods '(nnml "optus"))
    (setq mail-sources
      '((pop :server "localhost"
         :port 1110
         :user "CP111111"
         :password "MyPassword"
         :stream network)))
    )


(setq gnus-select-method
             '(nnimap "gmail"
                      (nnimap-address "imap.gmail.com")
                      (nnimap-server-port 993)
                      (nnimap-stream ssl)
                      (nnir-search-engine imap)
                      (nnimap-authinfo-file "~/.authinfo.gpg")
                      ; @see http://www.gnu.org/software/emacs/manual/html_node/gnus/Expiring-Mail.html
                      ;; press 'E' to expire email
                      (nnmail-expiry-target "nnimap+gmail:[Gmail]/Trash")
                      (nnmail-expiry-wait 90)
                      ))

;;@see http://gnus.org/manual/gnus_397.html
;; (add-to-list 'gnus-secondary-select-methods
;;              )

(setq-default
  gnus-summary-line-format "%U%R%z %(%&user-date;  %-15,15f  %B%s%)\n"
  gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M"))
  gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
  gnus-sum-thread-tree-false-root ""
  gnus-sum-thread-tree-indent ""
  gnus-sum-thread-tree-leaf-with-other "-> "
  gnus-sum-thread-tree-root ""
  gnus-sum-thread-tree-single-leaf "|_ "
  gnus-sum-thread-tree-vertical "|")
(setq gnus-thread-sort-functions
      '(
        (not gnus-thread-sort-by-date)
        (not gnus-thread-sort-by-number)
        ))

;; we want to browse freely from gwene (RSS)
(setq gnus-safe-html-newsgroups "\\`nntp[+:]news\\.gwene\\.org[+:]")

; NO 'passive
(setq gnus-use-cache t)
(setq gnus-use-adaptive-scoring t)
(setq gnus-save-score t)
(add-hook 'mail-citation-hook 'sc-cite-original)
(add-hook 'message-sent-hook 'gnus-score-followup-article)
(add-hook 'message-sent-hook 'gnus-score-followup-thread)
; @see http://stackoverflow.com/questions/945419/how-dont-use-gnus-adaptive-scoring-in-some-newsgroups
(setq gnus-parameters
      '(("nnimap.*"
         (gnus-use-scoring nil)) ;scoring is annoying when I check latest email
        ))

(defvar gnus-default-adaptive-score-alist
  '((gnus-kill-file-mark (from -10))
    (gnus-unread-mark)
    (gnus-read-mark (from 10) (subject 30))
    (gnus-catchup-mark (subject -10))
    (gnus-killed-mark (from -1) (subject -30))
    (gnus-del-mark (from -2) (subject -15))
    (gnus-ticked-mark (from 10))
    (gnus-dormant-mark (from 5))))

;; Fetch only part of the article if we can.  I saw this in someone
;; else's .gnus
(setq gnus-read-active-file 'some)

;; Tree view for groups.  I like the organisational feel this has.
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; Threads!  I hate reading un-threaded email -- especially mailing
;; lists.  This helps a ton!
(setq gnus-summary-thread-gathering-function
      'gnus-gather-threads-by-subject)

;; Also, I prefer to see only the top level message.  If a message has
;; several replies or is part of a thread, only show the first
;; message.  'gnus-thread-ignore-subject' will ignore the subject and
;; look at 'In-Reply-To:' and 'References:' headers.
(setq gnus-thread-hide-subtree t)
(setq gnus-thread-ignore-subject t)

; Personal Information
(setq user-full-name "My Name"
      user-mail-address (if (my/at-office) "myname@office.com" "myname@mydomain.com")
      )

;; Change email address for work folder.  This is one of the most
;; interesting features of Gnus.  I plan on adding custom .sigs soon
;; for different mailing lists.
;; Usage, FROM: chen bin <work>
(setq gnus-posting-styles
      '((".*"
         (name "My Name"
          (address "myname@mydomain.com"
                   (organization "")
                   (signature-file "~/.signature")
                   ("X-Troll" "Emacs is better than Vi")
                   )))))


(setq mm-text-html-renderer 'w3m)

;; http://www.gnu.org/software/emacs/manual/html_node/gnus/_005b9_002e2_005d.html
(setq gnus-use-correct-string-widths nil)
;; @see http://emacs.1067599.n5.nabble.com/gnus-compile-td221680.html
;;(gnus-compile)
; =Gnus Tips=
;; @see http://www.scottmcpeak.com/gnus.html
;; }}

My personal emacs customization (custom.el)

custom.el is my personal emacs configuration. I use it with my publicized Emacs configuration.

;; I'm in Australia now
;; I'm in Australia now
(setq system-time-locale "C")

;; {{ stardict
(setq sdcv-dictionary-simple-list '("朗道英汉字典5.0"))
(setq sdcv-dictionary-complete-list '("WordNet"))
;; }}

;; {{ elpa-mirror
(setq elpamr-default-output-directory "~/myelpa")
(setq elpamr-repository-name "myelpa")
(setq elpamr-repository-path "https://dl.dropboxusercontent.com/u/858862/myelpa/")
(setq elpamr-email "myname@mydomain.com")
;; }}

;; lock my package
(if (file-readable-p (expand-file-name "~/Dropbox/Public/myelpa/archive-contents"))
     (setq package-archives '(("myelpa" . "~/Dropbox/Public/myelpa/"))))

;; {{ Set up third party tags
(defun insert-into-tags-table-list(e)
  (add-to-list 'tags-table-list e t)
  )
(defun delete-from-tags-table-list (e)
  (setq tags-table-list (delete e tags-table-list))
  )

(defun add-wx-tags (&optional del)
  "Add or delete(C-u) wxWidgets tags into tags-table-list"
  (interactive "P")
  (let (mytags)
    ; here add your third party tags
    (setq mytags (list "~/tags/wx/osx/TAGS"))
    (if del (mapc 'delete-from-tags-table-list mytags)
      (mapc 'insert-into-tags-table-list mytags)
      )
    )
  )
;; }}

;; (getenv "HOSTNAME") won't work because $HOSTNAME is not an env variable
;; (system-name) won't work because as Optus required, my /etc/hosts is changed
(defun my/at-office ()
  (interactive)
  (let ((my-hostname (with-temp-buffer
                       (shell-command "hostname" t)
                       (goto-char (point-max))
                       (delete-char -1)
                       (buffer-string))
                     ))
    (and (string= my-hostname "my-sydney-workpc")
         (not (or (string= my-hostname "sydneypc")
                  (string= my-hostname "ChenBinMacAir")
                  (string= my-hostname "eee")
                  )))
    ))

(defun my/use-office-style ()
  (interactive)
  (let ((dir (if (buffer-file-name)
                 (file-name-directory (buffer-file-name))
               "")))
    (string-match-p "CompanyProject" dir)
    ))

(defun my/setup-develop-environment ()
  (cond
   ((my/use-office-style)
    (message "Office code style!")
    (setq coffee-tab-width 4)
    (setq javascript-indent-level 4)
    (setq js-indent-level 4)
    (setq js2-basic-offset 4)
    (setq web-mode-indent-style 4))
   (t
    (message "My code style!")
    (setq coffee-tab-width 4)
    (setq javascript-indent-level 2)
    (setq js-indent-level 2)
    (setq js2-basic-offset 2)
    (setq web-mode-indent-style 2))
   ))

(add-hook 'js2-mode-hook 'my/setup-develop-environment)
(add-hook 'web-mode-hook 'my/setup-develop-environment)

(my/setup-develop-environment)

;; {{ gnus setup
(require 'nnir)

;; ask encyption password once
(setq epa-file-cache-passphrase-for-symmetric-encryption t)


;;@see http://www.emacswiki.org/emacs/GnusGmail#toc1
;; (add-to-list 'gnus-secondary-select-methods '(nntp "news.gmane.org"))
;; (add-to-list 'gnus-secondary-select-methods '(nntp "news.gwene.org"))
(if (my/at-office)
    (add-to-list 'gnus-secondary-select-methods '(nnml "optus"))
    (setq mail-sources
      '((pop :server "localhost"
         :port 1110
         :user "CP111111"
         :password "MyPassword"
         :stream network)))
    )


(setq gnus-select-method
             '(nnimap "gmail"
                      (nnimap-address "imap.gmail.com")
                      (nnimap-server-port 993)
                      (nnimap-stream ssl)
                      (nnir-search-engine imap)
                      (nnimap-authinfo-file "~/.authinfo.gpg")
                      ; @see http://www.gnu.org/software/emacs/manual/html_node/gnus/Expiring-Mail.html
                      ;; press 'E' to expire email
                      (nnmail-expiry-target "nnimap+gmail:[Gmail]/Trash")
                      (nnmail-expiry-wait 90)
                      ))

;;@see http://gnus.org/manual/gnus_397.html
;; (add-to-list 'gnus-secondary-select-methods
;;              )

(setq-default
  gnus-summary-line-format "%U%R%z %(%&user-date;  %-15,15f  %B%s%)\n"
  gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M"))
  gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
  gnus-sum-thread-tree-false-root ""
  gnus-sum-thread-tree-indent ""
  gnus-sum-thread-tree-leaf-with-other "-> "
  gnus-sum-thread-tree-root ""
  gnus-sum-thread-tree-single-leaf "|_ "
  gnus-sum-thread-tree-vertical "|")
(setq gnus-thread-sort-functions
      '(
        (not gnus-thread-sort-by-date)
        (not gnus-thread-sort-by-number)
        ))

;; we want to browse freely from gwene (RSS)
(setq gnus-safe-html-newsgroups "\\`nntp[+:]news\\.gwene\\.org[+:]")

; NO 'passive
(setq gnus-use-cache t)
(setq gnus-use-adaptive-scoring t)
(setq gnus-save-score t)
(add-hook 'mail-citation-hook 'sc-cite-original)
(add-hook 'message-sent-hook 'gnus-score-followup-article)
(add-hook 'message-sent-hook 'gnus-score-followup-thread)
; @see http://stackoverflow.com/questions/945419/how-dont-use-gnus-adaptive-scoring-in-some-newsgroups
(setq gnus-parameters
      '(("nnimap.*"
         (gnus-use-scoring nil)) ;scoring is annoying when I check latest email
        ))

(defvar gnus-default-adaptive-score-alist
  '((gnus-kill-file-mark (from -10))
    (gnus-unread-mark)
    (gnus-read-mark (from 10) (subject 30))
    (gnus-catchup-mark (subject -10))
    (gnus-killed-mark (from -1) (subject -30))
    (gnus-del-mark (from -2) (subject -15))
    (gnus-ticked-mark (from 10))
    (gnus-dormant-mark (from 5))))

;; Fetch only part of the article if we can.  I saw this in someone
;; else's .gnus
(setq gnus-read-active-file 'some)

;; Tree view for groups.  I like the organisational feel this has.
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; Threads!  I hate reading un-threaded email -- especially mailing
;; lists.  This helps a ton!
(setq gnus-summary-thread-gathering-function
      'gnus-gather-threads-by-subject)

;; Also, I prefer to see only the top level message.  If a message has
;; several replies or is part of a thread, only show the first
;; message.  'gnus-thread-ignore-subject' will ignore the subject and
;; look at 'In-Reply-To:' and 'References:' headers.
(setq gnus-thread-hide-subtree t)
(setq gnus-thread-ignore-subject t)

; Personal Information
(setq user-full-name "My Name"
      user-mail-address (if (my/at-office) "myname@office.com" "myname@mydomain.com")
      )

;; Change email address for work folder.  This is one of the most
;; interesting features of Gnus.  I plan on adding custom .sigs soon
;; for different mailing lists.
;; Usage, FROM: chen bin <work>
(setq gnus-posting-styles
      '((".*"
         (name "My Name"
          (address "myname@mydomain.com"
                   (organization "")
                   (signature-file "~/.signature")
                   ("X-Troll" "Emacs is better than Vi")
                   )))))


(setq mm-text-html-renderer 'w3m)

;; http://www.gnu.org/software/emacs/manual/html_node/gnus/_005b9_002e2_005d.html
(setq gnus-use-correct-string-widths nil)
;; @see http://emacs.1067599.n5.nabble.com/gnus-compile-td221680.html
;;(gnus-compile)
; =Gnus Tips=
;; @see http://www.scottmcpeak.com/gnus.html
;; }}

How to use FTP in Emacs

Emacs's default Ftp client is a little outdated compared to other modern Ftp clients.

What I want is a two panel file explorer with ftp client integrated (An excellent example is Total Commander on windows).

In Emacs, I've got Sunrise Commander which is close to Total Commander, but NO Ftp integration.

I dig around the internet for a while and find that the perfect solution is mount the ftp server into my local file system with CurlFtpFS.

The best part of this solution is CurlFtpFS supports both OS X and Linux.

In order to install CurlFtpFS on OS X, you need use the package manager Homebrew. The only catch I met on OS X is that I need upgrade Fuse4X driver manually for some wired reason to avoid "incompatible with the kernel version" error. Upgrading is simple. Download dmg plus mouse click stuff only. See FAQ for details.

For the usage of CurlFtpFS, see HERE for documentation. It's for Linux. But totally fine for OS X users.

Practical guide to use Gnus with Gmail

This article is moved to Github

The latest version of yasnippet is NOT compatible with auto-complete

Yes. The latest yasnippet (yasnippet-20120822.52) changed too many APIs and I cannot figure out how to work around it. Upgrading to the latest auto-complete (auto-complete-20120922.1815) won't solve the problem.

See https://github.com/capitaomorte/yasnippet/issues/311 for the details.

So here is the fix. You can use older version of yasnippet (yasnippet-20120718) and wait until the issue is fixed.

Here is the link of older version, http://dl.dropbox.com/u/858862/yasnippet-20120718.tar.gz.

Why Facebook app for android pad sucks?

I don't use facebook. I just record my roommates' complaining.

Here are his points,

failed to take full advantage of big screen of android pad
The right blank margin could be used to display comments instead, as some application has done.
scroll down/up to view the images sucks
Slow and hard to locate the exact item he wants.
Performance may be not good enough
Especially when viewing the images, it's not as fluent as other applications.

python code to migrate the MySQL database

The script can read configuration file and runs on python 2.4.

#!/usr/bin/python
import sys

import os

import string

import time

import datetime

import getopt

#############

# CONFIG

#############

DB_NAME='mydb'

DB_PASSWORD='111111'

DB_USER='root'

DB_HOST='mylinux0'

SQL_DB_SCHEMA=os.path.abspath("db_schema.sql")

SQL_CREATE_TABLE=os.path.abspath("000.sql")

CLONE_TABLES=['MyJobs','MyUsers']

#############

# GLOBALS

#############

backup_db=False

migration=False

config=None

verbose=False

delete=False

remote=False

def sql_cmd(cmd): if remote: return 'mysql -h %s -u %s -p%s -e " %s " %s' % (DB_HOST,DB_USER,DB_PASSWORD,cmd,DB_NAME) return 'mysql -u %s -p%s -e " %s " %s' % (DB_USER,DB_PASSWORD,cmd,DB_NAME)

def sql_script(script): if remote: return 'mysql -h %s -u %s -p%s %s < %s' % (DB_HOST,DB_USER,DB_PASSWORD,DB_NAME,script) return 'mysql -u %s -p%s %s < %s' % (DB_USER,DB_PASSWORD,DB_NAME,script)

def make_sql_to_create_table(): s=open(SQL_DB_SCHEMA).read() for t in CLONE_TABLES: s=s.replace(t,t+'2') open(SQL_CREATE_TABLE,'w').write(s)

def backup_database(): fname="%s-%s.dump.gz" % (DB_NAME,time.strftime('%Y%m%d%H%M%S', time.gmtime())) if remote: cmd="mysqldump -h %s -u %s -p%s --compact %s|gzip -9 > %s" % (DB_HOST,DB_USER,DB_PASSWORD,DB_NAME,fname) else: cmd="mysqldump -u %s -p%s --compact %s|gzip -9 > %s" % (DB_USER,DB_PASSWORD,DB_NAME,fname)

<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

def delete_db_records(): cmd=sql_cmd("delete from sources;delete from cameras;") print "==WILL RUN [ %s ]" % (cmd) os.system(cmd) print "==DONE"

def package(): cmd="tar zcvf migrate-db.tar.gz .sql migrate.py .migrate_" print "==WILL RUN [ %s ]" % (cmd) os.system(cmd) print "==DONE"

def read_config(config): global DB_NAME global DB_PASSWORD global DB_USER global DB_HOST f=open(config,"r") for line in f: a=line.split("=") if len(a)!=2: continue n=a[0].strip() v=a[1].strip() if n=="DB_NAME": DB_NAME=v elif n=="DB_PASSWORD": DB_PASSWORD=v elif n=="DB_USER": DB_USER=v elif n=="DB_HOST": DB_HOST=v

def usage(): print ''' USAGE: python migrate.py [OPTIONS]

OPTIONS:

-h, --help

print this help

-b, --backup-database

backup the old database before migration (recommended)

-m, --migrate

donot start migration

-v, --verbose

print database related information

-p, --package

packge all the scripts into migrate-db.tar.gz

-d, --delete-db-records

delete database records so we can restart migration

-c, --config

SAMPLES:

python migrate.py -b #back database and exit

python migrate.py -m #start migration right now

python migrate.py -b -m #backup the database and start the migration (recommended)

python migrate.py -v #print database information and exit

python migrate.py -c .migrate_staging -v #print staging database information and exit

'''

def show_info(): print ''' ==Database Information

name:{name}

password:{password}

user:{user}

host:{host}

'''.format(name=DB_NAME, password=DB_PASSWORD,user=DB_USER,host=DB_HOST)

def confirm(prompt=None, resp=False): """prompts for yes or no response from the user. Returns True for yes and False for no.

'resp' should be set to the default value assumed by the caller when

user simply types ENTER.

>>> confirm(prompt='Create Directory?', resp=True)

Create Directory? [y]|n:

True

>>> confirm(prompt='Create Directory?', resp=False)

Create Directory? [n]|y:

False

>>> confirm(prompt='Create Directory?', resp=False)

Create Directory? [n]|y: y

True

"""

<span style="color: #af00ff;">if</span> prompt <span style="color: #af00ff;">is</span> <span style="color: #008787;">None</span>:
    prompt = <span style="color: #87005f;">'WARNING: DONOT run me twice and migration CANNOT be rolled back, GO?'</span>

<span style="color: #af00ff;">if</span> resp:
    prompt = <span style="color: #87005f;">'%s [%s]|%s: '</span> % (prompt, <span style="color: #87005f;">'y'</span>, <span style="color: #87005f;">'n'</span>)
<span style="color: #af00ff;">else</span>:
    prompt = <span style="color: #87005f;">'%s [%s]|%s: '</span> % (prompt, <span style="color: #87005f;">'n'</span>, <span style="color: #87005f;">'y'</span>)

<span style="color: #af00ff;">while</span> <span style="color: #af00ff;">True</span>:
    ans = <span style="color: #5f5f87;">raw_input</span>(prompt)
    <span style="color: #af00ff;">if</span> <span style="color: #af00ff;">not</span> ans:
        <span style="color: #af00ff;">return</span> resp
    <span style="color: #af00ff;">if</span> ans <span style="color: #af00ff;">not</span> <span style="color: #af00ff;">in</span> [<span style="color: #87005f;">'y'</span>, <span style="color: #87005f;">'Y'</span>, <span style="color: #87005f;">'n'</span>, <span style="color: #87005f;">'N'</span>]:
        <span style="color: #af00ff;">print</span> <span style="color: #87005f;">'please enter y or n.'</span>
        <span style="color: #af00ff;">continue</span>
    <span style="color: #af00ff;">if</span> ans == <span style="color: #87005f;">'y'</span> <span style="color: #af00ff;">or</span> ans == <span style="color: #87005f;">'Y'</span>:
        <span style="color: #af00ff;">return</span> <span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">if</span> ans == <span style="color: #87005f;">'n'</span> <span style="color: #af00ff;">or</span> ans == <span style="color: #87005f;">'N'</span>:
        <span style="color: #af00ff;">return</span> <span style="color: #af00ff;">False</span>

if name=="main": ''' @see http://linux.byexamples.com/archives/366/python-how-to-run-a-command-line-within-python/

''' try: opts, args = getopt.getopt(sys.argv[1:], "hbmvpdc:r", ["help", "backup-database","--migrate","--verbose","--package","--delete-db-records","--config=","--remote"]) except getopt.GetoptError, err: print str(err) # will print something like "option -a not recognized" usage() exit(2)

<span style="color: #af00ff;">if</span> <span style="color: #5f5f87;">len</span>(opts)==0:
    usage()
    <span style="color: #5f5f87;">exit</span>(2)

<span style="color: #af00ff;">for</span> o, a <span style="color: #af00ff;">in</span> opts:
    <span style="color: #af00ff;">if</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-h"</span>, <span style="color: #87005f;">"--help"</span>):
        usage()
        sys.exit()
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-v"</span>, <span style="color: #87005f;">"--verbose"</span>):
        verbose=<span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-c"</span>, <span style="color: #87005f;">"--config"</span>):
        config=a
        <span style="color: #af00ff;">print</span> config
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-d"</span>, <span style="color: #87005f;">"--delete-db-records"</span>):
        delete=<span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-p"</span>, <span style="color: #87005f;">"--package"</span>):
        package()
        <span style="color: #5f5f87;">exit</span>(0)
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-b"</span>, <span style="color: #87005f;">"--backup-database"</span>):
        backup_db=<span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-m"</span>, <span style="color: #87005f;">"--migrate"</span>):
        migration=<span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">elif</span> o <span style="color: #af00ff;">in</span> (<span style="color: #87005f;">"-r"</span>, <span style="color: #87005f;">"--remote"</span>):
        remote=<span style="color: #af00ff;">True</span>
    <span style="color: #af00ff;">else</span>:
        <span style="color: #af00ff;">assert</span> <span style="color: #af00ff;">False</span>, <span style="color: #87005f;">"unhandled option"</span>

<span style="color: #af00ff;">if</span> config!=<span style="color: #008787;">None</span>:
    read_config(config)

<span style="color: #af00ff;">if</span> delete:
    delete_db_records()
    sys.exit()

<span style="color: #af00ff;">if</span> verbose:
    show_info()
    sys.exit()

<span style="color: #af00ff;">if</span> backup_db:
    backup_database()

<span style="color: #af00ff;">if</span> migration==<span style="color: #af00ff;">False</span>:
    <span style="color: #5f5f87;">exit</span>(0)

<span style="color: #af00ff;">if</span> confirm()==<span style="color: #af00ff;">False</span>:
    <span style="color: #af00ff;">print</span> <span style="color: #87005f;">"Aborting ..."</span>
    <span style="color: #5f5f87;">exit</span>(0)

make_sql_to_create_table()

<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==START MIGRATION"</span>

<span style="color: #af0000;"># test data base connection</span>
cmd=sql_cmd(<span style="color: #87005f;">'show databases;use %s;'</span> % (DB_NAME))
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

cmd=sql_script(<span style="color: #87005f;">"000.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('001.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"001.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('002.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"002.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('003.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"003.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('004.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"004.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('005.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"005.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('006.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"006.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

os.system(sql_cmd(<span style="color: #87005f;">"insert into migrate (Action) values ('100.sql')"</span>))
cmd=sql_script(<span style="color: #87005f;">"100.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

cmd=sql_script(<span style="color: #87005f;">"insert_sample_sources.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

cmd=sql_script(<span style="color: #87005f;">"app_config.sql"</span>)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==WILL RUN [ %s ]"</span> % (cmd)
os.system(cmd)
<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==DONE"</span>

<span style="color: #af00ff;">print</span> <span style="color: #87005f;">"==END MIGRATION"</span>

# vim: set expandtab tabstop=4 shiftwidth=4:

Emacs中的自动完成(Auto Completion)完全指南

作者: 陈斌(redguardtoo)

更新时间: <2017-04-05 Wed>

原创时间: <2012-08-21 Tue>

Emacs比普通IDE的Intellisense强大,例如可输入当前文件名(带或者不带文件名后缀都可以).

我不是来赞美Emacs的强大的,我是来吐槽的.自动完成框架太多,功能重叠,让人困扰.

所以本文目的有两个:

  • 说明哪些框架流行
  • 如何使用框架

1 概述

函数/插件名 快捷键 使用频率
company-mode (结合clang) 不需要 (也可启用TAB)
hippie-expand M-/
evil-mode C-n/C-p(完成词),C-x C-n/p(完成行)
auto-complete (结合clang) TAB
complete-symbol C-M-i

2 auto-complete结合clang

auto-complete是第三方开发的插件,提供了自动完成需要的支持(例如在命令行环境下对下拉菜单的模拟).

clang是苹果公司C/C++/Objective-C编译器,对C++语法的解析很好.

显然,这种l案只适用于 Clang 支持的语言.

需要通过elpa(Emacs的AppStore)安装第三方插件 auto-completeauto-complete-clang.

具体配置请参考我的init-auto-complete.el.

已被company-mode取代,不推荐.

3 company-mode

company-mode和auto-complete功能类似,唯一的区别是clang以及其他语言支持已内置,所以不需要安装其他elisp插件或者额外配置.目前我已用company-mode代替了auto-complete.

4 hippie-expand

hippie-expand是Emacs自带的自动完成框架.

其默认的一些特色功能(例如,完成词/文件名/行的功能,或在 minibuffer 中使用)可作为 company-mode 补充.

5 complete-symbol

Emacs自带的一个函数,我对这个方案感觉一般,因为在Emacs23中,它默认仅仅调用了后台的ctags而已.

hippie-expand 经过调教也可用 Ctags,且默认特色功能比 complete-symbol 多,所以我没兴趣配置第三个自动完成框架了.

通过阅读Emacs24的ChangeLog,我发现 complete-symbol 经过配置后可以用 semantic 作为语法解析后端(Emacs23.4也支持,不明白为什么把该特性放在Emacs24的ChangeLog介绍).

semantic是lisp写的语法解析器,Emacs自带,智能程度介于ctags和clang之间,解析速度比较慢,如果机器配置较差会很卡.

我不喜欢这个语法解析器,过去在 Semantic 尚是Cedet的一个组件时,我折腾过 Cedet,当时感觉速度慢,配置繁琐,不稳定.

Semantic 支持多种语言,如C++/Java.

配置请参考我的init-semantic.el(注意,我不用 Semantic,所以相应代码被注释了.你可取消注释).

已被 company-mode 取代,不推荐.

6 evil-mode

Evil-mode把Emacs模拟成了Vim,是我最喜欢的第三方插件,其自动完成很简单,就是根据当前文件内容自动完成词或行.

值得推荐是因为我也是重度Vim用户,Vim的快捷键已成为我本能了.

无需配置,启动 evil-mode 即可,参见我的init-evil.el.

7 其他

我的一个想法. 类似于Evil的完成行.但是可以扫瞄指定目录中所有的文件,列出相似的行.

优点在于:

  • 匹配可以更加宽容一点
  • 使用目前最快的grep工具如ripgrep扫瞄文本

实现见init-ivy中的=counsel-complete-line-by-grep=.

试用好几个月了,非常好用.

8 小结

自动完成包括前端用户界面和后端语法解析引擎两个部分.

作为前端的用户界面, company-modeauto-complete 相当成熟.

后端 Clang 最优秀.

Ctags 谈不上语法解析,只是正则表达式罢了,但是因此才能通吃所有语言.

Semantic 支持的语言比 Clang 多一点,性能和稳定性比较差.

作为一个C++程序员,我过去用 auto-complete 加上 Clang,现在用 company-modeClang.

脚本语言(Ruby/Python/Javascript)用 Ctagscompany-mode 自带的 company-etags.

基于框架自己发明新技术会更好用.

My git alias in .bashrc

My favourite alias are g, gau, gc,gt,gl,gdc.

# Git alias
alias g="git status"

alias ga="git add"

alias gaa="git add ."

alias gau="git add -u"

alias gc="git commit -m"

alias gca="git commit -am"

alias gb="git branch"

alias gbd="git branch -d"

alias gco="git checkout"

alias gcob="git checkout -b"

alias gt="git stash"

alias gta="git stash apply"

alias gm="git merge"

alias gr="git rebase"

alias gl="git log --oneline --decorate --graph"

alias gs="git show"

alias gd="git diff"

alias gdc="git diff --cached"

alias gbl="git blame"

alias gps="git push"

alias gpl="git pull"

Emacs中的完美多窗口操作

典型的工作流

  1. 在两个子窗口中对比文件内容
  2. 打开更多的窗口以参考其他信息.
  3. 对某个窗口内容比较有兴趣,跳转到该窗口,将该窗口最大化
  4. 看完最大化的窗口内容后,undo最大化操作,重新回到早先的多个小窗口模式以便继续纵览全局

将子窗口自动编号,然后按M-0…9跳转(最爱)

安装window-numbering.el,然后在.emacs中添加以下代码,

(require 'window-numbering)
(window-numbering-mode 1)

undo/redo之前的窗口操作(最爱)

安装Winner Mode,然后在.emacs中添加以下代码,

(winner-mode 1)

;; copied from http://puntoblogspot.blogspot.com/2011/05/undo-layouts-in-emacs.html

(global-set-key (kbd "C-x 4 u") 'winner-undo)

(global-set-key (kbd "C-x 4 r") 'winner-redo)

焦点移动到下一窗口(常用)

M-x other-window,快捷键是C-x o.

水平/垂直切分当前窗口(常用)

快捷键C-x 2/3

将当前子窗口最大化(常用)

M-x delete-other-windows,快捷键C-x 1.

删除当前子窗口(偶尔用)

M-x delete-window (快捷键C-x 0)

顺便说一下,M-x kill-buffer-and-window (快捷键C-x 4 0),我现在用得更多 些.

移动焦点到上下左右的窗口(基本不用)

因我较喜欢vi快捷键,所以我安装了Evil Mode.快捷键和Vi一样. C-w h/j/k/l移动至各方向的子窗口.

存储/载入窗口布局到register(基本不用)

C-x r w &lt;register&gt;存储,C-x r j &lt;register&gt;载入.