From 2dfa17c77f336966f50902e78db9051bdd0a8f55 Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 01:02:30 +0430
Subject: [PATCH 1/8] add register '*'

---
 src/actions/actions.ts   | 25 +++++++++++++++++++++++++
 src/mode/modeHandler.ts  |  7 +++++--
 src/register/register.ts | 10 +++++++---
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/src/actions/actions.ts b/src/actions/actions.ts
index bead742610e..341f53d97d1 100644
--- a/src/actions/actions.ts
+++ b/src/actions/actions.ts
@@ -367,6 +367,31 @@ class CommandNumber extends BaseCommand {
   }
 }
 
+@RegisterAction
+class CommandRegister extends BaseCommand {
+  modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine];
+  keys = ["\"", "<character>"];
+  isCompleteAction = false;
+
+  public async exec(position: Position, vimState: VimState): Promise<VimState> {
+    const register = this.keysPressed[1];
+    vimState.recordedState.registerName = register;
+    return vimState;
+  }
+
+  public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
+    const register = keysPressed[1];
+
+    return super.doesActionApply(vimState, keysPressed) && true;
+  }
+
+  public couldActionApply(vimState: VimState, keysPressed: string[]): boolean {
+    const register = keysPressed[1];
+
+    return super.couldActionApply(vimState, keysPressed) && true;
+  }
+}
+
 @RegisterAction
 class CommandEsc extends BaseCommand {
   modes = [ModeName.Insert, ModeName.Visual, ModeName.VisualLine, ModeName.SearchInProgressMode];
diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts
index b573a23d430..dbc382fdfd5 100644
--- a/src/mode/modeHandler.ts
+++ b/src/mode/modeHandler.ts
@@ -103,8 +103,6 @@ export class VimState {
     }
   }
 
-  public registerName = '"';
-
   /**
    * This is for oddball commands that don't manipulate text in any way.
    */
@@ -302,6 +300,11 @@ export class RecordedState {
    */
   public count: number = 0;
 
+  /**
+   * The register name for this action.
+   */
+  public registerName: string = '"';
+
   public clone(): RecordedState {
     const res = new RecordedState();
 
diff --git a/src/register/register.ts b/src/register/register.ts
index 0bc0947143c..582cdf14814 100644
--- a/src/register/register.ts
+++ b/src/register/register.ts
@@ -18,8 +18,12 @@ export interface IRegisterContent {
 }
 
 export class Register {
+  /**
+   * The '*' is the special register for stroing into system clipboard.
+   */
   private static validRegisters = [
-    '"'
+    '"',
+    '*'
   ];
 
   private static registers: { [key: string]: IRegisterContent } = {
@@ -31,7 +35,7 @@ export class Register {
    * register ".
    */
   public static put(content: string, vimState: VimState): void {
-    const register = vimState.registerName;
+    const register = vimState.recordedState.registerName;
 
     if (Register.validRegisters.indexOf(register) === -1) {
       throw new Error(`Invalid register ${register}`);
@@ -48,7 +52,7 @@ export class Register {
    * register ".
    */
   public static get(vimState: VimState): IRegisterContent {
-    const register = vimState.registerName;
+    const register = vimState.recordedState.registerName;
 
     if (Register.validRegisters.indexOf(register) === -1) {
       throw new Error(`Invalid register ${register}`);

From 321de6979f85144acbb23ea6aa8ba3ca4cddff84 Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 02:03:31 +0430
Subject: [PATCH 2/8] add copy-paste to access system clipboard

---
 typings.json                            |  3 ++
 typings/globals/copy-paste/index.d.ts   | 43 +++++++++++++++++++++++++
 typings/globals/copy-paste/typings.json |  8 +++++
 typings/index.d.ts                      |  1 +
 4 files changed, 55 insertions(+)
 create mode 100644 typings/globals/copy-paste/index.d.ts
 create mode 100644 typings/globals/copy-paste/typings.json

diff --git a/typings.json b/typings.json
index 2ac87d04b11..c1da071f9cd 100644
--- a/typings.json
+++ b/typings.json
@@ -3,5 +3,8 @@
   "dependencies": {
     "diff": "registry:npm/diff#2.0.0+20160211003958",
     "lodash": "registry:npm/lodash#4.0.0+20160416211519"
+  },
+  "globalDependencies": {
+    "copy-paste": "registry:dt/copy-paste#1.1.3+20160117130525"
   }
 }
diff --git a/typings/globals/copy-paste/index.d.ts b/typings/globals/copy-paste/index.d.ts
new file mode 100644
index 00000000000..349e868fc30
--- /dev/null
+++ b/typings/globals/copy-paste/index.d.ts
@@ -0,0 +1,43 @@
+// Generated by typings
+// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/5421783adfaf9b99e9274f4488cfc0ee73f17a56/copy-paste/copy-paste.d.ts
+declare module 'copy-paste' {
+    
+    export type CopyCallback = (err: Error) => void;
+    export type PasteCallback = (err: Error, content: string) => void;
+
+    /**
+     * Asynchronously replaces the current contents of the clip board with text.
+     * 
+     * @param {T} content Takes either a string, array, object, or readable stream.
+     * @return {T} Returns the same value passed in.
+     */
+    export function copy<T>(content: T): T;
+    
+    /**
+     * Asynchronously replaces the current contents of the clip board with text.
+     * 
+     * @param {T} content Takes either a string, array, object, or readable stream.
+     * @param {CopyCallback} callback will fire when the copy operation is complete.
+     * @return {T} Returns the same value passed in.
+     */
+    export function copy<T>(content: T, callback: CopyCallback): T;
+
+
+    /**
+     * Synchronously returns the current contents of the system clip board.
+     * 
+     * Note: The synchronous version of paste is not always availabled.
+     * An error message is shown if the synchronous version of paste is used on an unsupported platform.
+     * The asynchronous version of paste is always available.
+     * 
+     * @return {string} Returns the current contents of the system clip board.
+     */
+    export function paste(): string;
+    
+    /**
+     * Asynchronously returns the current contents of the system clip board.
+     * 
+     * @param {PasteCallback} callback The contents of the system clip board are passed to the callback as the second parameter.
+     */
+    export function paste(callback: PasteCallback): void;
+}
diff --git a/typings/globals/copy-paste/typings.json b/typings/globals/copy-paste/typings.json
new file mode 100644
index 00000000000..5cdb3500fa7
--- /dev/null
+++ b/typings/globals/copy-paste/typings.json
@@ -0,0 +1,8 @@
+{
+  "resolution": "main",
+  "tree": {
+    "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/5421783adfaf9b99e9274f4488cfc0ee73f17a56/copy-paste/copy-paste.d.ts",
+    "raw": "registry:dt/copy-paste#1.1.3+20160117130525",
+    "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/5421783adfaf9b99e9274f4488cfc0ee73f17a56/copy-paste/copy-paste.d.ts"
+  }
+}
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 95cf3b0a29a..6cb68642ea0 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -1,3 +1,4 @@
+/// <reference path="globals/copy-paste/index.d.ts" />
 /// <reference path="modules/diff/index.d.ts" />
 /// <reference path="modules/lodash/index.d.ts" />
 /// <reference path="vscode/index.d.ts" />

From 323a62b093844ad233729d180d56f38530b244f3 Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 02:04:17 +0430
Subject: [PATCH 3/8] read and write to clipboard when register * is accessed

---
 src/actions/actions.ts   |  6 +++---
 src/register/register.ts | 19 +++++++++++++++++--
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/src/actions/actions.ts b/src/actions/actions.ts
index 341f53d97d1..d217a356019 100644
--- a/src/actions/actions.ts
+++ b/src/actions/actions.ts
@@ -917,7 +917,7 @@ export class PutCommand extends BaseCommand {
     canBeRepeatedWithDot = true;
 
     public async exec(position: Position, vimState: VimState, before: boolean = false, adjustIndent: boolean = false): Promise<VimState> {
-        const register = Register.get(vimState);
+        const register = await Register.get(vimState);
         const dest = before ? position : position.getRight();
         let text = register.text;
 
@@ -985,7 +985,7 @@ export class GPutCommand extends BaseCommand {
       }
 
   public async execCount(position: Position, vimState: VimState): Promise<VimState> {
-    const register = Register.get(vimState);
+    const register = await Register.get(vimState);
     const addedLinesCount = register.text.split('\n').length;
     const result = await super.execCount(position, vimState);
 
@@ -1104,7 +1104,7 @@ export class GPutBeforeCommand extends BaseCommand {
 
   public async exec(position: Position, vimState: VimState): Promise<VimState> {
     const result = await new PutCommand().exec(position, vimState, true);
-    const register = Register.get(vimState);
+    const register = await Register.get(vimState);
     const addedLinesCount = register.text.split('\n').length;
 
     if (vimState.effectiveRegisterMode() === RegisterMode.LineWise) {
diff --git a/src/register/register.ts b/src/register/register.ts
index 582cdf14814..093feb66027 100644
--- a/src/register/register.ts
+++ b/src/register/register.ts
@@ -1,5 +1,5 @@
 import { VimState } from './../mode/modeHandler';
-
+import * as clipboard from 'copy-paste';
 /**
  * There are two different modes of copy/paste in Vim - copy by character
  * and copy by line. Copy by line typically happens in Visual Line mode, but
@@ -41,6 +41,10 @@ export class Register {
       throw new Error(`Invalid register ${register}`);
     }
 
+    if (register === '*') {
+      clipboard.copy(content);
+    }
+
     Register.registers[register] = {
       text    : content,
       registerMode: vimState.effectiveRegisterMode(),
@@ -51,13 +55,24 @@ export class Register {
    * Gets content from a register. If none is specified, uses the default
    * register ".
    */
-  public static get(vimState: VimState): IRegisterContent {
+  public static async get(vimState: VimState): Promise<IRegisterContent> {
     const register = vimState.recordedState.registerName;
 
     if (Register.validRegisters.indexOf(register) === -1) {
       throw new Error(`Invalid register ${register}`);
     }
 
+    /* Read from system clipboard */
+    if (register === '*') {
+      const text = await new Promise<string>((resolve, reject) =>
+        clipboard.paste((err, text) => {
+          if (err) { reject(err); }
+          else { resolve(text); }
+        })
+      );
+      Register.registers[register].text = text;
+    }
+
     return Register.registers[register];
   }
 }

From 60e2ed22869fa365cd5f9cbf3baf2c2908fedceb Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 02:25:33 +0430
Subject: [PATCH 4/8] unit tests for registers

---
 test/register/register.test.ts | 57 ++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 test/register/register.test.ts

diff --git a/test/register/register.test.ts b/test/register/register.test.ts
new file mode 100644
index 00000000000..d905e2c083a
--- /dev/null
+++ b/test/register/register.test.ts
@@ -0,0 +1,57 @@
+"use strict";
+
+import { ModeHandler } from "../../src/mode/modeHandler";
+import { setupWorkspace, cleanUpWorkspace, assertEqualLines } from '../testUtils';
+
+suite("register", () => {
+
+  let modeHandler: ModeHandler;
+
+  setup(async () => {
+    await setupWorkspace();
+
+    modeHandler = new ModeHandler();
+  });
+
+  suiteTeardown(cleanUpWorkspace);
+
+  test("basic register put test", async () => {
+    await modeHandler.handleMultipleKeyEvents(
+      'iblah blah'.split('')
+    );
+
+    await modeHandler.handleMultipleKeyEvents([
+      '<esc>',
+      '^', '"', '"', 'D', '"', '"', 'p', '"', '"', 'p'
+    ]);
+
+    await assertEqualLines(["blah blahblah blah"]);
+  });
+
+  test("test yy and '*' register", async () => {
+    await modeHandler.handleMultipleKeyEvents(
+      'iblah blah\nblah'.split('')
+    );
+
+    await modeHandler.handleMultipleKeyEvents([
+      '<esc>',
+      '^', '"', '*', 'y', 'y', '"', '*', 'p'
+    ]);
+
+    await assertEqualLines(["blah blah", "blah", "blah"]);
+  });
+
+  test("test two seperate registers", async () => {
+    await modeHandler.handleMultipleKeyEvents(
+      'iblah blah\nblah'.split('')
+    );
+    /* Register '"' is the default register */
+    await modeHandler.handleMultipleKeyEvents([
+      '<esc>',
+      'g', 'g', '"', '*', 'y', 'y', 'j', 'y', 'y', '"', '*', 'p', 'p',
+    ]);
+
+    await assertEqualLines(["blah blah", "blah", "blah blah", "blah"]);
+  });
+
+});
\ No newline at end of file

From f3ecd4056c99d2f37571bb3bcc19c613e7e715ce Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 02:45:36 +0430
Subject: [PATCH 5/8] support alphanameric registers & update roadmap

---
 ROADMAP.md               |  3 ++-
 src/register/register.ts | 26 ++++++++++++++++++--------
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/ROADMAP.md b/ROADMAP.md
index 5b0c9928fbd..affe8c4ef8c 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -183,7 +183,8 @@ Status | Command | Description
 
 Status | Command | Description
 ---|--------|------------------------------
-   | "{char}	        | use register {char} for the next delete, yank, or put
+:warning:   | "{char}	        | use register {char} for the next delete, yank, or put
+:white_check_mark:   | "*	        | use register `*` to access system clipboard
    | :reg		| show the contents of all registers
    | :reg {arg}	        | show the contents of registers mentioned in {arg}
 :white_check_mark:   | :1234:  y{motion}	| yank the text moved over with {motion} into a register
diff --git a/src/register/register.ts b/src/register/register.ts
index 093feb66027..65d749ec314 100644
--- a/src/register/register.ts
+++ b/src/register/register.ts
@@ -19,17 +19,23 @@ export interface IRegisterContent {
 
 export class Register {
   /**
+   * The '"' is the unnamed register.
    * The '*' is the special register for stroing into system clipboard.
+   * TODO: Read-Only registers
+   *  '.' register has the last inserted text.
+   *  '%' register has the current file path.
+   *  ':' is the most recently executed command.
+   *  '#' is the name of last edited file. (low priority)
    */
-  private static validRegisters = [
-    '"',
-    '*'
-  ];
-
   private static registers: { [key: string]: IRegisterContent } = {
-    '"': { text: "", registerMode: RegisterMode.CharacterWise }
+    '"': { text: "", registerMode: RegisterMode.CharacterWise },
+    '*': { text: "", registerMode: RegisterMode.CharacterWise }
   };
 
+  private static isValidRegister(register: string): boolean {
+    return register in Register.registers || /^[a-z0-9]+$/i.test(register);
+  }
+
   /**
    * Puts content in a register. If none is specified, uses the default
    * register ".
@@ -37,7 +43,7 @@ export class Register {
   public static put(content: string, vimState: VimState): void {
     const register = vimState.recordedState.registerName;
 
-    if (Register.validRegisters.indexOf(register) === -1) {
+    if (!Register.isValidRegister(register)) {
       throw new Error(`Invalid register ${register}`);
     }
 
@@ -58,10 +64,14 @@ export class Register {
   public static async get(vimState: VimState): Promise<IRegisterContent> {
     const register = vimState.recordedState.registerName;
 
-    if (Register.validRegisters.indexOf(register) === -1) {
+    if (!Register.isValidRegister(register)) {
       throw new Error(`Invalid register ${register}`);
     }
 
+    if (!Register.registers[register]) {
+      Register.registers[register] = { text: "", registerMode: RegisterMode.CharacterWise };
+    }
+
     /* Read from system clipboard */
     if (register === '*') {
       const text = await new Promise<string>((resolve, reject) =>

From 3809e766e6a409badeb5bcf01be21801c92b2358 Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 16:17:28 +0430
Subject: [PATCH 6/8] trying to fix ci build

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 7bf884db2b7..ec3834f0cb5 100644
--- a/package.json
+++ b/package.json
@@ -160,7 +160,7 @@
         }
     },
     "scripts": {
-        "vscode:prepublish": "node ./node_modules/vscode/bin/compile",
+        "vscode:prepublish": "node ./node_modules/vscode/bin/compile -p ./",
         "compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
         "test": "node ./node_modules/vscode/bin/test",
         "postinstall": "node ./node_modules/vscode/bin/install && gulp init"
@@ -188,4 +188,4 @@
         "typings": "^1.0.4",
         "vscode": "^0.11.13"
     }
-}
\ No newline at end of file
+}

From b7d21dea0f05c32637354784b40a456097636b7c Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Mon, 1 Aug 2016 16:27:00 +0430
Subject: [PATCH 7/8] Fix gulp:tslint errors

---
 src/actions/actions.ts       | 4 ++--
 src/register/register.ts     | 9 ++++++---
 test/mode/modeNormal.test.ts | 2 +-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/actions/actions.ts b/src/actions/actions.ts
index d217a356019..a6b174325dc 100644
--- a/src/actions/actions.ts
+++ b/src/actions/actions.ts
@@ -382,13 +382,13 @@ class CommandRegister extends BaseCommand {
   public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
     const register = keysPressed[1];
 
-    return super.doesActionApply(vimState, keysPressed) && true;
+    return super.doesActionApply(vimState, keysPressed) && Register.isValidRegister(register);
   }
 
   public couldActionApply(vimState: VimState, keysPressed: string[]): boolean {
     const register = keysPressed[1];
 
-    return super.couldActionApply(vimState, keysPressed) && true;
+    return super.couldActionApply(vimState, keysPressed) && Register.isValidRegister(register);
   }
 }
 
diff --git a/src/register/register.ts b/src/register/register.ts
index 65d749ec314..62fcd85f6a3 100644
--- a/src/register/register.ts
+++ b/src/register/register.ts
@@ -32,7 +32,7 @@ export class Register {
     '*': { text: "", registerMode: RegisterMode.CharacterWise }
   };
 
-  private static isValidRegister(register: string): boolean {
+  public static isValidRegister(register: string): boolean {
     return register in Register.registers || /^[a-z0-9]+$/i.test(register);
   }
 
@@ -76,8 +76,11 @@ export class Register {
     if (register === '*') {
       const text = await new Promise<string>((resolve, reject) =>
         clipboard.paste((err, text) => {
-          if (err) { reject(err); }
-          else { resolve(text); }
+          if (err) {
+            reject(err);
+          } else {
+            resolve(text);
+          }
         })
       );
       Register.registers[register].text = text;
diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts
index d4b5b16785b..47787dad65a 100644
--- a/test/mode/modeNormal.test.ts
+++ b/test/mode/modeNormal.test.ts
@@ -1025,5 +1025,5 @@ suite("Mode Normal", () => {
       start: ["|blah blah"],
       keysPressed: "Yp",
       end: ["blah blah", "|blah blah"]
-    })
+    });
 });
\ No newline at end of file

From bf4f2a76bf3afbc14b3e11c832f34db4de809f55 Mon Sep 17 00:00:00 2001
From: amin roosta <amin.roosta@outlook.com>
Date: Tue, 2 Aug 2016 13:30:23 +0430
Subject: [PATCH 8/8] use new test style in register.test.ts

---
 package.json                   |  1 +
 test/register/register.test.ts | 64 +++++++++++++++-------------------
 2 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/package.json b/package.json
index ec3834f0cb5..7c06a49dd38 100644
--- a/package.json
+++ b/package.json
@@ -166,6 +166,7 @@
         "postinstall": "node ./node_modules/vscode/bin/install && gulp init"
     },
     "dependencies": {
+        "copy-paste": "^1.3.0",
         "diff": "^2.2.3",
         "lodash": "^4.12.0"
     },
diff --git a/test/register/register.test.ts b/test/register/register.test.ts
index d905e2c083a..3e1ada972ec 100644
--- a/test/register/register.test.ts
+++ b/test/register/register.test.ts
@@ -2,56 +2,50 @@
 
 import { ModeHandler } from "../../src/mode/modeHandler";
 import { setupWorkspace, cleanUpWorkspace, assertEqualLines } from '../testUtils';
+import { getTestingFunctions } from '../testSimplifier';
+import * as clipboard from 'copy-paste';
 
 suite("register", () => {
+  let modeHandler: ModeHandler = new ModeHandler();
 
-  let modeHandler: ModeHandler;
+  let {
+      newTest,
+      newTestOnly,
+  } = getTestingFunctions(modeHandler);
 
   setup(async () => {
     await setupWorkspace();
-
-    modeHandler = new ModeHandler();
   });
 
   suiteTeardown(cleanUpWorkspace);
 
-  test("basic register put test", async () => {
-    await modeHandler.handleMultipleKeyEvents(
-      'iblah blah'.split('')
-    );
-
-    await modeHandler.handleMultipleKeyEvents([
-      '<esc>',
-      '^', '"', '"', 'D', '"', '"', 'p', '"', '"', 'p'
-    ]);
-
-    await assertEqualLines(["blah blahblah blah"]);
+  newTest({
+    title: "Can copy to a register",
+    start: ['|one', 'two'],
+    keysPressed: '"add"ap',
+    end: ["two", "|one"],
   });
 
-  test("test yy and '*' register", async () => {
-    await modeHandler.handleMultipleKeyEvents(
-      'iblah blah\nblah'.split('')
-    );
-
-    await modeHandler.handleMultipleKeyEvents([
-      '<esc>',
-      '^', '"', '*', 'y', 'y', '"', '*', 'p'
-    ]);
+  newTest({
+    title: "Can copy to a register",
+    start: ['|one', 'two'],
+    keysPressed: '"add"ap',
+    end: ["two", "|one"],
+  });
 
-    await assertEqualLines(["blah blah", "blah", "blah"]);
+  clipboard.copy("12345");
+  newTest({
+    title: "Can access '*' (clipboard) register",
+    start: ['|one'],
+    keysPressed: '"*P',
+    end: ["1234|5one"],
   });
 
-  test("test two seperate registers", async () => {
-    await modeHandler.handleMultipleKeyEvents(
-      'iblah blah\nblah'.split('')
-    );
-    /* Register '"' is the default register */
-    await modeHandler.handleMultipleKeyEvents([
-      '<esc>',
-      'g', 'g', '"', '*', 'y', 'y', 'j', 'y', 'y', '"', '*', 'p', 'p',
-    ]);
-
-    await assertEqualLines(["blah blah", "blah", "blah blah", "blah"]);
+  newTest({
+    title: "Can use two registers together",
+    start: ['|one', "two"],
+    keysPressed: '"*yyjyy"*pp',
+    end: ["one", "two", "one", "|two"],
   });
 
 });
\ No newline at end of file