First Touch of Travis CI

目前 Travis CI 给我的感觉和 Jekins 类似,每次 push 到 github 上, Travis 会自动跑一遍,比如按官方文档所说,对于 Java 项目,如果发现 pom.xml 文件,会使用 Maven 3 的一些 lifecycle。

对于一个 Java 项目,需要在 .git/ 目录下,新建文件 .travis.yml,最简 单的内容是:

1
language: java

NOTE: Everything About CAS

假设 CAS Server 的域名是 cas.server.com

CAS Server 的 webapp 是 spring web flow,登陆地址为:https://cas.server.com/cas/login

登出地址为:https://cas.server.com/cas/logout

语言参数为:locale=zh_CN,locale=en

除了配置 CAS Server 和 Client 外,需要配置环境,包括生成和导出导入证书,Tomcat配置SSL等。

CAS Server

原理(认证流程)

CAS 基本模式

原理:按照此图来说

  1. 用户访问CAS Client

  2. 其配置的 AuthenticationFilter 会拦截此请求,生成 service 参数,并重定向到 CAS Server 的登陆接口,url为 https://cas.server.com/login?service=redirect_url

  3. 用户在 CAS Server 输入 Credentials(一般就是用户名和密码)进行身份验证,成功后,CAS Server 会生成认证 cookie,即TGC。(另:TGC作为 cookie之外,也会换存在服务器本地,我猜测是不是服务器运行实例的内存中。)

  4. CAS Server还会根据 service 参数,生成 Ticket,即ST。ST会保存在服务器,也会加在 url 后面,重定向回 client。url为 http://client_server_url:port/app_name?ticket=ST-*-*

  5. Client 的 AuthenticationFilter 看到 ticket 参数后,会跳过,交由后面的 TicketValidationFilter 来处理。TicketValidationFilter 会利用 httpclient 工具访问 cas server 的 /serviceValidate 接口,将 ticket, service 传入该接口,验证 ticket 的有效性。

  6. 如果返回验证成功,就会把用户信息写入 client 的 session 里。

至此,SSO 会话就建立起来了。

结果就是:

  1. 用户在同一浏览器访问同一 client,不会去 CAS Server 认证,因为 AuthenticationFilter 会在 session 读取到用户信息。

  2. 用户在同一浏览器访问其他 client,AuthenticationFilter 在 session 里读不到用户信息,会去 cas login 接口认证,但是此时 cas login 接口会读取到存储在cas server域名下的 TGC,所以,CAS Server不会跳到登录页,只会根据 service 参数生成一个 ticket,传给 client。然后由TicketValidationFilter做一次交互验证。

CAS Server 提供的接口

cas server 一共定义了9个接口。client 会通过 url redirect 和 httpclient 的方式和 server 交互。

接口 说明
/login 认证接口
/logout 退出接口,销毁 TGC
/validate 验证 ticket 接口,CAS1.0
/serviceValidate 同上,CAS2.0
/proxy 支持代理功能的接口
/proxyValidate 同上
/CentralAuthenticationService 用于和远程的 web services 交互
/remoteLogin 认证接口(新增)
/directLogin 认证接口(新增)

认证相关的术语

  • Credentials 用户提供的凭证,比如 用户名/密码,证书,IP地址,Cookie值等。

  • AuthenticationHandler 认证Handler,比如:AbstractUsernamePasswordAuthenticationHandler 负责处理 UsernamePasswordCredentials.

  • CredentialsToPrincipalResolvers 负责由 Credentials 生成 Principal 对象,每种 CredentialsToPrincipalResolvers 只处理 一种Credentials ,比如 UsernamePasswordCredentialsToPrincipalResolver 负责从 UsernamePasswordCredentials 中取出用户名,然后将其赋给生成的 SimplePrincipal 的 ID 属性。

  • AuthenticationMetaDataPopulators 负责将 Credentials 的一些属性赋值给 Authentication 的 attributes 属性。

  • Authentication Authentication是认证管理器的最终处理结果, Authentication 封装了 Principal ,认证时间,及其他一些属性(可能来自 Credentials)。

  • AuthenticationManager 认证管理器得到 Credentials 对象后,负责调度AuthenticationHandler 去完成认证工作,最后返回的结果是 Authentication 对象。

  • CentralAuthenticationService CAS 的服务类,对 Web 层提供了一些方法。该类还负责调用 AuthenticationManager 完成认证逻辑。

Maven Archetype Plugin

Struts 2 Maven Archetype

The Blank Archetype (struts2-archetype-blank)

The Starter Archetype (struts2-archetype-starter)

Compared to the former, it adds more features like “Spring Integration”.

The Blank Convention Archetype (struts2-archetype-convention)

Features like “Convention-based validation”, “GAE aware”.

Creating an Application Using a Maven Archetyp

1
2
3
4
5
6
mvn archetype:generate -B \
                       -DgroupId=tutorial \
                       -DartifactId=tutorial \
                       -DarchetypeGroupId=org.apache.struts \
                       -DarchetypeArtifactId=struts2-archetype-blank \
                       -DarchetypeVersion=<version>

If the above command will fail because of missing archetypes in central repository, you can try to use staging repository like below

1
mvn archetype:generate -DarchetypeCatalog=http://people.apache.org/builds/struts/<version>/m2-staging-repository/

NOTE: CAS Java Client

CAS Client for Java 3.1

通过 web.xml 配置 Jasig CAS Client for Java

CAS Client for Java 3.1/3.2 可以通过配置 web.xml 里的 context-params 和 filter init-params。每个 filter 都需要配置一系列的属性(properties)。filters 会查找这些属性:

  1. 首先检查 filter 的本地 init-params(local init-params),看是否有相符合的属性名;
  2. 其次检查 context 的参数 ,看是否有相符合的属性名;

如果在 filter 的 init-params 和 context 的参数中找到相同的值,则选用 init-params。

同样,filter 的顺序为:

  1. SingleLogOutFilter (if you’re using it)
  2. AuthenticationFilter
  3. TicketValidationFilter (whichever one is chosen)
  4. HttpServletRequestWrapperFilter
  5. AssertionThreadLocalFilter

! 如果使用 serverName 属性,请注意 fragment-URL(#后的 URL)不会发送给服务器。

一一介绍可用的 filters:

org.jasig.cas.client.authentication.AuthenticationFilter

AuthenticationFilter 判断一个用户是否需要验证。如果需要,则重定向到 CAS server。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<filter>
  <filter-name>CAS Authentication Filter</filter-name>
  <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
  <init-param>
    <!--cas server login url-->
    <param-name>casServerLoginUrl</param-name>
    <param-value>https://battags.ad.ess.rutgers.edu:8443/cas/login</param-value>
  </init-param>
  <init-param>
    <!--cas server name-->
    <param-name>serverName</param-name>
    <param-value>http://www.acme-client.com</param-value>
  </init-param>
</filter>

Required Properties

Optional Properties:

renew, gateway, artifactParameterName, serviceParameterName

org.jasig.cas.client.authentication.Saml11AuthenticationFilter

猜测是支持 SAML 1.1 的 authentication filter。

1
2
3
4
5
6
7
8
9
10
11
12
<filter>
  <filter-name>CAS Authentication Filter</filter-name>
  <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
  <init-param>
    <param-name>casServerLoginUrl</param-name>
    <param-value>https://battags.ad.ess.rutgers.edu:8443/cas/login</param-value>
  </init-param>
  <init-param>
    <param-name>serverName</param-name>
    <param-value>http://www.acme-client.com</param-value>
  </init-param>
</filter>

org.jasig.cas.client.validation.Saml11TicketValidationFilter

使用 SAML 1.1 协议验证 tickets。

1
2
3
4
5
6
7
8
9
10
11
12
<filter>
  <filter-name>CAS Validation Filter</filter-name>
  <filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>
  <init-param>
    <param-name>casServerUrlPrefix</param-name>
    <param-value>https://battags.ad.ess.rutgers.edu:8443/cas</param-value>
  </init-param>
  <init-param>
    <param-name>serverName</param-name>
    <param-value>http://www.acme-client.com</param-value>
  </init-param>
 </filter>

Required Properties

Optional Properties

  • redirectAfterValidation (default: true)
  • useSession (default: true)
  • exceptionOnValidationFailure (default: true)
  • tolerance (default: 1000 mSec)
  • renew (default: false)

org.jasig.cas.client.util.HttpServletRequestWrapperFilter

Wraps an HttpServletRequest so that the getRemoteUser and getPrincipal return the CAS related entries.

包裹 HttpServletRequest,使 getRemoteUser 和 getPrincipal 返回 CAS 相关的入口。

1
2
3
4
<filter>
  <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>

Required Properties

None

Optional Properties

None

org.jasig.cas.client.util.AssertionThreadLocalFilter

Places the Assertion in a ThreadLocal for portions of the application that need access to it. This is useful when the Web application that this filter “fronts” needs to get the Principal name, but it has no access to the HttpServletRequest, hence making getRemoteUser() call impossible.

把这个 Assertion 放进 ThreadLocal 中,因为有些应用可能需要。比如:当 Web 应用需要拿到 Principal 的名字,但是它无法访问 HttpServletRequest,因此 getRemoteUser() 没有用。

! 没搞懂什么意思,猜测是 CAS Client 应用想要拿到登陆的用户名,但是用户名存储在 CAS Server 上。这个 filter 的作用就是把 Principal 放到 ThreadLocal 变量中。

1
2
3
4
<filter>
  <filter-name>CAS Assertion Thread Local Filter</filter-name>
  <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>

e.g. 一份稍完整的 CAS Client for Java 的 web.xml(未使用 SAML 1.1,为 CAS 协议)

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

    <display-name>CAS client demo : application</display-name>

    <filter>
        <!--配置 AuthenticationFilter-->
        <filter-name>CAS Authentication Filter</filter-name>
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        <init-param>
            <!--property: 登陆页配置-->
            <param-name>casServerLoginUrl</param-name>
            <param-value>http://localhost:8080/cas/login</param-value>
        </init-param>
        <init-param>
            <!--property: 部署服务器地址-->
            <param-name>serverName</param-name>
            <param-value>http://localhost:8080</param-value>
        </init-param>
        <!-- init-param>
            <param-name>service</param-name>
            <param-value>http://localhost:8080/default.jsp</param-value>
        </init-param-->
    </filter>

    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>http://localhost:8080/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://localhost:8080</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CAS Authentication Filter</filter-name>
        <url-pattern>/protected/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>

</web-app>

e.g. 使用 SAML 1.1

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <display-name>CAS client demo : application</display-name>

  <filter>
      <filter-name>CAS Authentication Filter</filter-name>
      <filter-class>org.jasig.cas.client.authentication.Saml11AuthenticationFilter</filter-class>
      <init-param>
          <param-name>casServerLoginUrl</param-name>
          <param-value>http://localhost:8080/cas/login</param-value>
      </init-param>
      <init-param>
          <param-name>serverName</param-name>
          <param-value>http://localhost:8080</param-value>
      </init-param>
      <init-param>
          <param-name>onlyFullyAuthenticated</param-name>
            <param-value>true</param-value>
        </init-param>
  </filter>

  <filter>
      <filter-name>CAS Validation Filter</filter-name>
      <filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>
      <init-param>
          <param-name>casServerUrlPrefix</param-name>
          <param-value>http://localhost:8080/cas</param-value>
      </init-param>
      <init-param>
          <param-name>serverName</param-name>
          <param-value>http://localhost:8080</param-value>
      </init-param>
  </filter>

  <filter-mapping>
      <filter-name>CAS Authentication Filter</filter-name>
      <url-pattern>/protected/*</url-pattern>
  </filter-mapping>

  <filter-mapping>
      <filter-name>CAS Validation Filter</filter-name>
      <url-pattern>*</url-pattern>
  </filter-mapping>

</web-app>

配置单点登出 Single Sign Out

! SingleSignOutFilter 会影响到 character encoding。建议显式地配置下 VT Character Encoding FilterSpring Character Encoding Filter

CAS 对 Single Sign Out support 的支持,涉及到对一个 filter 和一个 ContextListener 的配置。需要注意的一点是,如果以 Web filters 的形式为 Java 配置 CAS Client,登出的 filter 需要在其他 filters 前面。

PS: Order of Required Filters 全文链接 Order of Required Filters

How to configure the filters is described on the pages above. This section details the order in which the filters should appear:

  1. SingleLogOutFilter (if you’re using it)
  2. AuthenticationFilter
  3. TicketValidationFilter (whichever one is chosen)
  4. HttpServletRequestWrapperFilter
  5. AssertionThreadLocalFilter
1
2
3
<listenerclass>
  org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

NOTE: Special Things About CAS

1

Create the Certificate

打开终端,进到 home 目录,运行命令:

1
keytool -genkey -alias tomcat -keyalg RSA -validity 365

需要输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Enter keystore password:
Re-enter new password:
What is your first and last name?
  [Unknown]:  $REPLACE_WITH_FULL_MACHINE_NAME
What is the name of your organizational unit?
  [Unknown]:  Test
What is the name of your organization?
  [Unknown]:  Test
What is the name of your City or Locality?
  [Unknown]:  Test
What is the name of your State or Province?
  [Unknown]:  Test
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=$FULL_MACHINE_NAME, OU=Test, O=Test, L=Test, ST=Test, C=US correct?
  [no]:  yes

如何给这些值?

For the keystore password you should enter “changeit” without the quotation marks. When prompted for the first and last name, you should enter your machine name during development. The rest of the data does not matter. Then obviously answer “yes” to the question of whether it’s correct.

注意: CAS 协议需要走 HTTPS,为了保证能够工作, “first and last name” 为 $FULL_MACHINE_NAME。Mac 上获取计算机全名的方法是:scutil --get ComputerName 或者 scutil --get LocalHostName

下一步,打开 $TOMCAT_HOME/conf/server.xml,找到这一块,去掉注释即可:

1
2
3
4
5
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
    maxThreads="150" scheme="https" secure="true"
    clientAuth="false" sslProtocol="TLS" />
-->

重启 Tomcat,访问

1
https://$FULL_MACHINE_NAME:8443/

Any application that wishes to securely connect to this Tomcat instance would need to import the certificate. You can export the certificate that’s compatible with other JVM keystores by executing the following command:

所有想访问该 Tomcat 实例的应用都需要导入证书。首先导出证书,需要输入 keystore 的密码,这里就是 changeit:

1
keytool -export -alias tomcat -file server.crt

输出是:

1
2
Enter keystore password:
Certificate stored in file <server.crt>

You can then import the server.crt into other JVM keystore’s by executing a command similar to this:

1
keytool -import -file server.crt -keystore $JAVA_HOME/jre/lib/security/cacerts -alias tomcat

It’s recommended that you add it to the JVM keystore of your local development machine to facilitate testing.

2

Maven War Overlay1

Deploy War to Tomcat

非常简单,mvn package 生成的 war 包,直接扔进 Tomcat 安装目录下的 webApps 目录。然后重启下 Tomcat。

不需要任何额外的配置,默认是 localhost:8080/war_name/

NOTE: Writing GNU Emacs Extensions

1

列表处理

1.1

Lisp 列表

1
2
3
4
'(rose
  violet
  daisy
  buttercup)

1.1.1

Lisp 原子

() 空列表

空列表既是原子,也是列表

原子和列表都叫做 符号表达式(symbolic expression),简称 s-expression。

Emacs Help Command

You have typed C-h, the help character. Type a Help option: (Use SPC or DEL to scroll through this text. Type q to exit the Help command.)

常用的是:

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
32
33
34
35
36
37
38
39
40
41
42
a PATTERN   Show commands whose name matches the PATTERN (a list of words
              or a regexp).  See also the `apropos' command.              
b           Display all key bindings.
c KEYS      Display the command name run by the given key sequence.
C CODING    Describe the given coding system, or RET for current ones.
d PATTERN   Show a list of functions, variables, and other items whose
              documentation matches the PATTERN (a list of words or a regexp).
e           Go to the *Messages* buffer which logs echo-area messages.
f FUNCTION  Display documentation for the given function.
F COMMAND   Show the on-line manual's section that describes the command.
g           Display information about the GNU project.
h           Display the HELLO file which illustrates various scripts.
i           Start the Info documentation reader: read on-line manuals.
I METHOD    Describe a specific input method, or RET for current.
k KEYS      Display the full documentation for the key sequence.
K KEYS      Show the on-line manual's section for the command bound to KEYS.
l           Show last 300 input keystrokes (lossage).
L LANG-ENV  Describes a specific language environment, or RET for current.
m           Display documentation of current minor modes and current major mode,
              including their special commands.
n           Display news of recent Emacs changes.
p TOPIC     Find packages matching a given topic keyword.
r           Display the Emacs manual in Info mode.
s           Display contents of current syntax table, plus explanations.
S SYMBOL    Show the section for the given symbol in the on-line manual
              for the programming language used in this buffer.
t           Start the Emacs learn-by-doing tutorial.
v VARIABLE  Display the given variable's documentation and value.
w COMMAND   Display which keystrokes invoke the given command (where-is).
.           Display any available local help at point in the echo area.

C-a         Information about Emacs.
C-c         Emacs copying permission (GNU General Public License).
C-d         Instructions for debugging GNU Emacs.
C-e         External packages and information about Emacs.
C-f         Emacs FAQ.
C-m         How to order printed Emacs manuals.
C-n         News of recent Emacs changes.
C-o         Emacs ordering and distribution information.
C-p         Info about known Emacs problems.
C-t         Emacs TODO list.
C-w         Information on absence of warranty for GNU Emacs.

Emacs Survial With Evil & Family

1 概览

1.1 安装 evil

从网上找到的一个简易的方法,easy to be understood:

1
2
3
4
5
6
(defun require-package (package)
  "Install given PACKAGE."
  (unless (package-installed-p package)
    (unless (assoc package package-archive-contents)
      (package-refresh-contents))
    (package-install package)))
1
2
3
(require-package 'evil)
(require 'evil)
(evil-mode 1)

1.2 modes and states

光标上用点颜色,看起来舒服点。红色是退回Emacs(使用C-z,再按一次C-z回到evil),

1
2
3
(setq evil-emacs-state-cursor '("red" box))
(setq evil-normal-state-cursor '("green" box))
(setq evil-insert-state-cursor '("orange" bar))

这里有个terminology的区别:vim中的mode指的是Normal, Insert, Visual等,vim是模式编辑器。但是在Emacs中,mode是指对特定文本定义的一组快捷键。所以,evil把vim中的mode称作state

2 设置

通过一堆variable设置evil,可以通过 M-x customize-group RET evil RET 查看当前的设置。

setq设置全局变量,setq-default设置buffer-local的变量,而且要在evil加载前修改1

1
2
3
(setq evil-shift-width 8) 
;; Load Evil
(require ’evil) . . .

下面列出的variable,基本上默认值和vim的行为类似,但是evil-want-C-u-scroll默认不是t。

evil-auto-indent [Variable]

t(default), nil,类似vim中的autoindent。

evil-shift-width [Variable]

The number of columns a line is shifted by the commands > and <.

evil-repeat-move-cursor [Variable]

如果t(default),使用.重复时光标改变位置。

evil-find-skip-newlines [Variable]

如果t,那么fFtT会查找到其他行。nil(default)。

evil-move-cursor-back [Variable]

t(default),和vim的行为类似,退出insert state时,光标前移一格。

evil-want-fine-undo [Variable]

If t, then a change-based action like cw may be undone in several steps. If nil (the default), then it is undone in one step.

evil-regexp-search [Variable]

t(default),/?使用正则表达式

evil-search-wrap [Variable]

t(default),/?搜索是到底后从头再搜索。

evil-flash-delay [Variable]

The number of seconds to flash search matches when pressing n and N.

evil-want-C-i-jump [Variable]

If t (the default), then C-i jumps forwards in the jump list. If nil, then C-i inserts a tab.

evil-want-C-u-scroll [Variable]

If t, then C-u scrolls the buffer. If nil (the default), then C-u begins a numeric prefix argument.

2.1 The cursor

这个之前也已经涉及过,现在全面了解下:

1
2
3
(setq evil-emacs-state-cursor '("red" box))
(setq evil-normal-state-cursor '("green" box))
(setq evil-insert-state-cursor '("orange" bar))

一共这么多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
evil-default-cursor
  The default cursor.
evil-normal-state-cursor
  The cursor for Normal state.
evil-insert-state-cursor
  The cursor for Insert state.
evil-visual-state-cursor
  The cursor for Visual state.
evil-replace-state-cursor
  The cursor for Replace state.
evil-operator-state-cursor
  The cursor for Operator-Pending state.
evil-motion-state-cursor
  The cursor for Motion state.
evil-emacs-state-cursor
  The cursor for Emacs state.

2.2 The initial state

默认是进入 Normal State。我也就不修改了。

3 Keymaps

Evil 的键映射存储在多个keymaps中,每个 state 有一个全局的 keymap,比如对应于Normal State 的evil-normal-state-map。 通过 Emacs 的 define-key 来修改。

1
2
;; bind key "w" to command foo
(define-key evil-normal-state-map "w" ’foo)

evil-maps.el 包含所有的键绑定。

1
2
3
4
5
6
7
8
9
10
11
12
evil-normal-state-map
  The global keymap for Normal state.
evil-insert-state-map
  The global keymap for Insert state.
evil-visual-state-map
  The global keymap for Visual state.
evil-replace-state-map
  The global keymap for Replace state.
evil-operator-state-map
  The global keymap for Operator-Pending state.
evil-motion-state-map
  The global keymap for Motion state.

每个 state 还有一个 buffer-local 的 keymap。也就是特定于该 buffer,优先于 global keymap。这些可以通过 mode hook 修改。

1
2
3
4
5
6
7
8
9
10
11
12
evil-normal-state-local-map
  Buffer-local keymap for Normal state.
evil-insert-state-local-map
  Buffer-local keymap for Insert state.
evil-visual-state-local-map
  Buffer-local keymap for Visual state.
evil-replace-state-local-map
  Buffer-local keymap for Replace state.
evil-operator-state-local-map
  Buffer-local keymap for Operator-Pending state.
evil-motion-state-local-map
  Buffer-local keymap for Motion state.

3.1 ‘evil-define-key’

Evil 提供的方法,可以往 Emacs 的 keymap 中添加特定 state 的键绑定。比如:

定义了一个 minor mode,叫做 foo-mode。然后往该 mode 的 normal state 下修改键绑定。

1
2
3
4
5
(define-minor-mode foo-mode
       "Foo mode."
       :keymap (make-sparse-keymap))
     (evil-define-key ’normal foo-mode-map "w" ’bar)
     (evil-define-key ’normal foo-mode-map "e" ’baz)

然后用 hook,添加到 text-mode-hook 里。

1
(add-hook ’text-mode-hook ’foo-mode) ; enable alongside text-mode

Appendix 1

什么是 vim 的 magic?

主要涉及到正则表达式。先留几个参考资料:

  1. vimdoc
  2. vim.vikia

To Be Continued


  1. Strictly speaking, the order only matters if the variable affects the way Evil is loaded. This is the case with some of the ‘evil-want-’ variables.

Linux Useful Tricks

课后任务

使用vagrant搭建Linux虚拟机

官方网址

1 首先安装 virtualbox

2 安装vagrant

3 打开cmd,或者终端,运行以下命令,注意这一步会下载一个Linux发行版,大约3,400M吧。所以,你也可以用迅雷到网上下载下来,然后把 http://files.vagrantup.com/precise32.box 改成你文件的路径,比如我的是file:///Users/pieux/Documents/o/precise32.box

1
2
$ vagrant init precise32 http://files.vagrantup.com/precise32.box
$ vagrant up

4 SSH 进入linux吧!vagrant ssh,退出就是 exit

5 关闭Linux的命令是,休眠vagrant suspend,或者关闭vagrant halt

man 命令

1
2
3
4
5
6
7
8
9
1    使用者在shell中可以操作的指令或可执行档
2 系統核心可呼叫的函数与工具等
3 一些常用的函数(function)与函数库(library),大部分是C的函数库(libc)
4 装置档案的说明,通常在/dev下的档案
5 设定档或者是某些档案的格式
6 游戏(games)
7 惯例与协定等,例如Linux档案系统、网络协定、ASCII code等等的說明
8 系統管理員可用的管理指令
9 跟kernel有关的文件

tree 命令

1
2
3
4
5
tree
-a
-A
-C
man tree

shell 快捷键

编辑命令

1
2
3
4
5
6
7
8
9
10
Ctrl + a :移到命令行首
Ctrl + e :移到命令行尾
Ctrl + f :按字符前移(右向)
Ctrl + b :按字符后移(左向)
Alt + f :按单词前移(右向)
Alt + b :按单词后移(左向)
Ctrl + u :从光标处删除至命令行首
Ctrl + k :从光标处删除至命令行尾
Ctrl + d :删除光标处的字符
Ctrl + y :粘贴至光标后

重新执行命令

1
2
3
4
Ctrl + r:逆向搜索命令历史
Ctrl + g:从历史搜索模式退出
Ctrl + p:历史中的上一条命令
Ctrl + n:历史中的下一条命令

控制命令

1
2
3
4
5
Ctrl + l:清屏
Ctrl + s:阻止屏幕输出
Ctrl + q:允许屏幕输出
Ctrl + c:终止命令
Ctrl + z:挂起命令

grep 命令

1
2
3
4
5
grep
-v 反选
-E 正则
-i 忽略大小写
-n 加上行号

简单的正则表达式:

1
2
3
4
5
6
7
8
^ 行首
$ 行尾
. 任意字符
* >0个重复
+ >1个重复
[Gg], [A-Za-z]
\< 单词首
\> 单词尾

进程相关

1
2
3
4
5
ps -aux | grep process-name
pgrep
kill
pkill
killall

find

1
2
3
4
5
6
7
8
find -name
find -not -name
-i
-type fdl
-mindepth 3
-maxdepth 3
-exec ls -l {} \;
| xargs ls -l

其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
touch 创建文件
alias 别名
history
sudo !! 重执行上一条命令
cd - 进入之前的目录
wc
chmod 
du -hd 1
du -h --max-depth=1
Ctrl-Z 挂起
fg 恢复
> .gitignore
< .gitignore
mv filename.{old,new}
rm !(*.foo|*.bar|*.baz)

git 相关

1
2
3
4
git add -A
git reset --soft
git reset --mixed
git reset --hard

学习资料推荐

http://www.commandlinefu.com/commands/tagged/800/commandfu