Corrosion initial contribution to Eclipse.org

See https://bugs.eclipse.org/bugs/show_bug.cgi?id=529673 and
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=15779

This commit contains the code that was approved in
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=15779 (Bulk of code),
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=15836 (rustup-init.sh),
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=15835 (Rust TML),
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=15793 (TOML TML), along
with tests and docs which are not included in the jar

Change-Id: Ic5be2f019b1f4a47613db348fb849f9dbe20693e
Signed-off-by: Lucas Bullen <lbullen@redhat.com>
diff --git a/.project b/.project
new file mode 100644
index 0000000..4e2da21
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>corrosion</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9d582b9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,26 @@
+language: java
+dist: trusty
+jdk: oraclejdk8
+sudo: required
+
+install:
+  - curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2017-11-29 -y
+  - export PATH=$HOME/.cargo/bin/:$PATH
+  - rustup component add rust-src --toolchain nightly-2017-11-29
+  - rustup component add rust-analysis --toolchain nightly-2017-11-29
+  - rustup component add rls-preview --toolchain nightly-2017-11-29
+
+before_script:
+  - "export DISPLAY=:99.0"
+  - "sh -e /etc/init.d/xvfb start"
+  - sleep 3 # give xvfb some time to start
+  - cargo --version
+  - rustup show
+
+script:
+  - if [[ $TRAVIS_PULL_REQUEST == "false" && $TRAVIS_BRANCH == "master" ]] ; then
+       mvn clean install;
+    else
+       mvn clean verify;
+    fi
+after_failure: "cat /home/travis/build/LucasBullen/corrosion/org.eclipse.corrosion.tests/target/work/data/.metadata/.log"
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d3087e4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a) in the case of the initial Contributor, the initial content
+     Distributed under this Agreement, and
+
+  b) in the case of each subsequent Contributor:
+     i) changes to the Program, and
+     ii) additions to the Program;
+  where such changes and/or additions to the Program originate from
+  and are Distributed by that particular Contributor. A Contribution
+  "originates" from a Contributor if it was added to the Program by
+  such Contributor itself or anyone acting on such Contributor's behalf.
+  Contributions do not include changes or additions to the Program that
+  are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+  a) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free copyright
+  license to reproduce, prepare Derivative Works of, publicly display,
+  publicly perform, Distribute and sublicense the Contribution of such
+  Contributor, if any, and such Derivative Works.
+
+  b) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free patent
+  license under Licensed Patents to make, use, sell, offer to sell,
+  import and otherwise transfer the Contribution of such Contributor,
+  if any, in Source Code or other form. This patent license shall
+  apply to the combination of the Contribution and the Program if, at
+  the time the Contribution is added by the Contributor, such addition
+  of the Contribution causes such combination to be covered by the
+  Licensed Patents. The patent license shall not apply to any other
+  combinations which include the Contribution. No hardware per se is
+  licensed hereunder.
+
+  c) Recipient understands that although each Contributor grants the
+  licenses to its Contributions set forth herein, no assurances are
+  provided by any Contributor that the Program does not infringe the
+  patent or other intellectual property rights of any other entity.
+  Each Contributor disclaims any liability to Recipient for claims
+  brought by any other entity based on infringement of intellectual
+  property rights or otherwise. As a condition to exercising the
+  rights and licenses granted hereunder, each Recipient hereby
+  assumes sole responsibility to secure any other intellectual
+  property rights needed, if any. For example, if a third party
+  patent license is required to allow Recipient to Distribute the
+  Program, it is Recipient's responsibility to acquire that license
+  before distributing the Program.
+
+  d) Each Contributor represents that to its knowledge it has
+  sufficient copyright rights in its Contribution, if any, to grant
+  the copyright license set forth in this Agreement.
+
+  e) Notwithstanding the terms of any Secondary License, no
+  Contributor makes additional grants to any Recipient (other than
+  those set forth in this Agreement) as a result of such Recipient's
+  receipt of the Program under the terms of a Secondary License
+  (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+  a) the Program must also be made available as Source Code, in
+  accordance with section 3.2, and the Contributor must accompany
+  the Program with a statement that the Source Code for the Program
+  is available under this Agreement, and informs Recipients how to
+  obtain it in a reasonable manner on or through a medium customarily
+  used for software exchange; and
+
+  b) the Contributor may Distribute the Program under a license
+  different than this Agreement, provided that such license:
+     i) effectively disclaims on behalf of all other Contributors all
+     warranties and conditions, express and implied, including
+     warranties or conditions of title and non-infringement, and
+     implied warranties or conditions of merchantability and fitness
+     for a particular purpose;
+
+     ii) effectively excludes on behalf of all other Contributors all
+     liability for damages, including direct, indirect, special,
+     incidental and consequential damages, such as lost profits;
+
+     iii) does not attempt to limit or alter the recipients' rights
+     in the Source Code under section 3.2; and
+
+     iv) requires any subsequent distribution of the Program by any
+     party to be under a license that satisfies the requirements
+     of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+  a) it must be made available under this Agreement, or if the
+  Program (i) is combined with other material in a separate file or
+  files made available under a Secondary License, and (ii) the initial
+  Contributor attached to the Source Code the notice described in
+  Exhibit A of this Agreement, then the Program may be made available
+  under the terms of such Secondary Licenses, and
+
+  b) a copy of this Agreement must be included with each copy of
+  the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+PURPOSE. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following 
+Secondary Licenses when the conditions for such availability set forth 
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+  Simply including a copy of this Agreement, including this Exhibit A
+  is not sufficient to license the Source Code under Secondary Licenses.
+
+  If it is not possible or desirable to put the notice in a particular
+  file, then You may include the notice in a location (such as a LICENSE
+  file in a relevant directory) where a recipient would be likely to
+  look for such a notice.
+
+  You may add additional accurate notices of copyright ownership.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..21985ad
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+# Corrosion
+
+> Corrosion was formerly called RedOx, but required a name change due to naming overlap with another project ([See issue #24](https://github.com/LucasBullen/redOx/issues/24))
+
+Support for Rust editing in Eclipse IDE.
+
+Corrosion is a Rust development plugin for the Eclipse IDE. Both [issue reports](https://github.com/LucasBullen/corrosion/issues) and [pull requests](https://github.com/LucasBullen/corrosion/pulls) are greatly appreciated.
+
+[![Build Status](https://travis-ci.org/LucasBullen/corrosion.svg?branch=master)](https://travis-ci.org/LucasBullen/corrosion)
+
+![Screenshot](images/editorOverview.png "Screenshot of Corrosion editor")
+
+## Installation
+Refer to our [Installation Guide](documentation/Installation.md)
+
+## Prerequisites
+
+The Rustup and Cargo commands are required for accessing the language server and performing most tasks. Go into the Rust preferences and either install the commands or input their paths if not automatically found.
+
+## Contributing
+[Issue reports](https://github.com/LucasBullen/corrosion/issues) and [pull requests](https://github.com/LucasBullen/corrosion/pulls) are always appreciated.
+
+For setting up Corrosion for testing and development follow the [Using Github Installation Instructions](documentation/Installation.md#using-github)
+
+The p2 repository is not kept up to date with the master branch. Releases to the p2 repository will be made in more controlled released after the initial release of Corrosion v1.
+
+## Concept
+
+Corrosion uses the [lsp4e](https://projects.eclipse.org/projects/technology.lsp4e) project to integrate with the [Rust Language Server](https://github.com/rust-lang-nursery/rls) and [TM4E](https://projects.eclipse.org/projects/technology.tm4e) project to provide syntax highlighting in order to provide a rich Rust editor in the Eclipse IDE.
+
+The Rust and Cargo logos are owned by Mozilla and distributed under the terms of the [Creative Commons Attribution license (CC-BY)](https://creativecommons.org/licenses/by/4.0/). [More Info](https://www.rust-lang.org/en-US/legal.html)
diff --git a/documentation/Installation.md b/documentation/Installation.md
new file mode 100644
index 0000000..bd39973
--- /dev/null
+++ b/documentation/Installation.md
@@ -0,0 +1,32 @@
+## Installing Corrosion
+
+### Using Eclipse Marketplace
+Download [Corrosion from the Eclipse Marketplace](https://marketplace.eclipse.org/content/corrosion-rust-edition-eclipse-ide)
+For further instructions on how to install using Eclipse Marketplace, see [their tutorial](https://marketplace.eclipse.org/marketplace-client-intro?mpc_install=3835145)
+
+### Using p2 repository
+The p2 site: https://lucasbullen.github.io/corrosion/site/
+ - Open Eclipse IDE
+ - Open the Install New Software Wizard (Under the Help menu)
+ - Enter https://lucasbullen.github.io/corrosion/site/ in the site field
+ - Select Corrosion - Rust in Eclipse IDE and click Next
+ - Wait for the dependencies to load
+ - Press Next again
+ - Accept the license and press Finish
+ - Restart Eclipse
+
+### Using Github
+##### For contributors and testers, This will allow running the plugin within a child Eclipse to test and develop new features 
+ - Download [Eclipse for Eclipse Contributors](https://www.eclipse.org/downloads/packages/eclipse-ide-eclipse-committers/oxygen2) or any version of Eclipse with the `Eclipse Plug-in Development Environment` package
+ - Clone the repo: https://github.com/LucasBullen/corrosion
+ - In the root of the repository, run `mvn clean verify` (You will need [Maven](http://maven.apache.org/))
+ - Open the following projects in Eclipse:
+   - org.eclipse.corrosion
+   - target-platform
+   - org.eclipse.corrosion.tests (If you intend on contributing)
+ - Set the Target Platform
+   - Preferences > Plug-in Development > Target Platform
+   - Select the `corrosion` target defininition
+ - Run the `org.eclipse.corrosion` project as an `Eclipse Application`
+
+
diff --git a/images/editorOverview.png b/images/editorOverview.png
new file mode 100644
index 0000000..85e6ada
--- /dev/null
+++ b/images/editorOverview.png
Binary files differ
diff --git a/images/preferencesOverview.png b/images/preferencesOverview.png
new file mode 100644
index 0000000..d35bff3
--- /dev/null
+++ b/images/preferencesOverview.png
Binary files differ
diff --git a/org.eclipse.corrosion.feature/.project b/org.eclipse.corrosion.feature/.project
new file mode 100644
index 0000000..b3b4521
--- /dev/null
+++ b/org.eclipse.corrosion.feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.corrosion.feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.corrosion.feature/build.properties b/org.eclipse.corrosion.feature/build.properties
new file mode 100644
index 0000000..b692f5f
--- /dev/null
+++ b/org.eclipse.corrosion.feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes = feature.xml,\
+               feature.properties
\ No newline at end of file
diff --git a/org.eclipse.corrosion.feature/category.xml b/org.eclipse.corrosion.feature/category.xml
new file mode 100644
index 0000000..6a53fd9
--- /dev/null
+++ b/org.eclipse.corrosion.feature/category.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+   <feature url="features/org.eclipse.corrosion.feature_0.1.0.qualifier.jar" id="org.eclipse.corrosion.feature" version="0.1.0.qualifier">
+      <category name="org.eclipse.corrosion.category"/>
+   </feature>
+   <category-def name="org.eclipse.corrosion.category" label="Corrosion: Rust edition in Eclipse IDE">
+      <description>
+         Corrosion enables Rust application development in the Eclipse IDE.
+      </description>
+   </category-def>
+</site>
diff --git a/org.eclipse.corrosion.feature/feature.properties b/org.eclipse.corrosion.feature/feature.properties
new file mode 100644
index 0000000..1b6c91a
--- /dev/null
+++ b/org.eclipse.corrosion.feature/feature.properties
@@ -0,0 +1,9 @@
+name=Corrosion: Rust edition in Eclipse IDE
+description=Rust editor in Eclipse IDE. Relies on the Rust Language Server (RLS).
+copyright=Copyright (c) 2017 Red Hat Inc. and others.\
+\
+This program and the accompanying materials are made\
+available under the terms of the Eclipse Public License 2.0\
+which is available at https://www.eclipse.org/legal/epl-2.0/\
+\
+SPDX-License-Identifier: EPL-2.0\
\ No newline at end of file
diff --git a/org.eclipse.corrosion.feature/feature.xml b/org.eclipse.corrosion.feature/feature.xml
new file mode 100644
index 0000000..0d75f37
--- /dev/null
+++ b/org.eclipse.corrosion.feature/feature.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.corrosion.feature"
+      label="%name"
+      version="0.1.0.qualifier"
+      provider-name="Red Hat Inc."
+      license-feature="org.eclipse.license"
+      license-feature-version="0.0.0">
+
+   <description>
+      %description
+   </description>
+
+   <copyright>
+      %copyright
+   </copyright>
+
+   <license url="%licenseURL">
+      %license
+   </license>
+
+   <plugin
+         id="org.eclipse.corrosion"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.google.gson"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.google.guava"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.apache.commons.lang"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.lsp4e"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.lsp4j"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.lsp4j.jsonrpc"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.tm4e.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.tm4e.languageconfiguration"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.tm4e.markdown"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.tm4e.registry"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.tm4e.ui"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.xtext.xbase.lib"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.jcodings"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.joni"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.notifications.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.notifications.ui"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.screenshots"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.ui"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.commons.workbench"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.wikitext"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.mylyn.wikitext.markdown"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.jsoup"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
diff --git a/org.eclipse.corrosion.feature/pom.xml b/org.eclipse.corrosion.feature/pom.xml
new file mode 100644
index 0000000..cc1a7f3
--- /dev/null
+++ b/org.eclipse.corrosion.feature/pom.xml
@@ -0,0 +1,10 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>org.eclipse.corrosion.feature</artifactId>
+	<parent>
+		<groupId>org.eclipse.corrosion</groupId>
+		<artifactId>parent</artifactId>
+		<version>0.1.0-SNAPSHOT</version>
+	</parent>
+	<packaging>eclipse-feature</packaging>
+</project>
\ No newline at end of file
diff --git a/org.eclipse.corrosion.tests/.classpath b/org.eclipse.corrosion.tests/.classpath
new file mode 100644
index 0000000..43b9862
--- /dev/null
+++ b/org.eclipse.corrosion.tests/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.corrosion.tests/.gitignore b/org.eclipse.corrosion.tests/.gitignore
new file mode 100644
index 0000000..09e3bc9
--- /dev/null
+++ b/org.eclipse.corrosion.tests/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/org.eclipse.corrosion.tests/.project b/org.eclipse.corrosion.tests/.project
new file mode 100644
index 0000000..96ec968
--- /dev/null
+++ b/org.eclipse.corrosion.tests/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.corrosion.tests</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.corrosion.tests/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.corrosion.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0c68a61
--- /dev/null
+++ b/org.eclipse.corrosion.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.eclipse.corrosion.tests/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.corrosion.tests/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.corrosion.tests/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.corrosion.tests/META-INF/MANIFEST.MF b/org.eclipse.corrosion.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..a4673d0
--- /dev/null
+++ b/org.eclipse.corrosion.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,27 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Tests for Corrosion
+Bundle-SymbolicName: org.eclipse.corrosion.tests;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Bundle-Vendor: Red Hat Inc.
+Eclipse-BundleShape: dir
+Automatic-Module-Name: org.eclipse.corrosion.tests
+Require-Bundle: org.eclipse.corrosion;bundle-version="0.1.0",
+ org.junit;bundle-version="4.11.0",
+ org.eclipse.core.runtime;bundle-version="3.13.0",
+ org.eclipse.core.resources;bundle-version="3.12.0",
+ org.eclipse.ui;bundle-version="3.109.0",
+ org.apache.commons.io;bundle-version="2.2.0",
+ org.eclipse.ui.tests.harness;bundle-version="1.4.100",
+ org.eclipse.ui.ide;bundle-version="3.13.1",
+ org.eclipse.ui.genericeditor;bundle-version="1.0.1",
+ org.eclipse.lsp4e;bundle-version="0.5.0",
+ org.eclipse.lsp4j,
+ org.eclipse.lsp4j.jsonrpc;bundle-version="0.2.0",
+ org.eclipse.ui.editors,
+ org.eclipse.debug.core,
+ org.eclipse.core.expressions,
+ org.eclipse.search,
+ org.eclipse.ui.console
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.corrosion.tests/build.properties b/org.eclipse.corrosion.tests/build.properties
new file mode 100644
index 0000000..9d8fb6f
--- /dev/null
+++ b/org.eclipse.corrosion.tests/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               projects/,\
+               .
diff --git a/org.eclipse.corrosion.tests/pom.xml b/org.eclipse.corrosion.tests/pom.xml
new file mode 100644
index 0000000..6320e88
--- /dev/null
+++ b/org.eclipse.corrosion.tests/pom.xml
@@ -0,0 +1,29 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>org.eclipse.corrosion.tests</artifactId>
+	<parent>
+		<groupId>org.eclipse.corrosion</groupId>
+		<artifactId>parent</artifactId>
+		<version>0.1.0-SNAPSHOT</version>
+	</parent>
+	<packaging>eclipse-test-plugin</packaging>
+
+	<properties>
+		<testSuite>${project.artifactId}</testSuite>
+		<testClass>org.eclipse.corrosion.tests.AllTests</testClass>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-surefire-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<useUIThread>true</useUIThread>
+					<useUIHarness>true</useUIHarness>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/org.eclipse.corrosion.tests/projects/basic/Cargo.toml b/org.eclipse.corrosion.tests/projects/basic/Cargo.toml
new file mode 100644
index 0000000..7d54538
--- /dev/null
+++ b/org.eclipse.corrosion.tests/projects/basic/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "basic"
+version = "0.1.0"
+authors = ["Lucas Bullen <lbullen@redhat.com>"]
+
+[dependencies]
\ No newline at end of file
diff --git a/org.eclipse.corrosion.tests/projects/basic/src/main.rs b/org.eclipse.corrosion.tests/projects/basic/src/main.rs
new file mode 100644
index 0000000..1a3d60a
--- /dev/null
+++ b/org.eclipse.corrosion.tests/projects/basic/src/main.rs
@@ -0,0 +1,11 @@
+fn main() {
+    let n = 5;
+
+    if n < 0 {
+        print!("{} is negative", n);
+    } else if n > 0 {
+        print!("{} is positive", n);
+    } else {
+        print!("{} is zero", n);
+    }
+}
diff --git a/org.eclipse.corrosion.tests/projects/basic_errors/Cargo.toml b/org.eclipse.corrosion.tests/projects/basic_errors/Cargo.toml
new file mode 100644
index 0000000..e67e620
--- /dev/null
+++ b/org.eclipse.corrosion.tests/projects/basic_errors/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "basic_errors"
+version = "0.1.0"
+authors = ["Lucas Bullen <lbullen@redhat.com>"]
+
+[dependencies]
\ No newline at end of file
diff --git a/org.eclipse.corrosion.tests/projects/basic_errors/src/main.rs b/org.eclipse.corrosion.tests/projects/basic_errors/src/main.rs
new file mode 100644
index 0000000..d199e50
--- /dev/null
+++ b/org.eclipse.corrosion.tests/projects/basic_errors/src/main.rs
@@ -0,0 +1,2 @@
+fn main() {
+    let n = 5;
diff --git a/org.eclipse.corrosion.tests/projects/not_cargo/src/main.rs b/org.eclipse.corrosion.tests/projects/not_cargo/src/main.rs
new file mode 100644
index 0000000..1a3d60a
--- /dev/null
+++ b/org.eclipse.corrosion.tests/projects/not_cargo/src/main.rs
@@ -0,0 +1,11 @@
+fn main() {
+    let n = 5;
+
+    if n < 0 {
+        print!("{} is negative", n);
+    } else if n > 0 {
+        print!("{} is positive", n);
+    } else {
+        print!("{} is zero", n);
+    }
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AbstractCorrosionTest.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AbstractCorrosionTest.java
new file mode 100644
index 0000000..99340b8
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AbstractCorrosionTest.java
@@ -0,0 +1,113 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Mickael Istria (Red Hat Inc.) - Source Reference
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * Takes care of creating a temporary project and resource before test and to
+ * clean it up after.
+ */
+public class AbstractCorrosionTest {
+
+	private Map<String, IProject> provisionedProjects;
+
+	@Before
+	public void setUp() throws Exception {
+		this.provisionedProjects = new HashMap<>();
+	}
+
+	/**
+	 *
+	 * @param projectName
+	 *            the name that will be used as prefix for the project, and that
+	 *            will be used to find the content of the project from the plugin
+	 *            "projects" folder
+	 * @throws IOException
+	 * @throws CoreException
+	 */
+	protected IProject provisionProject(String projectName) throws IOException, CoreException {
+		URL url = FileLocator.find(Platform.getBundle("org.eclipse.corrosion.tests"),
+				Path.fromPortableString("projects/" + projectName), Collections.emptyMap());
+		url = FileLocator.toFileURL(url);
+		File folder = new File(url.getFile());
+		if (folder != null && folder.exists()) {
+			IProject project = ResourcesPlugin.getWorkspace().getRoot()
+					.getProject(projectName + "_" + getClass().getName() + "_" + System.currentTimeMillis());
+			project.create(new NullProgressMonitor());
+			this.provisionedProjects.put(projectName, project);
+			FileUtils.copyDirectory(folder, project.getLocation().toFile());
+			project.open(new NullProgressMonitor());
+			project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
+			return project;
+		} else {
+			return null;
+		}
+	}
+
+	@After
+	public void tearDown() throws CoreException {
+		for (String projectName : this.provisionedProjects.keySet()) {
+			try {
+				getProject(projectName).delete(true, new NullProgressMonitor());
+			} catch (CoreException | IOException e) {
+				e.printStackTrace();
+			}
+		}
+		PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
+	}
+
+	/**
+	 * @param projectPrefix
+	 *            the prefix of the project, as it can be found in plugin's
+	 *            "projects" folder
+	 * @return a project with the content from the specified projectPrefix
+	 * @throws CoreException
+	 * @throws IOException
+	 */
+	protected IProject getProject(String projectPrefix) throws IOException, CoreException {
+		if (!this.provisionedProjects.containsKey(projectPrefix)) {
+			provisionProject(projectPrefix);
+		}
+		return this.provisionedProjects.get(projectPrefix);
+	}
+
+	protected Shell getShell() {
+		return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+	}
+
+	protected IWorkbench getWorkbench() {
+		return PlatformUI.getWorkbench();
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AllTests.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AllTests.java
new file mode 100644
index 0000000..6c075a5
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/AllTests.java
@@ -0,0 +1,25 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({ TestIDEIntegration.class, TestSyntaxHighlighting.class, TestLSPIntegration.class,
+		TestNewCargoProjectWizard.class, TestRunConfiguration.class, TestExportCargoProjectWizard.class,
+		TestBuilder.class, TestPerspective.class, TestLSPExtensions.class })
+public class AllTests {
+
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestBuilder.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestBuilder.java
new file mode 100644
index 0000000..83499a1
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestBuilder.java
@@ -0,0 +1,82 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.corrosion.builder.AddCargoBuilder;
+import org.eclipse.corrosion.builder.RemoveCargoBuilder;
+import org.eclipse.corrosion.builder.TestCargoBuilderEnabled;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Test;
+
+public class TestBuilder extends AbstractCorrosionTest {
+
+	@Test
+	public void testBuild() throws Exception {
+		IProject project = getProject("basic");
+		PropertyTester test = new TestCargoBuilderEnabled();
+		addBuilder(project);
+		assertTrue(test.test(project, "isCargoBuilderEnabled", null, null));
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				try {
+					project.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
+				} catch (CoreException e) {
+				}
+				return project.getFolder("target").getFolder("debug").getFile("basic").exists();
+			}
+		}.waitForCondition(getShell().getDisplay(), 10000);
+		assertTrue(project.getFolder("target").getFolder("debug").getFile("basic").exists());
+		removeBuilder(project);
+		assertFalse(test.test(project, "isCargoBuilderEnabled", null, null));
+	}
+
+	private static final ICommandService COMMAND_SERVICE = PlatformUI.getWorkbench().getService(ICommandService.class);
+	private static final Command ADD_COMMAND = COMMAND_SERVICE.getCommand("org.eclipse.corrosion.builder.AddCargoBuilder");
+	private static final Command REMOVE_COMMAND = COMMAND_SERVICE
+			.getCommand("org.eclipse.corrosion.builder.RemoveCargoBuilder");
+
+	private void addBuilder(IProject project) throws Exception {
+		IEvaluationContext evaluationContext = new EvaluationContext(null, project);
+		evaluationContext.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, new StructuredSelection(project));
+		ExecutionEvent event = new ExecutionEvent(ADD_COMMAND, new HashMap<>(0), null, evaluationContext);
+		AddCargoBuilder addBuilder = new AddCargoBuilder();
+		addBuilder.execute(event);
+	}
+
+	private void removeBuilder(IProject project) throws Exception {
+		IEvaluationContext evaluationContext = new EvaluationContext(null, project);
+		evaluationContext.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, new StructuredSelection(project));
+		ExecutionEvent event = new ExecutionEvent(REMOVE_COMMAND, new HashMap<>(0), null, evaluationContext);
+		RemoveCargoBuilder removeBuilder = new RemoveCargoBuilder();
+		removeBuilder.execute(event);
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestExportCargoProjectWizard.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestExportCargoProjectWizard.java
new file mode 100644
index 0000000..13424bf
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestExportCargoProjectWizard.java
@@ -0,0 +1,136 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.corrosion.wizards.export.CargoExportWizard;
+import org.eclipse.corrosion.wizards.export.CargoExportWizardPage;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Test;
+
+public class TestExportCargoProjectWizard extends AbstractCorrosionTest {
+
+	private WizardDialog dialog;
+	private CargoExportWizard wizard;
+	private Text projectText;
+	private Label locationLabel;
+
+	@Override
+	public void setUp() throws Exception {
+		super.setUp();
+	}
+
+	private void createWizard(String selectedProjectName) throws Exception {
+		wizard = new CargoExportWizard();
+		if (!selectedProjectName.isEmpty()) {
+			IProject project = getProject(selectedProjectName);
+			wizard.init(getWorkbench(), new StructuredSelection(project));
+		} else {
+			wizard.init(getWorkbench(), new StructuredSelection());
+		}
+		dialog = new WizardDialog(getShell(), wizard);
+		dialog.create();
+		dialog.setBlockOnOpen(false);
+		dialog.open();
+
+		Composite composite = (Composite) wizard.getPages()[0].getControl();
+		projectText = (Text) composite.getChildren()[1];
+		locationLabel = (Label) composite.getChildren()[4];
+	}
+
+	@Test
+	public void testExportPageWithSelection() throws Exception {
+		createWizard("basic");
+		confirmPageState(getProject("basic").getName(), true);
+
+		projectText.setText("");
+		confirmPageState(null, false);
+	}
+
+	@Test
+	public void testExportPageWithChangingProject() throws Exception {
+		createWizard("basic");
+		confirmPageState(getProject("basic").getName(), true);
+
+		IProject project = getProject("basic_errors");
+		projectText.setText(project.getName());
+		confirmPageState(project.getName(), true);
+	}
+
+	@Test
+	public void testExportPageWithNonCargoProject() throws Exception {
+		createWizard("basic");
+		confirmPageState(getProject("basic").getName(), true);
+
+		IProject project = getProject("not_cargo");
+		projectText.setText(project.getName());
+		confirmPageState(null, false);
+	}
+
+	private void confirmPageState(String expectedProjectName, Boolean expectedFinishState) {
+		CargoExportWizardPage page = (CargoExportWizardPage) wizard.getPages()[0];
+		if (!expectedFinishState) {
+			assertFalse(wizard.canFinish());
+			assertEquals(locationLabel.getText(), "");
+		} else {
+			assertEquals(expectedProjectName, page.getProject().getName());
+			assertEquals(locationLabel.getText(),
+					"Crate will be created in: " + expectedProjectName + "/target/package/");
+		}
+	}
+
+	@Test
+	public void testExportProject() throws Exception {
+		IProject basic = getProject("basic");
+		createWizard("basic");
+		Composite composite = (Composite) wizard.getPages()[0].getControl();
+		Button allowDirty = (Button) composite.getChildren()[10];
+		allowDirty.setSelection(true); // required of another test updates the project
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return allowDirty.getSelection();
+			}
+		}.waitForCondition(getShell().getDisplay(), 3000);
+
+		assertTrue(wizard.canFinish());
+		assertTrue(wizard.performFinish());
+		new DisplayHelper() {
+
+			@Override
+			protected boolean condition() {
+				return basic.getFolder("target").getFolder("package").exists();
+			}
+		}.waitForCondition(getShell().getDisplay(), 15000);
+		assertTrue(basic.getFolder("target").getFolder("package").members().length > 0);
+	}
+
+	@Override
+	public void tearDown() throws CoreException {
+		if (dialog != null) {
+			dialog.close();
+		}
+		super.tearDown();
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestIDEIntegration.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestIDEIntegration.java
new file mode 100644
index 0000000..39dc371
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestIDEIntegration.java
@@ -0,0 +1,45 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Mickael Istria (Red Hat Inc.) - Source Reference
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestIDEIntegration extends AbstractCorrosionTest {
+
+	@Test
+	public void testRustEditorAssociation() throws IOException, CoreException {
+		IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		IEditorPart editor = null;
+		editor = IDE.openEditor(activePage, getProject("basic").getFolder("src").getFile("main.rs"));
+		Assert.assertTrue(editor instanceof ExtensionBasedTextEditor);
+	}
+
+	@Test
+	public void testManifestEditorAssociation() throws IOException, CoreException {
+		IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		IEditorPart editor = null;
+		editor = IDE.openEditor(activePage, getProject("basic").getFile("Cargo.toml"));
+		Assert.assertTrue(editor instanceof ExtensionBasedTextEditor);
+	}
+
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPExtensions.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPExtensions.java
new file mode 100644
index 0000000..31caed8
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPExtensions.java
@@ -0,0 +1,55 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.corrosion.RLSClientImplementation;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Test;
+
+public class TestLSPExtensions {
+
+	@Test
+	public void testInitializationMessages() {
+		RLSClientImplementation clientImplementation = new RLSClientImplementation();
+		IJobManager jobManager = Job.getJobManager();
+		clientImplementation.beginBuild();
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return getRustDiagnosticsJob(jobManager) != null;
+			}
+		}.waitForCondition(Display.getCurrent(), 5000);
+
+		Job rustJob = getRustDiagnosticsJob(jobManager);
+		assertNotNull(rustJob);
+		clientImplementation.diagnosticsBegin();
+		clientImplementation.diagnosticsEnd();
+		assertEquals(rustJob.getResult().getCode(), IStatus.OK);
+	}
+
+	private Job getRustDiagnosticsJob(IJobManager jobManager) {
+		for (Job job : jobManager.find(null)) {
+			if ("Compiling Rust project diagnostics".equals(job.getName())) {
+				return job;
+			}
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPIntegration.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPIntegration.java
new file mode 100644
index 0000000..0a14724
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestLSPIntegration.java
@@ -0,0 +1,82 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Mickael Istria (Red Hat Inc.) - Source Reference
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.lsp4e.LanguageServiceAccessor;
+import org.eclipse.lsp4j.CompletionItem;
+import org.eclipse.lsp4j.CompletionList;
+import org.eclipse.lsp4j.Position;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.TextDocumentPositionParams;
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
+import org.eclipse.lsp4j.services.LanguageServer;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestLSPIntegration extends AbstractCorrosionTest {
+
+	@Test
+	public void testLSFound() throws Exception {
+		IProject project = getProject("basic");
+		IFile rustFile = project.getFolder("src").getFile("main.rs");
+		CompletableFuture<LanguageServer> languageServer = LanguageServiceAccessor
+				.getInitializedLanguageServers(rustFile, capabilities -> capabilities.getHoverProvider() != null)
+				.iterator().next();
+		String uri = rustFile.getLocationURI().toString();
+		Either<List<CompletionItem>, CompletionList> completionItems = languageServer.get(1, TimeUnit.MINUTES)
+				.getTextDocumentService()
+				.completion(new TextDocumentPositionParams(new TextDocumentIdentifier(uri), new Position(1, 4)))
+				.get(1, TimeUnit.MINUTES);
+		Assert.assertNotNull(completionItems);
+	}
+
+	@Test
+	public void testLSWorks() throws Exception {
+		IProject project = getProject("basic_errors");
+		IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		IEditorPart editor = null;
+		IFile file = project.getFolder("src").getFile("main.rs");
+		editor = IDE.openEditor(activePage, file);
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				try {
+					return file.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO)[0]
+							.getAttribute(IMarker.LINE_NUMBER, -1) == 3;
+				} catch (Exception e) {
+					return false;
+				}
+			}
+		}.waitForCondition(editor.getEditorSite().getShell().getDisplay(), 30000);
+		IMarker marker = file.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO)[0];
+		assertTrue(marker.getType().contains("lsp4e"));
+		assertEquals(3, marker.getAttribute(IMarker.LINE_NUMBER, -1));
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestNewCargoProjectWizard.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestNewCargoProjectWizard.java
new file mode 100644
index 0000000..1f80f3d
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestNewCargoProjectWizard.java
@@ -0,0 +1,95 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.corrosion.wizards.newCargo.NewCargoProjectWizard;
+import org.eclipse.corrosion.wizards.newCargo.NewCargoProjectWizardPage;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Test;
+
+public class TestNewCargoProjectWizard extends AbstractCorrosionTest {
+
+	@Test
+	public void testNewProjectPage() throws Exception {
+		NewCargoProjectWizard wizard = new NewCargoProjectWizard();
+		WizardDialog dialog = new WizardDialog(getShell(), wizard);
+		wizard.init(getWorkbench(), new StructuredSelection());
+		dialog.create();
+		confirmPageState(wizard, "new_rust_project", "none", true);
+
+		Composite composite = (Composite) wizard.getPages()[0].getControl();
+		Button binaryCheckBox = (Button) composite.getChildren()[12];
+		binaryCheckBox.setSelection(false);
+		confirmPageState(wizard, "new_rust_project", "none", false);
+
+		Button vcsCheckBox = (Button) composite.getChildren()[14];
+		vcsCheckBox.setSelection(true);
+		confirmPageState(wizard, "new_rust_project", "git", false);
+
+		dialog.close();
+	}
+
+	private void confirmPageState(IWizard wizard, String expectedProjectName, String expectedVCS,
+			Boolean expectedBinaryState) {
+		NewCargoProjectWizardPage page = (NewCargoProjectWizardPage) wizard.getPages()[0];
+		assertEquals(expectedProjectName, page.getProjectName());
+		assertEquals(expectedVCS, page.getVCS());
+		assertEquals(expectedBinaryState, page.isBinaryTemplate());
+	}
+
+	@Test
+	public void testCreateNewProject() throws Exception {
+		NewCargoProjectWizard wizard = new NewCargoProjectWizard();
+		WizardDialog dialog = new WizardDialog(getShell(), wizard);
+		wizard.init(getWorkbench(), new StructuredSelection());
+		dialog.create();
+
+		assertTrue(wizard.canFinish());
+		assertTrue(wizard.performFinish());
+		dialog.close();
+		new DisplayHelper() {
+
+			@Override
+			protected boolean condition() {
+				return ResourcesPlugin.getWorkspace().getRoot().getProjects().length > 0;
+			}
+		}.waitForCondition(getShell().getDisplay(), 15000);
+		IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+		assertEquals(1, projects.length);
+		assertTrue(projects[0].getFile("Cargo.toml").exists());
+	}
+
+	@Override
+	public void tearDown() throws CoreException {
+		for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+			try {
+				project.delete(true, new NullProgressMonitor());
+			} catch (CoreException e) {
+				e.printStackTrace();
+			}
+		}
+		super.tearDown();
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestPerspective.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestPerspective.java
new file mode 100644
index 0000000..aaf65fd
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestPerspective.java
@@ -0,0 +1,88 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.corrosion.RustPerspective;
+import org.eclipse.corrosion.wizards.newCargo.NewCargoProjectWizard;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.wizards.newresource.BasicNewFileResourceWizard;
+import org.eclipse.ui.wizards.newresource.BasicNewFolderResourceWizard;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestPerspective {
+
+	@Before
+	public void setup() {
+		IPerspectiveDescriptor descriptor = PlatformUI.getWorkbench().getPerspectiveRegistry()
+				.findPerspectiveWithId(RustPerspective.ID);
+
+		PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().setPerspective(descriptor);
+	}
+
+	@Test
+	public void testNewWizardShortCuts() {
+		String[] newWizardShortcutIds = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+				.getNewWizardShortcuts();
+		String[] expectedIds = new String[] { NewCargoProjectWizard.ID, BasicNewFolderResourceWizard.WIZARD_ID,
+				BasicNewFileResourceWizard.WIZARD_ID };
+		assertArrayEquals(expectedIds, newWizardShortcutIds);
+	}
+
+	@Test
+	public void testPerspectiveShortcut() {
+		String[] perspectiveShortcutIds = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+				.getPerspectiveShortcuts();
+		String[] expectedIds = new String[] { "org.eclipse.debug.ui.DebugPerspective",
+				"org.eclipse.ui.resourcePerspective", "org.eclipse.team.ui.TeamSynchronizingPerspective" };
+		assertArrayEquals(expectedIds, perspectiveShortcutIds);
+	}
+
+	@Test
+	public void testShowViewShortcuts() {
+		String[] showViewShortcutIds = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+				.getShowViewShortcuts();
+		String[] expectedIds = new String[] { IPageLayout.ID_OUTLINE, IPageLayout.ID_PROBLEM_VIEW,
+				IPageLayout.ID_TASK_LIST, NewSearchUI.SEARCH_VIEW_ID, IPageLayout.ID_PROGRESS_VIEW,
+				IConsoleConstants.ID_CONSOLE_VIEW };
+		assertArrayEquals(expectedIds, showViewShortcutIds);
+	}
+
+	@Test
+	public void testAddedViews() {
+		List<String> expectedViewIds = new ArrayList<>();
+		expectedViewIds.add(IPageLayout.ID_PROJECT_EXPLORER);
+		expectedViewIds.add(IPageLayout.ID_PROBLEM_VIEW);
+		expectedViewIds.add(IPageLayout.ID_TASK_LIST);
+		expectedViewIds.add(IPageLayout.ID_PROGRESS_VIEW);
+		expectedViewIds.add(IConsoleConstants.ID_CONSOLE_VIEW);
+		IViewReference[] viewReferences = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+				.getViewReferences();
+		for (IViewReference viewReference : viewReferences) {
+			expectedViewIds.remove(viewReference.getId());
+		}
+		assertEquals("Not all views present. Missing views: " + String.join(", ", expectedViewIds), 0,
+				expectedViewIds.size());
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestRunConfiguration.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestRunConfiguration.java
new file mode 100644
index 0000000..3a5069f
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestRunConfiguration.java
@@ -0,0 +1,134 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Test;
+
+public class TestRunConfiguration extends AbstractCorrosionTest {
+
+	@Test
+	public void testBasicRun() throws Exception {
+		IProject project = getProject("basic");
+		ILaunchConfiguration launchConfiguration = createLaunchConfiguration(project, "launch");
+		confirmLaunchConfiguration(launchConfiguration, 0);
+	}
+
+	// TODO: Unable to test multiple failing runs do to bug
+	// computer crashes if multiple popups are made one after another
+	// a popup is made if the configuration is unable to run
+	// @Test
+	// public void testFailOnFakeProjectName() throws Exception {
+	// IProject project = getProject("basic");
+	// ILaunchConfigurationWorkingCopy launchConfiguration =
+	// createLaunchConfiguration(project, "launch");
+	// launchConfiguration.setAttribute("PROJECT", "fakeProjectName");
+	// confirmLaunchConfiguration(launchConfiguration, 1);
+	// }
+	//
+	// @Test
+	// public void testFailOnDeletedProject() throws Exception {
+	// IProject project = getProject("basic");
+	// ILaunchConfigurationWorkingCopy launchConfiguration =
+	// createLaunchConfiguration(project, "launch");
+	// project.delete(true, new NullProgressMonitor());
+	// confirmLaunchConfiguration(launchConfiguration, 1);
+	// }
+	//
+	// @Test
+	// public void testFailOnNonCargoProject() throws Exception {
+	// IProject project = getProject("not_cargo");
+	// ILaunchConfigurationWorkingCopy launchConfiguration =
+	// createLaunchConfiguration(project, "launch");
+	// confirmLaunchConfiguration(launchConfiguration, 1);
+	// }
+
+	@Test
+	public void testTranslateVariablesInBuildCommand() throws Exception {
+		IProject project = getProject("basic");
+		ILaunchConfigurationWorkingCopy launchConfiguration = createLaunchConfiguration(project, "launch");
+		launchConfiguration.setAttribute("BUILD_COMMAND", "-- ${workspace_loc}");
+		ILaunch launch = launchConfiguration.launch(ILaunchManager.RUN_MODE, new NullProgressMonitor());
+
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return launch.getProcesses().length != 0;
+			}
+		}.waitForCondition(Display.getDefault(), 15000);
+
+		for (IProcess process : launch.getProcesses()) {
+			if (process.getLabel().equals("cargo run")) {
+				while (!process.isTerminated()) {
+					Thread.sleep(50);
+				}
+				String command = process.getAttribute(IProcess.ATTR_CMDLINE);
+				// confirm ${workspace_loc} has been replaced with its actual value
+				assertTrue(command
+						.matches(".*" + ResourcesPlugin.getWorkspace().getRoot().getLocation().toString() + ".*"));
+				assertEquals(0, process.getExitValue());
+				return;
+			}
+		}
+		fail();
+	}
+
+	private ILaunchConfigurationWorkingCopy createLaunchConfiguration(IProject project, String name)
+			throws CoreException {
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		ILaunchConfigurationType configType = launchManager
+				.getLaunchConfigurationType("org.eclipse.corrosion.run.CargoRunDelegate");
+		ILaunchConfigurationWorkingCopy wc = configType.newInstance(project, name);
+		wc.setAttribute("PROJECT", project.getName());
+		return wc;
+	}
+
+	private void confirmLaunchConfiguration(ILaunchConfiguration configuration, int expectedExitValue)
+			throws Exception {
+		ILaunch launch = configuration.launch(ILaunchManager.RUN_MODE, new NullProgressMonitor());
+
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return launch.getProcesses().length != 0;
+			}
+		}.waitForCondition(Display.getDefault(), 15000);
+
+		for (IProcess process : launch.getProcesses()) {
+			if (process.getLabel().equals("cargo run")) {
+				while (!process.isTerminated()) {
+					Thread.sleep(50);
+				}
+				assertEquals(expectedExitValue, process.getExitValue());
+				return;
+			}
+		}
+		assertEquals(expectedExitValue, 1);
+	}
+}
diff --git a/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestSyntaxHighlighting.java b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestSyntaxHighlighting.java
new file mode 100644
index 0000000..8e06226
--- /dev/null
+++ b/org.eclipse.corrosion.tests/src/org/eclipse/corrosion/tests/TestSyntaxHighlighting.java
@@ -0,0 +1,63 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Mickael Istria (Red Hat Inc.) - Source Reference
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.tests;
+
+import java.io.IOException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.tests.harness.util.DisplayHelper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestSyntaxHighlighting extends AbstractCorrosionTest {
+
+	@Test
+	public void testRustSyntaxHighlighting() throws CoreException, IOException {
+		IFile rustFile = getProject("basic").getFolder("src").getFile("main.rs");
+		TextEditor editor = (TextEditor) IDE.openEditor(
+				PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), rustFile,
+				"org.eclipse.ui.genericeditor.GenericEditor");
+		StyledText editorTextWidget = (StyledText) editor.getAdapter(Control.class);
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return editorTextWidget.getStyleRanges().length > 1;
+			}
+		}.waitForCondition(editorTextWidget.getDisplay(), 4000);
+		Assert.assertTrue("There should be multiple styles in editor", editorTextWidget.getStyleRanges().length > 1);
+	}
+
+	@Test
+	public void testManifestSyntaxHighlighting() throws CoreException, IOException {
+		IFile rustFile = getProject("basic").getFile("Cargo.toml");
+		TextEditor editor = (TextEditor) IDE.openEditor(
+				PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), rustFile,
+				"org.eclipse.ui.genericeditor.GenericEditor");
+		StyledText editorTextWidget = (StyledText) editor.getAdapter(Control.class);
+		new DisplayHelper() {
+			@Override
+			protected boolean condition() {
+				return editorTextWidget.getStyleRanges().length > 1;
+			}
+		}.waitForCondition(editorTextWidget.getDisplay(), 4000);
+		Assert.assertTrue("There should be multiple styles in editor", editorTextWidget.getStyleRanges().length > 1);
+	}
+
+}
diff --git a/org.eclipse.corrosion/.classpath b/org.eclipse.corrosion/.classpath
new file mode 100644
index 0000000..43b9862
--- /dev/null
+++ b/org.eclipse.corrosion/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/org.eclipse.corrosion/.gitignore b/org.eclipse.corrosion/.gitignore
new file mode 100644
index 0000000..005c862
--- /dev/null
+++ b/org.eclipse.corrosion/.gitignore
@@ -0,0 +1,4 @@
+grammar/
+scripts/
+/bin/
+/target/
diff --git a/org.eclipse.corrosion/.project b/org.eclipse.corrosion/.project
new file mode 100644
index 0000000..46146e0
--- /dev/null
+++ b/org.eclipse.corrosion/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.corrosion</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.corrosion/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.corrosion/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0c68a61
--- /dev/null
+++ b/org.eclipse.corrosion/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.eclipse.corrosion/.settings/org.eclipse.m2e.core.prefs b/org.eclipse.corrosion/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/org.eclipse.corrosion/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/org.eclipse.corrosion/META-INF/MANIFEST.MF b/org.eclipse.corrosion/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6507e14
--- /dev/null
+++ b/org.eclipse.corrosion/META-INF/MANIFEST.MF
@@ -0,0 +1,43 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Rust edition in Eclipse IDE
+Bundle-SymbolicName: org.eclipse.corrosion;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Automatic-Module-Name: org.eclipse.corrosion
+Bundle-Activator: org.eclipse.corrosion.CorrosionPlugin
+Bundle-Vendor: Red Hat Inc.
+Require-Bundle: org.eclipse.core.contenttype,
+ org.eclipse.ui.genericeditor;bundle-version="1.0.1",
+ org.eclipse.ui,
+ org.eclipse.lsp4e;bundle-version="0.5.0",
+ org.eclipse.tm4e.core,
+ org.eclipse.tm4e.ui,
+ org.eclipse.core.runtime;bundle-version="3.13.0",
+ org.eclipse.core.resources,
+ org.eclipse.swt,
+ org.eclipse.ui.ide,
+ org.eclipse.debug.core,
+ org.eclipse.debug.ui,
+ org.eclipse.core.variables,
+ org.eclipse.core.expressions;bundle-version="3.6.0",
+ org.eclipse.search,
+ org.eclipse.ui.console,
+ org.eclipse.lsp4j.jsonrpc,
+ org.eclipse.lsp4j,
+ com.google.gson;bundle-version="2.7.0",
+ org.eclipse.jface.text,
+ org.eclipse.ui.editors,
+ org.eclipse.cdt.debug.core,
+ org.eclipse.cdt.launch,
+ org.eclipse.cdt.core,
+ org.eclipse.cdt.dsf.gdb,
+ org.eclipse.cdt.dsf,
+ org.eclipse.cdt.debug.ui,
+ org.eclipse.cdt.dsf.gdb.ui
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.corrosion;x-friends:="org.eclipse.corrosion.tests",
+ org.eclipse.corrosion.builder;x-friends:="org.eclipse.corrosion.tests",
+ org.eclipse.corrosion.extensions;x-friends:="org.eclipse.corrosion.tests",
+ org.eclipse.corrosion.wizards.export;x-friends:="org.eclipse.corrosion.tests",
+ org.eclipse.corrosion.wizards.newCargo;x-friends:="org.eclipse.corrosion.tests"
diff --git a/org.eclipse.corrosion/build.properties b/org.eclipse.corrosion/build.properties
new file mode 100644
index 0000000..731e595
--- /dev/null
+++ b/org.eclipse.corrosion/build.properties
@@ -0,0 +1,10 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml,\
+               grammar/,\
+               icons/,\
+               images/,\
+               scripts/,\
+               snippets/
diff --git a/org.eclipse.corrosion/icons/cargo.png b/org.eclipse.corrosion/icons/cargo.png
new file mode 100644
index 0000000..46381f9
--- /dev/null
+++ b/org.eclipse.corrosion/icons/cargo.png
Binary files differ
diff --git a/org.eclipse.corrosion/icons/cargo@2x.png b/org.eclipse.corrosion/icons/cargo@2x.png
new file mode 100644
index 0000000..d4f1aeb
--- /dev/null
+++ b/org.eclipse.corrosion/icons/cargo@2x.png
Binary files differ
diff --git a/org.eclipse.corrosion/icons/link_obj.png b/org.eclipse.corrosion/icons/link_obj.png
new file mode 100644
index 0000000..7124232
--- /dev/null
+++ b/org.eclipse.corrosion/icons/link_obj.png
Binary files differ
diff --git a/org.eclipse.corrosion/icons/rust.png b/org.eclipse.corrosion/icons/rust.png
new file mode 100644
index 0000000..123d027
--- /dev/null
+++ b/org.eclipse.corrosion/icons/rust.png
Binary files differ
diff --git a/org.eclipse.corrosion/icons/rust@x2.png b/org.eclipse.corrosion/icons/rust@x2.png
new file mode 100644
index 0000000..23f14a4
--- /dev/null
+++ b/org.eclipse.corrosion/icons/rust@x2.png
Binary files differ
diff --git a/org.eclipse.corrosion/images/cargo.png b/org.eclipse.corrosion/images/cargo.png
new file mode 100644
index 0000000..586f2e7
--- /dev/null
+++ b/org.eclipse.corrosion/images/cargo.png
Binary files differ
diff --git a/org.eclipse.corrosion/plugin.xml b/org.eclipse.corrosion/plugin.xml
new file mode 100644
index 0000000..37989a6
--- /dev/null
+++ b/org.eclipse.corrosion/plugin.xml
@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.core.contenttype.contentTypes">
+      <content-type
+            base-type="org.eclipse.core.runtime.text"
+            file-extensions="rs"
+            id="org.eclipse.corrosion.rust"
+            name="Rust project file"
+            priority="normal">
+      </content-type>
+      <content-type
+            base-type="org.eclipse.core.runtime.text"
+            file-names="Cargo.toml"
+            id="org.eclipse.corrosion.manifest"
+            name="Cargo manifest file"
+            priority="normal">
+      </content-type>
+   </extension>
+   <extension
+         point="org.eclipse.ui.editors">
+     <editorContentTypeBinding
+        contentTypeId="org.eclipse.corrosion.rust"
+        editorId="org.eclipse.ui.genericeditor.GenericEditor">
+   		</editorContentTypeBinding>
+     <editorContentTypeBinding
+        contentTypeId="org.eclipse.corrosion.manifest"
+        editorId="org.eclipse.ui.genericeditor.GenericEditor">
+   		</editorContentTypeBinding>
+   </extension>
+   <extension
+         point="org.eclipse.lsp4e.languageServer">
+     <server
+        class="org.eclipse.corrosion.RLSStreamConnectionProvider"
+        id="org.eclipse.corrosion.rls"
+        label="org.eclipse.corrosion.RLS"
+        clientImpl="org.eclipse.corrosion.RLSClientImplementation"
+        serverInterface="org.eclipse.corrosion.RLSServerInterface">
+      </server>
+      <contentTypeMapping
+            contentType="org.eclipse.corrosion.rust"
+            id="org.eclipse.corrosion.rls">
+      </contentTypeMapping>
+   </extension>
+   <extension
+         point="org.eclipse.tm4e.registry.grammars">
+      <grammar
+            path="grammar/Rust.tmLanguage"
+            scopeName="source.rust">
+      </grammar>
+      <scopeNameContentTypeBinding
+            contentTypeId="org.eclipse.corrosion.rust"
+            scopeName="source.rust">
+      </scopeNameContentTypeBinding>
+      <grammar
+            path="grammar/TOML.tmLanguage"
+            scopeName="source.toml">
+      </grammar>
+      <scopeNameContentTypeBinding
+            contentTypeId="org.eclipse.corrosion.manifest"
+            scopeName="source.toml">
+      </scopeNameContentTypeBinding>
+   </extension>
+   <extension
+         point="org.eclipse.ui.genericeditor.presentationReconcilers">
+      <presentationReconciler
+            class="org.eclipse.tm4e.ui.text.TMPresentationReconciler"
+            contentType="org.eclipse.corrosion.rust">
+      </presentationReconciler>
+   </extension>
+   <extension
+         point="org.eclipse.ui.genericeditor.contentAssistProcessors">
+      <contentAssistProcessor
+            class="org.eclipse.corrosion.snippet.SnippetContentAssistProcessor"
+            contentType="org.eclipse.corrosion.rust">
+      </contentAssistProcessor>
+   </extension>
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+         <initializer
+            class="org.eclipse.corrosion.CorrosionPreferenceInitializer">
+		</initializer>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            class="org.eclipse.corrosion.CorrosionPreferencePage"
+            id="org.eclipse.corrosion.preferencePage"
+            name="Rust">
+      </page>
+   </extension>
+   <extension
+       point="org.eclipse.core.expressions.definitions">
+    <definition id="org.eclipse.corrosion.isCargoProject">
+       <with variable="selection">
+          <count value="1"/>
+          <iterate>
+             <adapt type="org.eclipse.core.resources.IResource">
+                <test property="org.eclipse.corrosion.isCargoProject"
+                      forcePluginActivation="true"/>
+             </adapt>
+          </iterate>
+       </with>
+     </definition>
+   </extension>
+<!-- WIZARDS -->
+   <extension
+         point="org.eclipse.ui.newWizards">
+      <category
+            id="org.eclipse.corrosion.rust"
+            name="Rust">
+      </category>
+      <wizard
+            category="org.eclipse.corrosion.rust"
+            class="org.eclipse.corrosion.wizards.newCargo.NewCargoProjectWizard"
+            icon="icons/cargo.png"
+            id="org.eclipse.corrosion.wizards.newCargo"
+            name="Cargo project"
+            project="true">
+      </wizard>
+   </extension>
+   <extension
+         point="org.eclipse.ui.exportWizards">
+      <wizard
+            id="org.eclipse.corrosion.wizards.export"
+            name="Rust Crate Packager"
+            class="org.eclipse.corrosion.wizards.export.CargoExportWizard"
+            icon="icons/cargo.png">
+         <description>
+            A wizard to assist with packaging Cargo based Rust projects into crates
+         </description>
+         <selection class="org.eclipse.core.resources.IResource"/>
+      </wizard>
+   </extension>
+
+<!-- LAUNCH CONFIGURATIONS -->
+   <extension
+         point="org.eclipse.debug.core.launchConfigurationTypes">
+      <launchConfigurationType
+            delegate="org.eclipse.corrosion.run.CargoRunDelegate"
+            id="org.eclipse.corrosion.run.CargoRunDelegate"
+            modes="run"
+            name="Cargo Based Rust Project">
+      </launchConfigurationType>
+      <launchConfigurationType
+            delegate="org.eclipse.corrosion.debug.RustDebugDelegate"
+            id="org.eclipse.corrosion.debug.RustDebugDelegate"
+            modes="debug"
+            name="Rust"
+            public="true"
+            sourceLocatorId="com.eclipse.corrosion.debug.SourceLocator">
+      </launchConfigurationType>
+   </extension>
+   <extension
+         point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+      <launchConfigurationTabGroup
+            class="org.eclipse.corrosion.run.CargoRunTabGroup"
+            id="org.eclipse.corrosion.run.CargoRunTabGroup"
+            type="org.eclipse.corrosion.run.CargoRunDelegate">
+      </launchConfigurationTabGroup>
+      <launchConfigurationTabGroup
+            class="org.eclipse.corrosion.debug.RustDebugTabGroup"
+            id="org.eclipse.corrosion.debug.RustDebugTabGroup"
+            type="org.eclipse.corrosion.debug.RustDebugDelegate">
+      </launchConfigurationTabGroup>
+   </extension>
+   <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+      <launchConfigurationTypeImage
+            id="org.eclipse.corrosion.run.CargoRunTypeImage"
+            configTypeID="org.eclipse.corrosion.run.CargoRunDelegate"
+            icon="icons/cargo.png">
+      </launchConfigurationTypeImage>
+      <launchConfigurationTypeImage
+            id="org.eclipse.corrosion.debug.RustDebugTypeImage"
+            configTypeID="org.eclipse.corrosion.debug.RustDebugDelegate"
+            icon="icons/rust.png">
+      </launchConfigurationTypeImage>
+   </extension>
+   <extension point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            id="org.eclipse.corrosion.cargoProjectTester"
+            type="org.eclipse.core.resources.IResource"
+            namespace="org.eclipse.corrosion"
+            properties="isCargoProject"
+            class="org.eclipse.corrosion.CargoProjectTester">
+      </propertyTester>
+   </extension>
+   <extension point="org.eclipse.debug.ui.launchShortcuts">
+      <shortcut
+            id="org.eclipse.corrosion.run.Shortcut"
+            class="org.eclipse.corrosion.run.CargoRunDelegate"
+            label="Cargo Based Rust Project"
+            icon="icons/cargo.png"
+            modes="run">
+         <contextualLaunch>
+            <enablement>
+               <reference definitionId="org.eclipse.corrosion.isCargoProject"/>
+            </enablement>
+         </contextualLaunch>
+      </shortcut>
+      <shortcut
+            class="org.eclipse.corrosion.debug.RustDebugDelegate"
+            icon="icons/rust.png"
+            id="org.eclipse.corrosion.debug.Shortcut"
+            label="Rust Project"
+            modes="debug">
+         <contextualLaunch>
+            <enablement>
+               <reference definitionId="org.eclipse.corrosion.isCargoProject"/>
+            </enablement>
+         </contextualLaunch>
+      </shortcut>
+   </extension>
+   <extension
+         point="org.eclipse.debug.core.sourceLocators">
+      <sourceLocator
+            class="org.eclipse.corrosion.debug.SourceLookupDirector"
+            id="com.eclipse.corrosion.debug.SourceLocator"
+            name="Source Locator">
+      </sourceLocator>
+   </extension>
+
+<!-- INCREMENTAL BUILD PROCESS -->
+   <extension
+         id="org.eclipse.corrosion.builder.IncrementalCargoBuilder"
+         name="Cargo Builder"
+         point="org.eclipse.core.resources.builders">
+      <builder>
+         <run class="org.eclipse.corrosion.builder.IncrementalCargoBuilder"/>
+      </builder>
+   </extension>
+   <extension
+         point="org.eclipse.ui.menus">
+      <menuContribution
+            allPopups="false"
+            locationURI="popup:org.eclipse.ui.projectConfigure?after=additions">
+         <command
+               commandId="org.eclipse.corrosion.builder.AddCargoBuilder"
+               style="push">
+            <visibleWhen checkEnabled="false">
+               <and>
+                  <count value="1"/>
+                  <reference definitionId="org.eclipse.corrosion.isCargoProject"/>
+                  <iterate>
+                     <not>
+                        <test
+                              forcePluginActivation="true"
+                              property="org.eclipse.corrosion.builder.isCargoBuilderEnabled">
+                        </test>
+                     </not>
+                  </iterate>
+               </and>
+            </visibleWhen>
+         </command>
+         <command
+               commandId="org.eclipse.corrosion.builder.RemoveCargoBuilder"
+               style="push">
+            <visibleWhen checkEnabled="true">
+               <and>
+                  <count value="1"/>
+                  <reference definitionId="org.eclipse.corrosion.isCargoProject"/>
+                  <iterate>
+                     <test
+                           forcePluginActivation="true"
+                           property="org.eclipse.corrosion.builder.isCargoBuilderEnabled">
+                     </test>
+                  </iterate>
+               </and>
+            </visibleWhen>
+         </command>
+      </menuContribution>
+      <menuContribution
+            allPopups="true"
+            locationURI="popup:#TextEditorContext?after=additions">
+        <command
+               commandId="org.eclipse.corrosion.commands.Implementations"
+               style="push">
+         </command>
+      </menuContribution>
+   </extension>
+   <extension
+          point="org.eclipse.ui.commands">
+      <command
+            defaultHandler="org.eclipse.corrosion.builder.AddCargoBuilder"
+            name="Add Cargo Builder"
+            id="org.eclipse.corrosion.builder.AddCargoBuilder">
+      </command>
+      <command
+            defaultHandler="org.eclipse.corrosion.builder.RemoveCargoBuilder"
+            id="org.eclipse.corrosion.builder.RemoveCargoBuilder"
+            name="Remove Cargo Builder">
+      </command>
+      <command
+            categoryId="org.eclipse.lsp4e.category"
+            id="org.eclipse.corrosion.commands.Implementations"
+            name="Implementations">
+      </command>
+   </extension>
+   <extension
+         point="org.eclipse.ui.handlers">
+      <handler
+            class="org.eclipse.corrosion.extensions.Implementations"
+            commandId="org.eclipse.corrosion.commands.Implementations">
+         <enabledWhen>
+            <and>
+               <with
+                     variable="selection">
+                  <instanceof
+                        value="org.eclipse.jface.text.ITextSelection">
+                  </instanceof>
+               </with>
+            </and>
+         </enabledWhen>
+      </handler>
+   </extension>
+      <extension
+         point="org.eclipse.core.expressions.propertyTesters">
+      <propertyTester
+            class="org.eclipse.corrosion.builder.TestCargoBuilderEnabled"
+            id="org.eclipse.corrosion.builder.IncrementalCargoBuilderTester"
+            namespace="org.eclipse.corrosion.builder"
+            properties="isCargoBuilderEnabled"
+            type="java.lang.Object">
+      </propertyTester>
+   </extension>
+
+<!-- PERSPECTIVE -->
+   <extension
+        point="org.eclipse.ui.perspectives">
+        <perspective
+            id="org.eclipse.corrosion.rustPerspective"
+            name="Rust"
+            class="org.eclipse.corrosion.RustPerspective"
+            icon="icons/rust.png">
+        </perspective> 
+    </extension>
+<!-- BREAKPOINTS -->
+	<extension point="org.eclipse.debug.ui.toggleBreakpointsTargetFactories">
+      <toggleTargetFactory
+            class="org.eclipse.corrosion.debug.ToggleBreakpointsTargetFactory"
+            id="com.eclipse.corrosion.debug.ToggleBreakpointsTargetFactory">
+      </toggleTargetFactory>
+   </extension>
+
+   <extension point="org.eclipse.ui.editorActions">
+      <editorContribution
+         targetID="org.eclipse.ui.genericeditor.GenericEditor"
+         id="com.github.rustdt.ide.debug.ui.EditorBreakpointRulerActions">
+
+         <action
+               actionID="RulerDoubleClick"
+               class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
+               id="Editor.rulerDoubleClickAction"
+               label="Toggle Breakpoint">
+         </action>
+      </editorContribution>
+   </extension>
+</plugin>
diff --git a/org.eclipse.corrosion/pom.xml b/org.eclipse.corrosion/pom.xml
new file mode 100644
index 0000000..292c120
--- /dev/null
+++ b/org.eclipse.corrosion/pom.xml
@@ -0,0 +1,68 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>org.eclipse.corrosion</artifactId>
+	<parent>
+		<groupId>org.eclipse.corrosion</groupId>
+		<artifactId>parent</artifactId>
+		<version>0.1.0-SNAPSHOT</version>
+	</parent>
+	<packaging>eclipse-plugin</packaging>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>com.googlecode.maven-download-plugin</groupId>
+				<artifactId>download-maven-plugin</artifactId>
+				<version>1.3.0</version>
+				<executions>
+					<execution>
+						<id>fetch-rust-grammar</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>wget</goal>
+						</goals>
+						<configuration>
+							<url>https://raw.githubusercontent.com/defuz/sublimate/5c782e6fcd7942e05716143296ae0e928182456e/packages/Rust/Rust.tmLanguage</url>
+							<outputDirectory>${project.basedir}/grammar</outputDirectory>
+							<skipCache>true</skipCache>
+							<overwrite>true</overwrite>
+						</configuration>
+					</execution>
+					<execution>
+						<id>fetch-toml-grammar</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>wget</goal>
+						</goals>
+						<configuration>
+							<url>https://raw.githubusercontent.com/textmate/toml.tmbundle/37c532ae892d2af2da76e05918af673efc1111a6/Syntaxes/TOML.tmLanguage</url>
+							<outputDirectory>${project.basedir}/grammar</outputDirectory>
+							<skipCache>true</skipCache>
+							<overwrite>true</overwrite>
+						</configuration>
+					</execution>
+					<execution>
+						<id>fetch-rustup-install-script</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>wget</goal>
+						</goals>
+						<configuration>
+							<url>https://raw.githubusercontent.com/rust-lang-nursery/rustup.rs/d93c1c83994ae6046a3d9fc0b8f88aed99bacab9/rustup-init.sh</url>
+							<outputDirectory>${project.basedir}/scripts</outputDirectory>
+							<skipCache>true</skipCache>
+							<overwrite>true</overwrite>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-packaging-plugin</artifactId>
+				<configuration>
+					<jgit.ignore>pom.xml,grammar,scripts</jgit.ignore>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/org.eclipse.corrosion/snippets/rust.json b/org.eclipse.corrosion/snippets/rust.json
new file mode 100644
index 0000000..4f385b1
--- /dev/null
+++ b/org.eclipse.corrosion/snippets/rust.json
@@ -0,0 +1,61 @@
+[
+    {
+    	"display": "for",
+        "completionItemKind": 15,
+        "replacementLines": [
+            "for $0 in $1 {",
+            "\t$2",
+            "}"
+        ]
+    },
+    {
+    	"display": "unimplemented",
+        "completionItemKind": 3,
+        "replacementLines": [
+            "unimplemented!()"
+        ]
+    },
+    {
+    	"display": "unreachable",
+        "completionItemKind": 3,
+        "replacementLines": [
+            "unreachable!()"
+        ]
+    },
+    {
+    	"display": "println",
+        "completionItemKind": 3,
+        "replacementLines": [
+            "println!(\"$1\", $0)"
+        ]
+    },
+    {
+    	"display":  "macro_rules",
+        "completionItemKind": 15,
+        "replacementLines": [
+            "macro_rules! $1 {",
+            "\t($2) => {",
+            "\t\t$0",
+            "\t};",
+            "}"
+        ]
+    },
+    {
+    	"display": "if let Option",
+        "completionItemKind": 15,
+        "replacementLines": [
+            "if let Some(${1:foo}) = ${1:foo} {",
+            "\t${0:${1:foo}.}",
+            "}"
+        ]
+    },
+    {
+    	"display": "spawn",
+        "completionItemKind": 15,
+        "replacementLines": [
+            "thread::spawn(move || {",
+            "\t$0",
+            "});"
+        ]
+    }
+]
\ No newline at end of file
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/CargoProjectTester.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/CargoProjectTester.java
new file mode 100644
index 0000000..3034819
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/CargoProjectTester.java
@@ -0,0 +1,46 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+
+public class CargoProjectTester extends PropertyTester {
+	private static final String PROPERTY_NAME = "isCargoProject";
+
+	@Override
+	public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+		if (property.equals(PROPERTY_NAME)) {
+			IResource resource = toResource(receiver);
+			if (resource == null) {
+				return false;
+			}
+			IProject project = resource.getProject();
+			return project.getFile("Cargo.toml").exists();
+		}
+		return false;
+	}
+
+	private IResource toResource(Object o) {
+		if (o instanceof IResource) {
+			return (IResource) o;
+		} else if (o instanceof IAdaptable) {
+			return ((IAdaptable) o).getAdapter(IResource.class);
+		} else {
+			return null;
+		}
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPlugin.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPlugin.java
new file mode 100644
index 0000000..22309b6
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPlugin.java
@@ -0,0 +1,58 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+public class CorrosionPlugin extends AbstractUIPlugin {
+
+	// The plug-in ID
+	public static final String PLUGIN_ID = "org.eclipse.corrosion"; //$NON-NLS-1$
+
+	// The shared instance
+	private static CorrosionPlugin plugin;
+
+	/**
+	 * The constructor
+	 */
+	public CorrosionPlugin() {
+	}
+
+	@Override
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+		plugin = this;
+	}
+
+	@Override
+	public void stop(BundleContext context) throws Exception {
+		plugin = null;
+		super.stop(context);
+	}
+
+	/**
+	 * Returns the shared instance
+	 *
+	 * @return the shared instance
+	 */
+	public static CorrosionPlugin getDefault() {
+		return plugin;
+	}
+
+	public static void logError(Throwable t) {
+		getDefault().getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, t.getMessage(), t));
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferenceInitializer.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferenceInitializer.java
new file mode 100644
index 0000000..6554e72
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferenceInitializer.java
@@ -0,0 +1,145 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+public class CorrosionPreferenceInitializer extends AbstractPreferenceInitializer {
+
+	private static final IPreferenceStore STORE = CorrosionPlugin.getDefault().getPreferenceStore();
+
+	public static String rustSourcePreference = "corrosion.rustSource";
+
+	public static String defaultPathsPreference = "corrosion.rustup_defaultPaths";
+	public static String rustupPathPreference = "corrosion.rustup_rustupPath";
+	public static String cargoPathPreference = "corrosion.rustup_cargoPath";
+	public static String toolchainIdPreference = "corrosion.rustup_toolchain_Id";
+	public static String toolchainTypePreference = "corrosion.rustup_toolchain_type";
+
+	public static String rlsPathPreference = "corrosion.rslPath";
+	public static String sysrootPathPreference = "corrosion.sysrootPath";
+
+	@Override
+	public void initializeDefaultPreferences() {
+		STORE.setDefault(rustSourcePreference, "rustup");
+
+		STORE.setDefault(defaultPathsPreference, true);
+		STORE.setDefault(rustupPathPreference, getRustupPathBestGuess());
+		STORE.setDefault(cargoPathPreference, getCargoPathBestGuess());
+		setToolchainBestGuesses();
+
+		STORE.setDefault(rlsPathPreference, getRLSPathBestGuess());
+		STORE.setDefault(sysrootPathPreference, getSysrootPathBestGuess());
+	}
+
+	private String getRustupPathBestGuess() {
+		String command = findCommandPath("rustup");
+		if (command.isEmpty()) {
+			File possibleCommandFile = new File(System.getProperty("user.home") + "/.cargo/bin/rustup");
+			if (possibleCommandFile.exists() && possibleCommandFile.isFile() && possibleCommandFile.canExecute()) {
+				return possibleCommandFile.getAbsolutePath();
+			}
+		}
+		return command;
+	}
+
+	private String getCargoPathBestGuess() {
+		String command = findCommandPath("cargo");
+		if (command.isEmpty()) {
+			File possibleCommandFile = new File(System.getProperty("user.home") + "/.cargo/bin/cargo");
+			if (possibleCommandFile.exists() && possibleCommandFile.isFile() && possibleCommandFile.canExecute()) {
+				return possibleCommandFile.getAbsolutePath();
+			}
+		}
+		return command;
+	}
+
+	private String findCommandPath(String command) {
+		try {
+			ProcessBuilder builder = new ProcessBuilder("which", command);
+			Process process = builder.start();
+
+			if (process.waitFor() == 0) {
+				try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+					return in.readLine();
+				}
+			}
+		} catch (IOException | InterruptedException e) {
+			// Errors caught with empty return
+		}
+		return "";
+	}
+
+	private void setToolchainBestGuesses() {
+		String toolchain = RustManager.getDefaultToolchain();
+		if (toolchain == null || toolchain.isEmpty()) {
+			STORE.setDefault(toolchainIdPreference, "");
+			STORE.setDefault(toolchainTypePreference, "Other");
+			return;
+		}
+		int splitIndex = toolchain.indexOf('-');
+		if (splitIndex != -1) {
+			String type = toolchain.substring(0, splitIndex);
+			if ("nightly".equals(type)) {
+				STORE.setDefault(toolchainIdPreference, toolchain);
+				STORE.setDefault(toolchainTypePreference, "Nightly");
+			} else {
+				for (String option : CorrosionPreferencePage.RUSTUP_TOOLCHAIN_OPTIONS) {
+					if (option.toLowerCase().equals(type)) {
+						STORE.setDefault(toolchainIdPreference, type);
+						STORE.setDefault(toolchainTypePreference, option);
+					}
+				}
+			}
+			return;
+		}
+		STORE.setDefault(toolchainIdPreference, toolchain.trim());
+		STORE.setDefault(toolchainTypePreference, "Other");
+	}
+
+	private String getRLSPathBestGuess() {
+		String command = findCommandPath("rls");
+		if (command.isEmpty()) {
+			File possibleCommandFile = new File(System.getProperty("user.home") + "/.cargo/bin/rls");
+			if (possibleCommandFile.exists() && possibleCommandFile.isFile() && possibleCommandFile.canExecute()) {
+				return possibleCommandFile.getAbsolutePath();
+			}
+		}
+		return command;
+	}
+
+	private String getSysrootPathBestGuess() {
+		File rustc = new File(findCommandPath("rustc"));
+		if (!(rustc.exists() && rustc.isFile() && rustc.canExecute())) {
+			rustc = new File(System.getProperty("user.home") + "/.cargo/bin/rustc");
+		}
+		if (!(rustc.exists() && rustc.isFile() && rustc.canExecute())) {
+			return "";
+		}
+		String[] command = new String[] { rustc.getAbsolutePath(), "--print", "sysroot" };
+		try {
+			Process process = Runtime.getRuntime().exec(command);
+			try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+				return in.readLine();
+			}
+		} catch (IOException e) {
+			return "";
+		}
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferencePage.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferencePage.java
new file mode 100644
index 0000000..461e56f
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/CorrosionPreferencePage.java
@@ -0,0 +1,569 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.ICoreRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.osgi.framework.Bundle;
+
+public class CorrosionPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+	public static final String PAGE_ID = "org.eclipse.corrosion.preferencePage";
+	public static final List<String> RUST_SOURCE_OPTIONS = Arrays.asList("rustup", "other", "disabled");
+	public static final List<String> RUSTUP_TOOLCHAIN_OPTIONS = Arrays.asList("Stable", "Beta", "Nightly", "Other");
+
+	private IPreferenceStore store;
+
+	private Button rustupRadioButton;
+	private Button otherRadioButton;
+	private Button disableRadioButton;
+
+	@Override
+	public void init(IWorkbench workbench) {
+		store = doGetPreferenceStore();
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		Composite container = new Composite(parent, SWT.NULL);
+		container.setLayout(new GridLayout(2, false));
+
+		createCommandPathsPart(container);
+
+		Label rlsLocationLabel = new Label(container, SWT.NONE);
+		rlsLocationLabel.setText("Rust Language Server Location:");
+		rlsLocationLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+
+		disableRadioButton = new Button(container, SWT.RADIO);
+		disableRadioButton.setText("Disable Rust editor");
+		disableRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+		disableRadioButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			setRadioSelection(2);
+		}));
+
+		otherRadioButton = new Button(container, SWT.RADIO);
+		otherRadioButton.setText("Other installation");
+		otherRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+		otherRadioButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			setRadioSelection(1);
+		}));
+		createOtherPart(container);
+
+		rustupRadioButton = new Button(container, SWT.RADIO);
+		rustupRadioButton.setText("Use Rustup");
+		rustupRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+		rustupRadioButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			setRadioSelection(0);
+		}));
+
+		createRustupPart(container);
+
+		initializeContent();
+		return container;
+	}
+
+	private void initializeContent() {
+		int sourceIndex = RUST_SOURCE_OPTIONS.indexOf(store.getString(CorrosionPreferenceInitializer.rustSourcePreference));
+		setRadioSelection(sourceIndex);
+		int toolchainIndex = RUSTUP_TOOLCHAIN_OPTIONS
+				.indexOf(store.getString(CorrosionPreferenceInitializer.toolchainTypePreference));
+		String toolchainId = store.getString(CorrosionPreferenceInitializer.toolchainIdPreference);
+		otherIdText.setText(toolchainId);
+		for (int i = 0; i < RUSTUP_TOOLCHAIN_OPTIONS.size(); i++) {
+			if (RUSTUP_TOOLCHAIN_OPTIONS.get(i).toLowerCase().equals(toolchainId.toLowerCase())) {
+				toolchainIndex = i;
+				break;
+			}
+		}
+		setToolchainSelection(toolchainIndex);
+		rustupPathText.setText(store.getString(CorrosionPreferenceInitializer.rustupPathPreference));
+		cargoPathText.setText(store.getString(CorrosionPreferenceInitializer.cargoPathPreference));
+		setDefaultPathsSelection(store.getBoolean(CorrosionPreferenceInitializer.defaultPathsPreference));
+		rlsPathText.setText(store.getString(CorrosionPreferenceInitializer.rlsPathPreference));
+		sysrootPathText.setText(store.getString(CorrosionPreferenceInitializer.sysrootPathPreference));
+	}
+
+	@Override
+	protected IPreferenceStore doGetPreferenceStore() {
+		return CorrosionPlugin.getDefault().getPreferenceStore();
+	}
+
+	private boolean isPageValid() {
+		int radioIndex = getRadioSelection();
+		if (!isCommandPathsValid()) {
+			return false;
+		}
+		if (radioIndex == 0 && isRustupSectionValid()) {
+			return true;
+		} else if (radioIndex == 1 && isOtherInstallSectionValid()) {
+			return true;
+		} else if (radioIndex == 2) {
+			return true;
+		}
+		return false;
+	}
+
+	private boolean isCommandPathsValid() {
+		String error = "";
+		if ((rustupPathText.getText().isEmpty() || cargoPathText.getText().isEmpty())) {
+			error = "Rustup and Cargo paths cannot be empty";
+		} else {
+			File rustup = new File(rustupPathText.getText());
+			File cargo = new File(cargoPathText.getText());
+			if (!rustup.exists() || !rustup.isFile()) {
+				error = "Input a valid `rustup` command path";
+			} else if (!rustup.canExecute()) {
+				error = "Inputted `rustup` command is not executable";
+			} else if (!cargo.exists() || !cargo.isFile()) {
+				error = "Input a valid `cargo` command path";
+			} else if (!cargo.canExecute()) {
+				error = "Inputted `cargo` command is not executable";
+			}
+		}
+
+		if (error.isEmpty()) {
+			setErrorMessage(null);
+		} else {
+			setErrorMessage(error);
+		}
+		setInstallRequired(!error.isEmpty());
+		return error.isEmpty();
+	}
+
+	private boolean isRustupSectionValid() {
+		if (rustupToolchainCombo.getSelectionIndex() == 3 && otherIdText.getText().isEmpty()) {
+			setErrorMessage("Toolchain ID cannot be empty");
+			return false;
+		}
+		setErrorMessage(null);
+		return true;
+	}
+
+	private boolean isOtherInstallSectionValid() {
+		if (rlsPathText.getText().isEmpty() || sysrootPathText.getText().isEmpty()) {
+			setErrorMessage("Paths cannot be empty");
+			return false;
+		}
+		File rls = new File(rlsPathText.getText());
+		if (!rls.exists() || !rls.isFile()) {
+			setErrorMessage("Input a valid path to the Rust Language Server (rls)");
+			return false;
+		} else if (!rls.canExecute()) {
+			setErrorMessage("Inputted `rls` command is not executable");
+			return false;
+		}
+
+		File sysrootPath = new File(sysrootPathText.getText());
+		boolean a = sysrootPath.exists();
+		boolean b = sysrootPath.isDirectory();
+		if (!a || !b) {
+			setErrorMessage("Input a valid path to the sysroot directory");
+			return false;
+		}
+		setErrorMessage(null);
+		return true;
+	}
+
+	@Override
+	protected void performDefaults() {
+		int sourceIndex = RUST_SOURCE_OPTIONS
+				.indexOf(store.getDefaultString(CorrosionPreferenceInitializer.rustSourcePreference));
+		setRadioSelection(sourceIndex);
+		int toolchainIndex = RUSTUP_TOOLCHAIN_OPTIONS
+				.indexOf(store.getDefaultString(CorrosionPreferenceInitializer.toolchainTypePreference));
+		String toolchainId = store.getDefaultString(CorrosionPreferenceInitializer.toolchainIdPreference);
+		otherIdText.setText(toolchainId);
+		for (int i = 0; i < RUSTUP_TOOLCHAIN_OPTIONS.size(); i++) {
+			if (RUSTUP_TOOLCHAIN_OPTIONS.get(i).toLowerCase().equals(toolchainId.toLowerCase())) {
+				toolchainIndex = i;
+				break;
+			}
+		}
+		setToolchainSelection(toolchainIndex);
+		setDefaultPathsSelection(store.getDefaultBoolean(CorrosionPreferenceInitializer.defaultPathsPreference));
+		rustupPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.rustupPathPreference));
+		cargoPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.cargoPathPreference));
+		rlsPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.rlsPathPreference));
+		sysrootPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.sysrootPathPreference));
+		super.performDefaults();
+	}
+
+	private void setDefaultPathsSelection(boolean selection) {
+		useDefaultPathsCheckbox.setSelection(selection);
+		if (selection) {
+			rustupPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.rustupPathPreference));
+			cargoPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.cargoPathPreference));
+		}
+		setDefaultPathsEnabled(!selection);
+	}
+
+	private void setToolchainSelection(int selection) {
+		rustupToolchainCombo.select(selection);
+		GridData otherIdData = (GridData) otherIdComposite.getLayoutData();
+		otherIdData.exclude = selection != 3;
+		otherIdComposite.getParent().layout();
+		otherIdComposite.setVisible(!otherIdData.exclude);
+		otherIdComposite.getParent().getParent().layout(true);
+	}
+
+	private int getRadioSelection() {
+		if (rustupRadioButton.getSelection()) {
+			return 0;
+		}
+		if (otherRadioButton.getSelection()) {
+			return 1;
+		}
+		return 2;
+	}
+
+	private void setRadioSelection(int selection) {
+		setOtherEnabled(false);
+		setRustupEnabled(false);
+		rustupRadioButton.setSelection(false);
+		otherRadioButton.setSelection(false);
+		disableRadioButton.setSelection(false);
+
+		if (selection == 0) {
+			rustupRadioButton.setSelection(true);
+			setRustupEnabled(true);
+		} else if (selection == 1) {
+			otherRadioButton.setSelection(true);
+			setOtherEnabled(true);
+		} else {
+			disableRadioButton.setSelection(true);
+		}
+		isPageValid();
+	}
+
+	@Override
+	public boolean performOk() {
+		int source = getRadioSelection();
+		store.setValue(CorrosionPreferenceInitializer.rustSourcePreference, RUST_SOURCE_OPTIONS.get(source));
+		if (source == 0) {
+			String id = getToolchainId();
+			store.setValue(CorrosionPreferenceInitializer.toolchainTypePreference, rustupToolchainCombo.getText());
+			store.setValue(CorrosionPreferenceInitializer.toolchainIdPreference, id);
+			store.setValue(CorrosionPreferenceInitializer.defaultPathsPreference, useDefaultPathsCheckbox.getSelection());
+			store.setValue(CorrosionPreferenceInitializer.rustupPathPreference, rustupPathText.getText());
+			store.setValue(CorrosionPreferenceInitializer.cargoPathPreference, cargoPathText.getText());
+			RustManager.setDefaultToolchain(id);
+		} else if (source == 1) {
+			store.setValue(CorrosionPreferenceInitializer.rlsPathPreference, rlsPathText.getText());
+			store.setValue(CorrosionPreferenceInitializer.sysrootPathPreference, sysrootPathText.getText());
+		}
+		return true;
+	}
+
+	private String getToolchainId() {
+		int index = rustupToolchainCombo.getSelectionIndex();
+		if (index == -1) {
+			return "";
+		} else if (index < 3) {
+			return RUSTUP_TOOLCHAIN_OPTIONS.get(index).toLowerCase();
+		} else {
+			return otherIdText.getText();
+		}
+	}
+
+	private Button installButton;
+
+	private Button useDefaultPathsCheckbox;
+
+	private Label rustupLabel;
+	private Text rustupPathText;
+	private Button rustupBrowseButton;
+
+	private Label cargoLabel;
+	private Text cargoPathText;
+	private Button cargoBrowseButton;
+
+	private void createCommandPathsPart(Composite container) {
+		Composite parent = new Composite(container, SWT.NULL);
+		parent.setLayout(new GridLayout(3, false));
+		parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+		GridData textGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		GridData buttonGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+
+		useDefaultPathsCheckbox = new Button(parent, SWT.CHECK);
+		useDefaultPathsCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+		useDefaultPathsCheckbox.setText("Use default paths (rustup and cargo required for most features)");
+		useDefaultPathsCheckbox.addSelectionListener(widgetSelectedAdapter(e -> {
+			setDefaultPathsEnabled(!useDefaultPathsCheckbox.getSelection());
+			if (useDefaultPathsCheckbox.getSelection()) {
+				rustupPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.rustupPathPreference));
+				cargoPathText.setText(store.getDefaultString(CorrosionPreferenceInitializer.cargoPathPreference));
+			}
+			setValid(isPageValid());
+		}));
+		installButton = new Button(parent, SWT.NONE);
+		installButton.setLayoutData(buttonGridData);
+		installButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			if (Platform.getOS().equals(Platform.OS_WIN32)) {
+				Program.launch("https://rustup.rs/");
+			} else {
+				installCommands();
+			}
+		}));
+
+		rustupLabel = new Label(parent, SWT.NONE);
+		rustupLabel.setText("Rustup:");
+		rustupLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		rustupPathText = new Text(parent, SWT.BORDER);
+		rustupPathText.setLayoutData(textGridData);
+		rustupPathText.addModifyListener(e -> {
+			setValid(isPageValid());
+		});
+
+		rustupBrowseButton = new Button(parent, SWT.NONE);
+		rustupBrowseButton.setLayoutData(buttonGridData);
+		rustupBrowseButton.setText("Browse...");
+		rustupBrowseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			FileDialog dialog = new FileDialog(rustupBrowseButton.getShell());
+			String path = dialog.open();
+			if (path != null) {
+				rustupPathText.setText(path);
+			}
+		}));
+
+		cargoLabel = new Label(parent, SWT.NONE);
+		cargoLabel.setText("Cargo:");
+		cargoLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		cargoPathText = new Text(parent, SWT.BORDER);
+		cargoPathText.setLayoutData(textGridData);
+		cargoPathText.addModifyListener(e -> {
+			setValid(isPageValid());
+		});
+
+		cargoBrowseButton = new Button(parent, SWT.NONE);
+		cargoBrowseButton.setLayoutData(buttonGridData);
+		cargoBrowseButton.setText("Browse...");
+		cargoBrowseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			FileDialog dialog = new FileDialog(cargoBrowseButton.getShell());
+			String path = dialog.open();
+			if (path != null) {
+				cargoPathText.setText(path);
+			}
+		}));
+	}
+
+	private void installCommands() {
+		installButton.setText("Installling");
+		installButton.setEnabled(false);
+		Job.create("Installing Rustup and Cargo", (ICoreRunnable) monitor -> {
+			try {
+				Bundle bundle = Platform.getBundle("org.eclipse.corrosion");
+				URL fileURL = FileLocator.toFileURL(bundle.getEntry("scripts/rustup.sh"));
+				File file = new File(new URI(fileURL.getProtocol(), fileURL.getPath(), null));
+				String[] command = new String[] { "/bin/bash", "-c", file.getAbsolutePath() + " -y" };
+				ProcessBuilder builder = new ProcessBuilder(command);
+				Process process = builder.start();
+				if (process.waitFor() == 0) {
+					CorrosionPreferenceInitializer initializer = new CorrosionPreferenceInitializer();
+					initializer.initializeDefaultPreferences();
+					Display.getDefault().asyncExec(() -> {
+						setInstallRequired(false);
+						performDefaults();
+						setValid(isPageValid());
+					});
+					RustManager.setDefaultToolchain("beta");
+					return;
+				}
+			} catch (InterruptedException | URISyntaxException | IOException e) {
+				// will be caught with dialog
+			}
+			Display.getDefault().asyncExec(() -> {
+				setInstallRequired(true);
+				MessageDialog.openError(getShell(), "Cannot install Rust and Cargo",
+						"We were unable to perform the install, you can do so manually by going to doc.crates.io");
+			});
+		}).schedule();
+	}
+
+	private void setInstallRequired(Boolean required) {
+		if (required) {
+			installButton.setText("Install");
+		} else {
+			installButton.setText("Installed");
+		}
+		installButton.setEnabled(required);
+	}
+
+	private Label rustupToolchainLabel;
+	private Combo rustupToolchainCombo;
+
+	private Composite otherIdComposite;
+	private Label otherIdLabel;
+	private Text otherIdText;
+
+	private void createRustupPart(Composite container) {
+
+		Composite parent = new Composite(container, SWT.NULL);
+		parent.setLayout(new GridLayout(3, false));
+		parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+		rustupToolchainLabel = new Label(parent, SWT.NONE);
+		rustupToolchainLabel.setText("Toolchain:");
+		GridData rustupToolchainGridData = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
+		rustupToolchainGridData.horizontalIndent = 25;
+		rustupToolchainLabel.setLayoutData(rustupToolchainGridData);
+
+		rustupToolchainCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
+		rustupToolchainCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		for (String toolchain : RUSTUP_TOOLCHAIN_OPTIONS) {
+			rustupToolchainCombo.add(toolchain);
+		}
+		rustupToolchainCombo.addSelectionListener(widgetSelectedAdapter(e -> {
+			setToolchainSelection(rustupToolchainCombo.getSelectionIndex());
+			getShell().pack();
+			getShell().layout();
+			setValid(isPageValid());
+		}));
+		new Label(parent, SWT.NONE);
+
+		new Label(parent, SWT.NONE);
+		otherIdComposite = new Composite(parent, SWT.NULL);
+		otherIdComposite.setLayout(new GridLayout(3, false));
+		GridData otherIdData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		otherIdData.exclude = false;
+		otherIdComposite.setLayoutData(otherIdData);
+		otherIdLabel = new Label(otherIdComposite, SWT.NONE);
+		otherIdLabel.setText("ID:");
+		otherIdLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+		otherIdText = new Text(otherIdComposite, SWT.BORDER);
+		otherIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		otherIdText.addModifyListener(e -> {
+			setValid(isPageValid());
+		});
+		new Label(parent, SWT.NONE);
+	}
+
+	private void setDefaultPathsEnabled(boolean enabled) {
+		rustupLabel.setEnabled(enabled);
+		rustupPathText.setEnabled(enabled);
+		rustupBrowseButton.setEnabled(enabled);
+		cargoLabel.setEnabled(enabled);
+		cargoPathText.setEnabled(enabled);
+		cargoBrowseButton.setEnabled(enabled);
+	}
+
+	private void setRustupEnabled(boolean enabled) {
+		rustupToolchainLabel.setEnabled(enabled);
+		rustupToolchainCombo.setEnabled(enabled);
+		otherIdLabel.setEnabled(enabled);
+		otherIdText.setEnabled(enabled);
+	}
+
+	private Label rlsLabel;
+	private Text rlsPathText;
+	private Button rlsBrowseButton;
+
+	private Label sysrootLabel;
+	private Text sysrootPathText;
+	private Button sysrootBrowseButton;
+
+	private void createOtherPart(Composite container) {
+		Composite parent = new Composite(container, SWT.NULL);
+		parent.setLayout(new GridLayout(3, false));
+		parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+		GridData labelIndent = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
+		labelIndent.horizontalIndent = 25;
+
+		GridData textIndent = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		textIndent.horizontalIndent = 50;
+		textIndent.widthHint = convertWidthInCharsToPixels(50);
+
+		rlsLabel = new Label(parent, SWT.NONE);
+		rlsLabel.setText("Path to the Rust Language Server (rls):");
+		rlsLabel.setLayoutData(labelIndent);
+
+		rlsPathText = new Text(parent, SWT.BORDER);
+		rlsPathText.setLayoutData(textIndent);
+		rlsPathText.addModifyListener(e -> {
+			setValid(isPageValid());
+		});
+
+		rlsBrowseButton = new Button(parent, SWT.NONE);
+		rlsBrowseButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+		rlsBrowseButton.setText("Browse...");
+		rlsBrowseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			FileDialog dialog = new FileDialog(rlsBrowseButton.getShell());
+			String path = dialog.open();
+			if (path != null) {
+				rlsPathText.setText(path);
+			}
+		}));
+
+		sysrootLabel = new Label(parent, SWT.NONE);
+		sysrootLabel.setText("Path to `sysroot` of the Rust installation:");
+		sysrootLabel.setLayoutData(labelIndent);
+
+		sysrootPathText = new Text(parent, SWT.BORDER);
+		sysrootPathText.setLayoutData(textIndent);
+		sysrootPathText.addModifyListener(e -> {
+			setValid(isPageValid());
+		});
+
+		sysrootBrowseButton = new Button(parent, SWT.NONE);
+		sysrootBrowseButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+		sysrootBrowseButton.setText("Browse...");
+		sysrootBrowseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			FileDialog dialog = new FileDialog(sysrootBrowseButton.getShell());
+			String path = dialog.open();
+			if (path != null) {
+				sysrootPathText.setText(path);
+			}
+		}));
+	}
+
+	private void setOtherEnabled(boolean enabled) {
+		rlsLabel.setEnabled(enabled);
+		rlsPathText.setEnabled(enabled);
+		rlsBrowseButton.setEnabled(enabled);
+
+		sysrootLabel.setEnabled(enabled);
+		sysrootPathText.setEnabled(enabled);
+		sysrootBrowseButton.setEnabled(enabled);
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSClientImplementation.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSClientImplementation.java
new file mode 100644
index 0000000..9d2f75d
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSClientImplementation.java
@@ -0,0 +1,75 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.lsp4e.LanguageClientImpl;
+import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
+
+@SuppressWarnings("restriction")
+public class RLSClientImplementation extends LanguageClientImpl {
+
+	private static Job diagnosticsJob;
+	private String status;
+
+	@JsonNotification("rustDocument/beginBuild")
+	public void beginBuild() {
+		status = "Building project";
+		initializeJob();
+	}
+
+	@JsonNotification("rustDocument/diagnosticsBegin")
+	public void diagnosticsBegin() {
+		status = "Compiling diagnostics";
+		initializeJob();
+	}
+
+	@JsonNotification("rustDocument/diagnosticsEnd")
+	public void diagnosticsEnd() {
+		status = null;
+		if (diagnosticsJob != null) {
+			diagnosticsJob.done(new Status(IStatus.OK, CorrosionPlugin.PLUGIN_ID, null));
+			diagnosticsJob = null;
+		}
+	}
+
+	private void initializeJob() {
+		if (diagnosticsJob == null) {
+			diagnosticsJob = Job.create("Compiling Rust project diagnostics", monitor -> {
+				SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
+				subMonitor.worked(1);
+				try {
+					int maxWaitTime = 60000; // 1 minute
+					subMonitor.beginTask("Building project", IProgressMonitor.UNKNOWN);
+					while (maxWaitTime > 0 && !subMonitor.isCanceled()) {
+						if (status == null || subMonitor.isCanceled()) {
+							break;
+						} else {
+							subMonitor.subTask(status);
+						}
+						Thread.sleep(50);
+						maxWaitTime -= 50;
+					}
+					diagnosticsJob = null;
+				} catch (InterruptedException e) {
+					// Exception ends the job
+				}
+			});
+			diagnosticsJob.schedule();
+		}
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSServerInterface.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSServerInterface.java
new file mode 100644
index 0000000..58031f0
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSServerInterface.java
@@ -0,0 +1,28 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.lsp4j.Location;
+import org.eclipse.lsp4j.TextDocumentPositionParams;
+import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
+import org.eclipse.lsp4j.services.LanguageServer;
+
+public interface RLSServerInterface extends LanguageServer {
+
+	@JsonRequest("rustDocument/implementations")
+	CompletableFuture<List<? extends Location>> implementations(TextDocumentPositionParams position);
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSStreamConnectionProvider.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSStreamConnectionProvider.java
new file mode 100644
index 0000000..1910781
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/RLSStreamConnectionProvider.java
@@ -0,0 +1,241 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import java.io.BufferedReader;
+import java.io.FilterInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.lsp4e.server.StreamConnectionProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+public class RLSStreamConnectionProvider implements StreamConnectionProvider {
+
+	private static boolean hasCancelledSetup = false;
+	private boolean DEBUG = Boolean.parseBoolean(System.getProperty("rsl.lsp.debug"));
+	private Process process;
+
+	@Override
+	public void start() throws IOException {
+		boolean wereSystemPropertiesSet = setSystemProperties();
+		String rls = getRLS();
+		if ((rls.isEmpty() || !wereSystemPropertiesSet)) {
+			showSetupRustNotification();
+			return;
+		}
+		String[] command = new String[] { "/bin/bash", "-c", rls };
+		if (Platform.getOS().equals(Platform.OS_WIN32)) {
+			command = new String[] { "cmd", "/c", rls };
+		}
+		this.process = Runtime.getRuntime().exec(command);
+	}
+
+	private boolean setSystemProperties() {
+		CorrosionPlugin plugin = CorrosionPlugin.getDefault();
+		IPreferenceStore preferenceStore = plugin.getPreferenceStore();
+		int rustSourceIndex = CorrosionPreferencePage.RUST_SOURCE_OPTIONS
+				.indexOf(preferenceStore.getString(CorrosionPreferenceInitializer.rustSourcePreference));
+
+		String sysrootPath = "";
+
+		if (rustSourceIndex == 0) {
+			String rustup = preferenceStore.getString(CorrosionPreferenceInitializer.rustupPathPreference);
+			String toolchain = preferenceStore.getString(CorrosionPreferenceInitializer.toolchainIdPreference);
+			if (!(rustup.isEmpty() || toolchain.isEmpty())) {
+				String[] command = new String[] { rustup, "run", toolchain, "rustc", "--print", "sysroot" };
+				try {
+					Process process = Runtime.getRuntime().exec(command);
+					try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+						sysrootPath = in.readLine();
+					}
+				} catch (IOException e) {
+					// Caught with final return
+				}
+			}
+		} else if (rustSourceIndex == 1) {
+			sysrootPath = preferenceStore.getString(CorrosionPreferenceInitializer.sysrootPathPreference);
+		}
+
+		if (!sysrootPath.isEmpty()) {
+			System.setProperty("SYS_ROOT", sysrootPath);
+			System.setProperty("LD_LIBRARY_PATH", sysrootPath + "/lib");
+			String sysRoot = System.getProperty("SYS_ROOT");
+			String ldLibraryPath = System.getProperty("LD_LIBRARY_PATH");
+			if (!(sysRoot == null || sysRoot.isEmpty() || ldLibraryPath == null || ldLibraryPath.isEmpty())) {
+				return true;
+			}
+		}
+		CorrosionPlugin.getDefault().getLog().log(new Status(IStatus.ERROR,
+				CorrosionPlugin.getDefault().getBundle().getSymbolicName(),
+				"Was unable to set the `SYS_ROOT` and `LD_LIBRARY_PATH` environment variables. Please do so manually."));
+		return false;
+	}
+
+	private String getRLS() {
+		CorrosionPlugin plugin = CorrosionPlugin.getDefault();
+		IPreferenceStore preferenceStore = plugin.getPreferenceStore();
+		int rustSourceIndex = CorrosionPreferencePage.RUST_SOURCE_OPTIONS
+				.indexOf(preferenceStore.getString(CorrosionPreferenceInitializer.rustSourcePreference));
+
+		if (rustSourceIndex == 0) {
+			String rustup = preferenceStore.getString(CorrosionPreferenceInitializer.rustupPathPreference);
+			String toolchain = preferenceStore.getString(CorrosionPreferenceInitializer.toolchainIdPreference);
+			if (!(rustup.isEmpty() || toolchain.isEmpty())) {
+				return rustup + " run " + toolchain + " rls";
+			}
+		} else if (rustSourceIndex == 1) {
+			String rls = preferenceStore.getString(CorrosionPreferenceInitializer.rlsPathPreference);
+			if (!rls.isEmpty()) {
+				return rls;
+			}
+		}
+
+		CorrosionPlugin.getDefault().getLog()
+				.log(new Status(IStatus.ERROR, CorrosionPlugin.getDefault().getBundle().getSymbolicName(),
+						"Rust Language Server not found. Update in Rust preferences."));
+		return "";
+	}
+
+	private void showSetupRustNotification() {
+		if (hasCancelledSetup) {
+			return;
+		}
+		Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+		int dialogResponse = MessageDialog.open(MessageDialog.CONFIRM, shell, "Rust Support Not Found",
+				"Requirments for Rust edition were not found. Install the required components or input their paths in the Rust Preferences.",
+				SWT.NONE, "Open Preferences", "Cancel");
+		if (dialogResponse == 0) {
+			PreferenceDialog preferenceDialog = PreferencesUtil.createPreferenceDialogOn(shell,
+					CorrosionPreferencePage.PAGE_ID, new String[] { CorrosionPreferencePage.PAGE_ID }, null);
+			preferenceDialog.setBlockOnOpen(true);
+			preferenceDialog.open();
+		} else {
+			hasCancelledSetup = true;
+		}
+	}
+
+	@Override
+	public InputStream getInputStream() {
+		if (DEBUG) {
+			return new FilterInputStream(process.getInputStream()) {
+				@Override
+				public int read() throws IOException {
+					int res = super.read();
+					System.err.print((char) res);
+					return res;
+				}
+
+				@Override
+				public int read(byte[] b, int off, int len) throws IOException {
+					int bytes = super.read(b, off, len);
+					byte[] payload = new byte[bytes];
+					System.arraycopy(b, off, payload, 0, bytes);
+					System.err.print(new String(payload));
+					return bytes;
+				}
+
+				@Override
+				public int read(byte[] b) throws IOException {
+					int bytes = super.read(b);
+					byte[] payload = new byte[bytes];
+					System.arraycopy(b, 0, payload, 0, bytes);
+					System.err.print(new String(payload));
+					return bytes;
+				}
+			};
+		} else {
+			return process.getInputStream();
+		}
+	}
+
+	@Override
+	public OutputStream getOutputStream() {
+		if (DEBUG) {
+			return new FilterOutputStream(process.getOutputStream()) {
+				@Override
+				public void write(int b) throws IOException {
+					System.err.print((char) b);
+					super.write(b);
+				}
+
+				@Override
+				public void write(byte[] b) throws IOException {
+					System.err.print(new String(b));
+					super.write(b);
+				}
+
+				@Override
+				public void write(byte[] b, int off, int len) throws IOException {
+					byte[] actual = new byte[len];
+					System.arraycopy(b, off, actual, 0, len);
+					System.err.print(new String(actual));
+					super.write(b, off, len);
+				}
+			};
+		} else {
+			return process.getOutputStream();
+		}
+	}
+
+	@Override
+	public void stop() {
+		process.destroy();
+	}
+
+	@Override
+	public InputStream getErrorStream() {
+		if (DEBUG) {
+			return new FilterInputStream(process.getErrorStream()) {
+				@Override
+				public int read() throws IOException {
+					int res = super.read();
+					System.err.print((char) res);
+					return res;
+				}
+
+				@Override
+				public int read(byte[] b, int off, int len) throws IOException {
+					int bytes = super.read(b, off, len);
+					byte[] payload = new byte[bytes];
+					System.arraycopy(b, off, payload, 0, bytes);
+					System.err.print(new String(payload));
+					return bytes;
+				}
+
+				@Override
+				public int read(byte[] b) throws IOException {
+					int bytes = super.read(b);
+					byte[] payload = new byte[bytes];
+					System.arraycopy(b, 0, payload, 0, bytes);
+					System.err.print(new String(payload));
+					return bytes;
+				}
+			};
+		} else {
+			return process.getErrorStream();
+		}
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/RustManager.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/RustManager.java
new file mode 100644
index 0000000..3aef716
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/RustManager.java
@@ -0,0 +1,237 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.lsp4e.LanguageServiceAccessor;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.lsp4j.DidChangeConfigurationParams;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+//TODO: investigate solution not requiring breaking restrictions
+@SuppressWarnings("restriction")
+public class RustManager {
+	private static final IPreferenceStore STORE = CorrosionPlugin.getDefault().getPreferenceStore();
+
+	public static String getDefaultToolchain() {
+		String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
+		if (!rustup.isEmpty()) {
+			try {
+				ProcessBuilder builder = new ProcessBuilder(new String[] { rustup, "show" });
+				Process process = builder.start();
+
+				if (process.waitFor() == 0) {
+					try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+						String line = in.readLine();
+						while (line != null) {
+							if (line.matches("^.*\\(default\\)$")) {
+								if (line.matches("^nightly-\\d{4}-\\d{2}-\\d{2}.*$")) {
+									return line.substring(0, 18);// "nightly-YYYY-MM-DD".length()==18
+								}
+								int splitIndex = line.indexOf('-');
+								if (splitIndex != -1) {
+									return line.substring(0, splitIndex);
+								}
+								return line;
+							}
+							line = in.readLine();
+						}
+					}
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+				// Errors will be caught with empty return
+			}
+		}
+		return "";
+	}
+
+	private static Job settingToolchainJob = null;
+
+	public static void setDefaultToolchain(String toolchainId) {
+		if (settingToolchainJob != null) {
+			settingToolchainJob.cancel();
+		}
+
+		settingToolchainJob = Job.create("Setting RLS Toolchain", monitor -> {
+			SubMonitor subMonitor = SubMonitor.convert(monitor, 5);
+			subMonitor.beginTask("Installing Toolchain", 5);
+			subMonitor.split(1);
+			if (!runRustupCommand(subMonitor, "toolchain", "install", toolchainId)) {
+				if (!monitor.isCanceled()) {
+					showToolchainSelectionError("Unable to install toolchain `" + toolchainId
+							+ "`. Ensure the `rustup` command path is correct and that `" + toolchainId
+							+ "` is a valid toolchain ID.");
+				}
+				return;
+			}
+			subMonitor.subTask("Setting default toolchain");
+			subMonitor.split(1);
+			if (!runRustupCommand(subMonitor, "default", toolchainId)) {
+				if (!monitor.isCanceled()) {
+					showToolchainSelectionError("Unable to set `" + toolchainId + "` as the default toolchain");
+				}
+				return;
+			}
+			subMonitor.subTask("Adding `rls-preview` component");
+			subMonitor.split(1);
+			if (!runRustupCommand(subMonitor, "component", "add", "rls-preview")) {
+				if (!monitor.isCanceled()) {
+					showToolchainSelectionError("The toolchain `" + toolchainId
+							+ "` does not contain the Rust Language Server, please select a different toolchain");
+				}
+				return;
+			}
+			subMonitor.subTask("Adding `rust-analysis` and `rust-src` components");
+			subMonitor.split(1);
+			if (!runRustupCommand(subMonitor, "component", "add", "rust-analysis")
+					|| !runRustupCommand(subMonitor, "component", "add", "rust-src")) {
+				if (!monitor.isCanceled()) {
+					showToolchainSelectionError(
+							"Unable to add required components, please select a different toolchain");
+				}
+				return;
+			}
+			Map<String, String> updatedSettings = new HashMap<>();
+			updatedSettings.put("target", toolchainId);
+
+			sendDidChangeConfigurationsMessage(updatedSettings);
+		});
+		settingToolchainJob.schedule();
+	}
+
+	private static void sendDidChangeConfigurationsMessage(Map<String, String> updatedSettings) {
+		DidChangeConfigurationParams params = new DidChangeConfigurationParams();
+		params.setSettings(updatedSettings);
+		LSPDocumentInfo info = infoFromOpenEditors();
+		if (info != null) {
+			info.getInitializedLanguageClient()
+					.thenAccept(languageServer -> languageServer.getWorkspaceService().didChangeConfiguration(params));
+		}
+	}
+
+	private static LSPDocumentInfo infoFromOpenEditors() {
+		for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+			for (IWorkbenchPage page : window.getPages()) {
+				for (IEditorReference editor : page.getEditorReferences()) {
+					IEditorInput input;
+					try {
+						input = editor.getEditorInput();
+					} catch (PartInitException e) {
+						continue;
+					}
+					if (input.getName().endsWith(".rs") && editor.getEditor(false) instanceof ITextEditor) {
+						IDocument document = (((ITextEditor) editor.getEditor(false)).getDocumentProvider())
+								.getDocument(input);
+						Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(document,
+								capabilities -> Boolean.TRUE.equals(capabilities.getReferencesProvider()));
+						if (infos.isEmpty()) {
+							continue;
+						}
+						return infos.iterator().next();
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	private static void showToolchainSelectionError(String message) {
+		Display.getDefault().asyncExec(() -> {
+			MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+					"Rust Toolchain Selection Failure", message);
+		});
+	}
+
+	private static boolean runRustupCommand(SubMonitor monitor, String... arguments) {
+		String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
+		if (rustup.isEmpty()) {
+			return false;
+		}
+		try {
+			String[] command = new String[arguments.length + 1];
+			command[0] = rustup;
+			System.arraycopy(arguments, 0, command, 1, arguments.length);
+			ProcessBuilder builder = new ProcessBuilder(command);
+			builder.inheritIO();
+			Process process = builder.start();
+			while (process.isAlive() && !monitor.isCanceled()) {
+				Thread.sleep(50);
+			}
+			if (monitor.isCanceled()) {
+				process.destroyForcibly();
+				return false;
+			}
+
+			return process.waitFor() == 0;
+		} catch (IOException | InterruptedException e) {
+			return false;
+		}
+	}
+
+	public static List<String> getToolchains() {
+		List<String> toolchainsList = new ArrayList<>();
+		String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
+		if (!rustup.isEmpty()) {
+			try {
+				ProcessBuilder builder = new ProcessBuilder(new String[] { rustup, "show" });
+				Process process = builder.start();
+
+				if (process.waitFor() == 0) {
+					try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+						String line = in.readLine();
+						while (line != null && !line.equals("active toolchain")) {
+							String toolchain = "";
+							if (line.matches("^nightly-\\d{4}-\\d{2}-\\d{2}.*$")) {
+								toolchain = line.substring(0, 18);// "nightly-YYYY-MM-DD".length()==18
+							} else if (line.matches("\\w+\\-.*")) {
+								int splitIndex = line.indexOf('-');
+								if (splitIndex != -1) {
+									toolchain = line.substring(0, splitIndex);
+								}
+							}
+							if (!toolchain.isEmpty()) {
+								toolchainsList.add(toolchain);
+							}
+							line = in.readLine();
+						}
+					}
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+				// Errors will be caught with empty return
+			}
+		}
+		return toolchainsList;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/RustPerspective.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/RustPerspective.java
new file mode 100644
index 0000000..a8f06e1
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/RustPerspective.java
@@ -0,0 +1,86 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion;
+
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.corrosion.wizards.newCargo.NewCargoProjectWizard;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+import org.eclipse.ui.console.IConsoleConstants;
+import org.eclipse.ui.wizards.newresource.BasicNewFileResourceWizard;
+import org.eclipse.ui.wizards.newresource.BasicNewFolderResourceWizard;
+
+public class RustPerspective implements IPerspectiveFactory {
+	public static final String ID = "org.eclipse.corrosion.rustPerspective";
+
+	@Override
+	public void createInitialLayout(IPageLayout layout) {
+		addViewStructure(layout);
+
+		addActionSets(layout);
+		addShowViewShortcuts(layout);
+		addNewWizardShortcuts(layout);
+		addPerspectiveShotcuts(layout);
+	}
+
+	protected void addViewStructure(IPageLayout layout) {
+		String editorArea = layout.getEditorArea();
+
+		IFolderLayout leftFolder = layout.createFolder("leftPane", IPageLayout.LEFT, 0.25f, editorArea);
+		leftFolder.addView(IPageLayout.ID_PROJECT_EXPLORER);
+
+		IFolderLayout bottomFolder = layout.createFolder("bottomPane", IPageLayout.BOTTOM, 0.75f, editorArea);
+
+		bottomFolder.addView(IPageLayout.ID_PROBLEM_VIEW);
+		bottomFolder.addView(IPageLayout.ID_TASK_LIST);
+		bottomFolder.addPlaceholder(NewSearchUI.SEARCH_VIEW_ID);
+		bottomFolder.addView(IPageLayout.ID_PROGRESS_VIEW);
+		bottomFolder.addView(IConsoleConstants.ID_CONSOLE_VIEW);
+
+		// Create outline after bottom pane
+		layout.addView(IPageLayout.ID_OUTLINE, IPageLayout.RIGHT, 0.75f, editorArea);
+	}
+
+	protected void addShowViewShortcuts(IPageLayout layout) {
+		layout.addShowViewShortcut(IPageLayout.ID_OUTLINE);
+
+		layout.addShowViewShortcut(IPageLayout.ID_PROBLEM_VIEW);
+		layout.addShowViewShortcut(IPageLayout.ID_TASK_LIST);
+		layout.addShowViewShortcut(NewSearchUI.SEARCH_VIEW_ID);
+		layout.addShowViewShortcut(IPageLayout.ID_PROGRESS_VIEW);
+		layout.addShowViewShortcut(IConsoleConstants.ID_CONSOLE_VIEW);
+	}
+
+	protected void addActionSets(IPageLayout layout) {
+		layout.addActionSet(IPageLayout.ID_NAVIGATE_ACTION_SET);
+		layout.addActionSet(IDebugUIConstants.LAUNCH_ACTION_SET);
+	}
+
+	protected void addNewWizardShortcuts(IPageLayout layout) {
+		// Lang
+		layout.addNewWizardShortcut(NewCargoProjectWizard.ID);
+
+		// General
+		layout.addNewWizardShortcut(BasicNewFolderResourceWizard.WIZARD_ID);
+		layout.addNewWizardShortcut(BasicNewFileResourceWizard.WIZARD_ID);
+	}
+
+	protected void addPerspectiveShotcuts(IPageLayout layout) {
+		layout.addPerspectiveShortcut("org.eclipse.debug.ui.DebugPerspective"); //$NON-NLS-1$
+		layout.addPerspectiveShortcut("org.eclipse.ui.resourcePerspective"); //$NON-NLS-1$
+		layout.addPerspectiveShortcut("org.eclipse.team.ui.TeamSynchronizingPerspective"); //$NON-NLS-1$
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/AddCargoBuilder.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/AddCargoBuilder.java
new file mode 100644
index 0000000..934f4ea
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/AddCargoBuilder.java
@@ -0,0 +1,83 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.builder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+public class AddCargoBuilder extends AbstractHandler {
+
+	@Override
+	public Object execute(final ExecutionEvent event) {
+		final IProject project = getProject(event);
+
+		if (project != null) {
+			try {
+				if (hasBuilder(project)) {
+					return null;
+				}
+
+				IProjectDescription description = project.getDescription();
+				final ICommand buildCommand = description.newCommand();
+				buildCommand.setBuilderName(IncrementalCargoBuilder.BUILDER_ID);
+
+				final List<ICommand> commands = new ArrayList<>();
+				commands.addAll(Arrays.asList(description.getBuildSpec()));
+				commands.add(buildCommand);
+
+				description.setBuildSpec(commands.toArray(new ICommand[commands.size()]));
+				project.setDescription(description, null);
+
+			} catch (final CoreException e) {
+			}
+		}
+
+		return null;
+	}
+
+	public static IProject getProject(final ExecutionEvent event) {
+		final ISelection selection = HandlerUtil.getCurrentSelection(event);
+		if (selection instanceof IStructuredSelection) {
+			final Object element = ((IStructuredSelection) selection).getFirstElement();
+
+			return Platform.getAdapterManager().getAdapter(element, IProject.class);
+		}
+
+		return null;
+	}
+
+	public static final boolean hasBuilder(final IProject project) {
+		try {
+			for (final ICommand buildSpec : project.getDescription().getBuildSpec()) {
+				if (IncrementalCargoBuilder.BUILDER_ID.equals(buildSpec.getBuilderName())) {
+					return true;
+				}
+			}
+		} catch (final CoreException e) {
+		}
+
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/IncrementalCargoBuilder.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/IncrementalCargoBuilder.java
new file mode 100644
index 0000000..dc69613
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/IncrementalCargoBuilder.java
@@ -0,0 +1,80 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.builder;
+
+import java.util.Map;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+
+public class IncrementalCargoBuilder extends IncrementalProjectBuilder {
+
+	public static final String BUILDER_ID = "org.eclipse.corrosion.builder.IncrementalCargoBuilder";
+	private static Job buildJob;
+	private static boolean wasCausedByRefresh = false;
+
+	@Override
+	protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
+		if (wasCausedByRefresh) {
+			wasCausedByRefresh = false;
+			return null;
+		}
+		IProject project = getProject();
+		IPath manifest = project.getFile("Cargo.toml").getLocation();
+		IMarker[] errorMarkers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
+
+		if (buildJob != null) {
+			buildJob.cancel();
+		}
+		if (errorMarkers.length == 0 && manifest != null) {
+			buildJob = Job.create("cargo build", buildMonitor -> {
+				SubMonitor subMonitor = SubMonitor.convert(buildMonitor, 2);
+				subMonitor.worked(1);
+				try {
+					IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+					String cargo = store.getString(CorrosionPreferenceInitializer.cargoPathPreference);
+					String[] commandList = { cargo, "build", "--manifest-path", manifest.toString() };
+					Process buildProcess = DebugPlugin.exec(commandList, project.getLocation().makeAbsolute().toFile());
+					while (buildProcess.isAlive() && !subMonitor.isCanceled()) {
+						Thread.sleep(50);
+					}
+					wasCausedByRefresh = true;
+					project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
+					buildJob = null;
+					if (subMonitor.isCanceled()) {
+						buildProcess.destroyForcibly();
+						return;
+					}
+
+				} catch (InterruptedException | CoreException e) {
+					return;
+				}
+			});
+			buildJob.schedule();
+		}
+		return null;
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/RemoveCargoBuilder.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/RemoveCargoBuilder.java
new file mode 100644
index 0000000..fee63b0
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/RemoveCargoBuilder.java
@@ -0,0 +1,53 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.builder;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.runtime.CoreException;
+
+public class RemoveCargoBuilder extends AbstractHandler {
+
+	@Override
+	public Object execute(final ExecutionEvent event) throws ExecutionException {
+		final IProject project = AddCargoBuilder.getProject(event);
+
+		if (project != null) {
+			try {
+				final IProjectDescription description = project.getDescription();
+				final List<ICommand> commands = new ArrayList<>();
+				commands.addAll(Arrays.asList(description.getBuildSpec()));
+
+				for (final ICommand buildSpec : description.getBuildSpec()) {
+					if (IncrementalCargoBuilder.BUILDER_ID.equals(buildSpec.getBuilderName())) {
+						commands.remove(buildSpec);
+					}
+				}
+
+				description.setBuildSpec(commands.toArray(new ICommand[commands.size()]));
+				project.setDescription(description, null);
+			} catch (final CoreException e) {
+			}
+		}
+
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/TestCargoBuilderEnabled.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/TestCargoBuilderEnabled.java
new file mode 100644
index 0000000..b6244bb
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/builder/TestCargoBuilderEnabled.java
@@ -0,0 +1,33 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.builder;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.Platform;
+
+public class TestCargoBuilderEnabled extends PropertyTester {
+
+	private static final String IS_ENABLED = "isCargoBuilderEnabled";
+
+	@Override
+	public boolean test(final Object receiver, final String property, final Object[] args, final Object expectedValue) {
+		if (IS_ENABLED.equals(property)) {
+			final IProject project = Platform.getAdapterManager().getAdapter(receiver, IProject.class);
+			if (project != null) {
+				return AddCargoBuilder.hasBuilder(project);
+			}
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugDelegate.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugDelegate.java
new file mode 100644
index 0000000..b9c5236
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugDelegate.java
@@ -0,0 +1,210 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupDirector;
+import org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate;
+import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.variables.IStringVariableManager;
+import org.eclipse.core.variables.VariablesPlugin;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.ui.ILaunchShortcut;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+
+public class RustDebugDelegate extends GdbLaunchDelegate implements ILaunchShortcut {
+	public static final String BUILD_COMMAND_ATTRIBUTE = CorrosionPlugin.PLUGIN_ID + "BUILD_COMMAND";
+
+	@Override
+	public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor)
+			throws CoreException {
+		IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+		String cargo = store.getString(CorrosionPreferenceInitializer.cargoPathPreference);
+		String buildCommand = config.getAttribute(BUILD_COMMAND_ATTRIBUTE, "");
+		File projectLocation = new File(
+				config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, ""));
+
+		List<String> cmdLine = new ArrayList<>();
+		cmdLine.add(cargo);
+		if (buildCommand.isEmpty()) {
+			buildCommand = "build";
+		}
+		IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
+		buildCommand = manager.performStringSubstitution(buildCommand);
+		cmdLine.addAll(Arrays.asList(buildCommand.replace('\n', ' ').split(" ")));
+		Process restoreProcess = DebugPlugin.exec(cmdLine.toArray(new String[cmdLine.size()]), projectLocation);
+		String labelString = "cargo ";
+		if (buildCommand.length() > 20) {
+			labelString += buildCommand.substring(0, 20) + "...";
+		} else {
+			labelString += buildCommand;
+		}
+		IProcess process = DebugPlugin.newProcess(launch, restoreProcess, labelString);
+		process.setAttribute(IProcess.ATTR_CMDLINE, String.join(" ", cmdLine));
+
+		try {
+			restoreProcess.waitFor();
+		} catch (InterruptedException e) {
+		}
+		if (restoreProcess.exitValue() != 0) { // errors will be shown in console
+			return;
+		}
+		super.launch(config, mode, launch, monitor);
+	}
+
+	@Override
+	public void launch(ISelection selection, String mode) {
+
+		if (selection instanceof IStructuredSelection) {
+			Iterator<?> selectionIterator = ((IStructuredSelection) selection).iterator();
+			while (selectionIterator.hasNext()) {
+				Object element = selectionIterator.next();
+				IResource resource = null;
+				if (element instanceof IResource) {
+					resource = (IResource) element;
+				} else if (element instanceof IAdaptable) {
+					resource = ((IAdaptable) element).getAdapter(IResource.class);
+				}
+
+				if (resource != null) {
+					try {
+						ILaunchConfiguration launchConfig = getLaunchConfiguration(mode, resource);
+						if (launchConfig != null) {
+							launchConfig.launch(mode, new NullProgressMonitor());
+						}
+					} catch (CoreException e) {
+						CorrosionPlugin.logError(e);
+					}
+					return;
+				}
+			}
+		}
+		Display.getDefault().asyncExec(() -> {
+			MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Unable to Launch",
+					"Unable to launch Rust Project from selection.");
+		});
+	}
+
+	@Override
+	public void launch(IEditorPart editor, String mode) {
+		IEditorInput input = editor.getEditorInput();
+		IFile file = input.getAdapter(IFile.class);
+
+		try {
+			ILaunchConfiguration launchConfig = getLaunchConfiguration(mode, file);
+			if (launchConfig != null) {
+				launchConfig.launch(mode, new NullProgressMonitor());
+			}
+		} catch (CoreException e) {
+			CorrosionPlugin.logError(e);
+		}
+	}
+
+	@Override
+	protected ISourceLocator getSourceLocator(ILaunchConfiguration configuration, DsfSession session)
+			throws CoreException {
+		SourceLookupDirector locator = new SourceLookupDirector();
+		String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null);
+		if (memento == null) {
+			locator.initializeDefaults(configuration);
+		} else {
+			locator.initializeFromMemento(memento, configuration);
+		}
+		return locator;
+	}
+
+	@Override
+	protected DsfSourceLookupDirector createDsfSourceLocator(ILaunchConfiguration configuration, DsfSession session)
+			throws CoreException {
+		DsfSourceLookupDirector sourceLookupDirector = new DsfSourceLookupDirector(session);
+		sourceLookupDirector.setSourceContainers(
+				((SourceLookupDirector) getSourceLocator(configuration, session)).getSourceContainers());
+		return sourceLookupDirector;
+	}
+
+	@Override
+	public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+		setDefaultProcessFactory(configuration); // Reset process factory to what GdbLaunch expected
+
+		ILaunch launch = super.getLaunch(configuration, mode);
+		// workaround for DLTK bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=419273
+		launch.setAttribute("org.eclipse.dltk.debug.debugConsole", "false");
+		return launch;
+	}
+
+	@Override
+	protected IPath checkBinaryDetails(ILaunchConfiguration config) throws CoreException {
+		return LaunchUtils.verifyProgramPath(config, null);
+	}
+
+	private ILaunchConfiguration getLaunchConfiguration(String mode, IResource resource) {
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		ILaunchConfigurationType configType = launchManager
+				.getLaunchConfigurationType("org.eclipse.corrosion.debug.RustDebugDelegate");
+		try {
+			ILaunchConfiguration[] launchConfigurations = launchManager.getLaunchConfigurations(configType);
+			final IProject project = resource.getProject();
+			final String projectName = project.getName();
+
+			for (ILaunchConfiguration iLaunchConfiguration : launchConfigurations) {
+				if (iLaunchConfiguration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, "")
+						.equals(projectName)) {
+					return iLaunchConfiguration;
+				}
+			}
+			String configName = launchManager.generateLaunchConfigurationName(projectName);
+			ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, configName);
+			wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName);
+			wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
+					project.getLocation().toString() + "/target/debug/" + projectName);
+			wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, project.getLocation().toString());
+			wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false);
+			wc.doSave();
+			return wc;
+		} catch (CoreException e) {
+			CorrosionPlugin.logError(e);
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTab.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTab.java
new file mode 100644
index 0000000..5d81c3c
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTab.java
@@ -0,0 +1,256 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import java.io.File;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.StringVariableSelectionDialog;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.corrosion.CargoProjectTester;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+public class RustDebugTab extends AbstractLaunchConfigurationTab {
+
+	private Text projectText;
+	private Text buildCommandText;
+	private Button defaultExecutablePathButton;
+
+	private Text executablePathText;
+	private Label executableLabel;
+	private Button browseExecutableButton;
+
+	private IProject project;
+	private File executable;
+
+	@Override
+	public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+		configuration.setAttribute(RustDebugDelegate.BUILD_COMMAND_ATTRIBUTE, buildCommandText.getText());
+		configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, projectText.getText());
+		configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, executablePathText.getText());
+		if (project != null) {
+			configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
+					project.getLocation().toString());
+		}
+		setDirty(false);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		Composite container = new Group(parent, SWT.BORDER);
+		setControl(container);
+		GridLayoutFactory.swtDefaults().numColumns(3).applyTo(container);
+		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		Label projectLabel = new Label(container, SWT.NONE);
+		projectLabel.setText("Project:");
+		projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		projectText = new Text(container, SWT.BORDER);
+		projectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		projectText.addModifyListener(e -> {
+			setDirty(true);
+			if (!projectText.getText().isEmpty()) {
+				project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectText.getText());
+			} else {
+				project = null;
+			}
+			if (defaultExecutablePathButton.getSelection()) {
+				executablePathText.setText(getDefaultExecutablePath());
+			}
+			updateLaunchConfigurationDialog();
+		});
+
+		Button browseButton = new Button(container, SWT.NONE);
+		browseButton.setText("Browse...");
+		browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+		browseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			ListSelectionDialog dialog = new ListSelectionDialog(browseButton.getShell(),
+					ResourcesPlugin.getWorkspace().getRoot(), new BaseWorkbenchContentProvider(),
+					new WorkbenchLabelProvider(), "Select the Project:");
+			dialog.setTitle("Project Selection");
+			int returnCode = dialog.open();
+			Object[] results = dialog.getResult();
+			if (returnCode == 0 && results.length > 0) {
+				setDirty(true);
+				projectText.setText(((IProject) results[0]).getName());
+				if (defaultExecutablePathButton.getSelection()) {
+					executablePathText.setText(getDefaultExecutablePath());
+				}
+				updateLaunchConfigurationDialog();
+			}
+		}));
+
+		Group buildCommandGroup = new Group(container, SWT.NONE);
+		buildCommandGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
+		buildCommandGroup.setLayout(new GridLayout(2, false));
+		buildCommandGroup.setText("Build Command");
+
+		buildCommandText = new Text(buildCommandGroup, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);
+		GridData buildCommandGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		buildCommandGridData.heightHint = 100;
+		buildCommandText.setLayoutData(buildCommandGridData);
+		buildCommandText.addModifyListener(e -> {
+			setDirty(true);
+			updateLaunchConfigurationDialog();
+		});
+
+		Button variableButton = new Button(buildCommandGroup, SWT.NONE);
+		variableButton.setText("Variables");
+		variableButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+		variableButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			StringVariableSelectionDialog variableSelector = new StringVariableSelectionDialog(
+					variableButton.getShell());
+			int returnCode = variableSelector.open();
+			String result = variableSelector.getVariableExpression();
+			if (returnCode == 0 && result != null) {
+				buildCommandText.append(result);
+			}
+			setDirty(true);
+			updateLaunchConfigurationDialog();
+		}));
+
+		defaultExecutablePathButton = new Button(container, SWT.CHECK);
+		defaultExecutablePathButton.setText("Use default path to executable");
+		defaultExecutablePathButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 3, 1));
+		defaultExecutablePathButton.addSelectionListener(
+				widgetSelectedAdapter(e -> setDefaultExecutionPath(defaultExecutablePathButton.getSelection())));
+		defaultExecutablePathButton.setSelection(true);
+
+		executableLabel = new Label(container, SWT.NONE);
+		executableLabel.setText("Executable:");
+		executableLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		executablePathText = new Text(container, SWT.BORDER);
+		executablePathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		executablePathText.addModifyListener(e -> {
+			setDirty(true);
+			executable = new File(executablePathText.getText());
+			updateLaunchConfigurationDialog();
+		});
+
+		browseExecutableButton = new Button(container, SWT.NONE);
+		browseExecutableButton.setText("Browse...");
+		browseExecutableButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+		browseExecutableButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			FileDialog dialog = new FileDialog(browseExecutableButton.getShell());
+			String result = dialog.open();
+			if (result != null) {
+				projectText.setText(result);
+				setDirty(true);
+				updateLaunchConfigurationDialog();
+			}
+		}));
+		setDefaultExecutionPath(true);
+	}
+
+	private void setDefaultExecutionPath(boolean state) {
+		defaultExecutablePathButton.setEnabled(state);
+		executableLabel.setEnabled(!state);
+		executablePathText.setEnabled(!state);
+		browseExecutableButton.setEnabled(!state);
+		if (state) {
+			executablePathText.setText(getDefaultExecutablePath());
+		}
+	}
+
+	private String getDefaultExecutablePath() {
+		if (project == null) {
+			return "";
+		} else {
+			return project.getLocation().toString() + "/target/debug/" + project.getName();
+		}
+	}
+
+	@Override
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+		configuration.setAttribute(RustDebugDelegate.BUILD_COMMAND_ATTRIBUTE, "build");
+		configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
+		configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "");
+		configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, "");
+	}
+
+	@Override
+	public void initializeFrom(ILaunchConfiguration configuration) {
+		try {
+			projectText.setText(configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""));
+		} catch (CoreException ce) {
+			projectText.setText("");
+		}
+		try {
+			buildCommandText.setText(configuration.getAttribute(RustDebugDelegate.BUILD_COMMAND_ATTRIBUTE, "build"));
+		} catch (CoreException ce) {
+			buildCommandText.setText("");
+		}
+		try {
+			executablePathText
+					.setText(configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""));
+		} catch (CoreException ce) {
+			executablePathText.setText("");
+		}
+		setDefaultExecutionPath(executablePathText.getText().equals(getDefaultExecutablePath()));
+	}
+
+	@Override
+	public boolean isValid(ILaunchConfiguration launchConfig) {
+		return canSave();
+	}
+
+	private static CargoProjectTester tester = new CargoProjectTester();
+
+	@Override
+	public boolean canSave() {
+		if (buildCommandText.getText().isEmpty()) {
+			setErrorMessage("Cargo Build command cannot be empty");
+			return false;
+		}
+		if (project == null || !project.exists() || !tester.test(project, "isCargoProject", null, null)) {
+			setErrorMessage("Input a valid cargo project name");
+			return false;
+		}
+		if (executable == null || !executable.exists() || !executable.canExecute()) {
+			setErrorMessage("Input a valid project executable path");
+			return false;
+		}
+		if (!executable.canExecute()) {
+			setErrorMessage("Executable File is not executable");
+			return false;
+		}
+		setErrorMessage(null);
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return "Main";
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTabGroup.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTabGroup.java
new file mode 100644
index 0000000..37fb4f4
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/RustDebugTabGroup.java
@@ -0,0 +1,41 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.gdb.internal.ui.launching.LocalApplicationCDebuggerTab;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
+
+public class RustDebugTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+	@Override
+	public void createTabs(ILaunchConfigurationDialog arg0, String arg1) {
+		setTabs(new ILaunchConfigurationTab[] { new RustDebugTab(), new EnvironmentTab(),
+				new RustLocalApplicationCDebuggerTab(), new SourceLookupTab(), new CommonTab() });
+	}
+
+	protected class RustLocalApplicationCDebuggerTab extends LocalApplicationCDebuggerTab {
+
+		@Override
+		public void setDefaults(ILaunchConfigurationWorkingCopy config) {
+			super.setDefaults(config);
+			config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false);
+		}
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/SourceLookupDirector.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/SourceLookupDirector.java
new file mode 100644
index 0000000..d84ee66
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/SourceLookupDirector.java
@@ -0,0 +1,47 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourcePathComputerDelegate;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourcePathComputer;
+import org.eclipse.corrosion.CorrosionPlugin;
+
+public class SourceLookupDirector extends CSourceLookupDirector {
+	@Override
+	public ISourcePathComputer getSourcePathComputer() {
+		ISourcePathComputer computer = super.getSourcePathComputer();
+		if (computer != null) {
+			return computer;
+		}
+		return new ISourcePathComputer() {
+
+			CSourcePathComputerDelegate langSourcePathComputer = new CSourcePathComputerDelegate();
+
+			@Override
+			public ISourceContainer[] computeSourceContainers(ILaunchConfiguration configuration,
+					IProgressMonitor monitor) throws CoreException {
+				return langSourcePathComputer.computeSourceContainers(configuration, monitor);
+			}
+
+			@Override
+			public String getId() {
+				return CorrosionPlugin.PLUGIN_ID + ".SourceLocator";
+			}
+		};
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointAdapter.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointAdapter.java
new file mode 100644
index 0000000..cc82052
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointAdapter.java
@@ -0,0 +1,102 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.debug.core.CDIDebugModel;
+import org.eclipse.cdt.debug.core.model.ICBreakpointType;
+import org.eclipse.cdt.debug.core.model.ICEventBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICFunctionBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICWatchpoint;
+import org.eclipse.cdt.debug.ui.breakpoints.AbstractToggleBreakpointAdapter;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IWorkbenchPart;
+
+public class ToggleBreakpointAdapter extends AbstractToggleBreakpointAdapter {
+	@Override
+	protected ICLineBreakpoint findLineBreakpoint(String sourceHandle, IResource resource, int lineNumber)
+			throws CoreException {
+		return CDIDebugModel.lineBreakpointExists(sourceHandle, resource, lineNumber);
+	}
+
+	@Override
+	protected void createLineBreakpoint(boolean interactive, IWorkbenchPart part, String sourceHandle,
+			IResource resource, int lineNumber) throws CoreException {
+		if (interactive) {
+			ICLineBreakpoint lineBp = CDIDebugModel.createBlankLineBreakpoint();
+			Map<String, Object> attributes = new HashMap<>();
+			CDIDebugModel.setLineBreakpointAttributes(attributes, sourceHandle, getBreakpointType(), lineNumber, true,
+					0, ""); //$NON-NLS-1$
+			openBreakpointPropertiesDialog(lineBp, part, resource, attributes);
+		} else {
+			CDIDebugModel.createLineBreakpoint(sourceHandle, resource, getBreakpointType(), lineNumber, true, 0, "", //$NON-NLS-1$
+					true);
+		}
+	}
+
+	@Override
+	protected ICFunctionBreakpoint findFunctionBreakpoint(String sourceHandle, IResource resource, String functionName)
+			throws CoreException {
+		return CDIDebugModel.functionBreakpointExists(sourceHandle, resource, functionName);
+	}
+
+	@Override
+	protected void createFunctionBreakpoint(boolean interactive, IWorkbenchPart part, String sourceHandle,
+			IResource resource, String functionName, int charStart, int charEnd, int lineNumber) throws CoreException {
+		if (interactive) {
+			ICFunctionBreakpoint bp = CDIDebugModel.createBlankFunctionBreakpoint();
+			Map<String, Object> attributes = new HashMap<>();
+			CDIDebugModel.setFunctionBreakpointAttributes(attributes, sourceHandle, getBreakpointType(), functionName,
+					charStart, charEnd, lineNumber, true, 0, ""); //$NON-NLS-1$
+			openBreakpointPropertiesDialog(bp, part, resource, attributes);
+		} else {
+			CDIDebugModel.createFunctionBreakpoint(sourceHandle, resource, getBreakpointType(), functionName, charStart,
+					charEnd, lineNumber, true, 0, "", true); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	protected ICWatchpoint findWatchpoint(String sourceHandle, IResource resource, String expression)
+			throws CoreException {
+		return CDIDebugModel.watchpointExists(sourceHandle, resource, expression);
+	}
+
+	@Override
+	protected void createWatchpoint(boolean interactive, IWorkbenchPart part, String sourceHandle, IResource resource,
+			int charStart, int charEnd, int lineNumber, String expression, String memorySpace, String range)
+			throws CoreException {
+		ICWatchpoint bp = CDIDebugModel.createBlankWatchpoint();
+		Map<String, Object> attributes = new HashMap<>();
+		CDIDebugModel.setWatchPointAttributes(attributes, sourceHandle, resource, true, false, expression, memorySpace,
+				new BigInteger(range), true, 0, ""); //$NON-NLS-1$
+		openBreakpointPropertiesDialog(bp, part, resource, attributes);
+	}
+
+	@Override
+	protected void createEventBreakpoint(boolean interactive, IWorkbenchPart part, IResource resource, String type,
+			String arg) throws CoreException {
+		ICEventBreakpoint bp = CDIDebugModel.createBlankEventBreakpoint();
+		Map<String, Object> attributes = new HashMap<>();
+		CDIDebugModel.setEventBreakpointAttributes(attributes, type, arg);
+		openBreakpointPropertiesDialog(bp, part, resource, attributes);
+	}
+
+	protected int getBreakpointType() {
+		return ICBreakpointType.REGULAR;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointsTargetFactory.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointsTargetFactory.java
new file mode 100644
index 0000000..4973958
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/debug/ToggleBreakpointsTargetFactory.java
@@ -0,0 +1,69 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.debug;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetFactory;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public class ToggleBreakpointsTargetFactory implements IToggleBreakpointsTargetFactory {
+	public static final String FACTORY_ID = CorrosionPlugin.PLUGIN_ID + "BreakpointFactory";
+
+	public ToggleBreakpointsTargetFactory() {
+	}
+
+	@Override
+	public Set<String> getToggleTargets(IWorkbenchPart part, ISelection selection) {
+		return isRustPart(part) ? Collections.singleton(FACTORY_ID) : Collections.emptySet();
+	}
+
+	@Override
+	public String getDefaultToggleTarget(IWorkbenchPart part, ISelection selection) {
+		return isRustPart(part) ? FACTORY_ID : null;
+	}
+	
+	private boolean isRustPart(IWorkbenchPart part) {
+		if (part instanceof ITextEditor) {
+			IEditorInput editorInput = ((ITextEditor) part).getEditorInput();
+			return editorInput instanceof FileEditorInput && "rs".equals(((FileEditorInput) editorInput).getPath().getFileExtension());
+		}
+		return false;
+	}
+
+	@Override
+	public IToggleBreakpointsTarget createToggleTarget(String targetID) {
+		if (FACTORY_ID.equals(targetID)) {
+			return new ToggleBreakpointAdapter();
+		}
+		return null;
+	}
+
+	@Override
+	public String getToggleTargetName(String targetID) {
+		return "Breakpoint";
+	}
+
+	@Override
+	public String getToggleTargetDescription(String targetID) {
+		return "Breakpoint for native Rust code.";
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/Implementations.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/Implementations.java
new file mode 100644
index 0000000..08abc4d
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/Implementations.java
@@ -0,0 +1,84 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.extensions;
+
+import java.util.Collection;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.lsp4e.LSPEclipseUtils;
+import org.eclipse.lsp4e.LanguageServerPlugin;
+import org.eclipse.lsp4e.LanguageServiceAccessor;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.search.ui.NewSearchUI;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.texteditor.AbstractTextEditor;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+@SuppressWarnings("restriction")
+public class Implementations extends AbstractHandler implements IHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IEditorPart part = HandlerUtil.getActiveEditor(event);
+		if (part instanceof ITextEditor) {
+			Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
+					LSPEclipseUtils.getDocument((ITextEditor) part),
+					capabilities -> Boolean.TRUE.equals(capabilities.getReferencesProvider()));
+			if (!infos.isEmpty()) {
+				// TODO consider better way to choose the actual LS to use
+				LSPDocumentInfo info = infos.iterator().next();
+				ISelection sel = ((AbstractTextEditor) part).getSelectionProvider().getSelection();
+
+				if (sel instanceof TextSelection) {
+					try {
+						int offset = ((TextSelection) sel).getOffset();
+						ImplementationsSearchQuery query = new ImplementationsSearchQuery(offset, info);
+						NewSearchUI.runQueryInBackground(query);
+					} catch (BadLocationException e) {
+						LanguageServerPlugin.logError(e);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		IWorkbenchPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
+		if (part instanceof ITextEditor) {
+			Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
+					LSPEclipseUtils.getDocument((ITextEditor) part),
+					capabilities -> Boolean.TRUE.equals(capabilities.getReferencesProvider()));
+			ISelection selection = ((ITextEditor) part).getSelectionProvider().getSelection();
+			return !infos.isEmpty() && !selection.isEmpty() && selection instanceof ITextSelection;
+		}
+		return false;
+	}
+
+	@Override
+	public boolean isHandled() {
+		return true;
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/ImplementationsSearchQuery.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/ImplementationsSearchQuery.java
new file mode 100644
index 0000000..83a1b5e
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/extensions/ImplementationsSearchQuery.java
@@ -0,0 +1,163 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.extensions;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.lsp4e.LSPEclipseUtils;
+import org.eclipse.lsp4e.LanguageServerPlugin;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.lsp4j.Location;
+import org.eclipse.lsp4j.Position;
+import org.eclipse.lsp4j.ReferenceContext;
+import org.eclipse.lsp4j.ReferenceParams;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.corrosion.RLSServerInterface;
+import org.eclipse.search.internal.ui.text.FileMatch;
+import org.eclipse.search.internal.ui.text.FileSearchQuery;
+import org.eclipse.search.internal.ui.text.FileSearchResult;
+import org.eclipse.search.internal.ui.text.LineElement;
+import org.eclipse.search.ui.ISearchResult;
+import org.eclipse.search.ui.text.AbstractTextSearchResult;
+import org.eclipse.search.ui.text.Match;
+
+//TODO: investigate implementation without high reliance on restrictions
+@SuppressWarnings("restriction")
+public class ImplementationsSearchQuery extends FileSearchQuery {
+
+	private final Position position;
+	private final LSPDocumentInfo info;
+	private final String filename;
+
+	private FileSearchResult result;
+
+	private long startTime;
+
+	private CompletableFuture<List<? extends Location>> references;
+
+	public ImplementationsSearchQuery(int offset, LSPDocumentInfo info) throws BadLocationException {
+		super("", false, false, null); //$NON-NLS-1$
+		this.position = LSPEclipseUtils.toPosition(offset, info.getDocument());
+		this.info = info;
+		IResource resource = LSPEclipseUtils.findResourceFor(info.getFileUri().toString());
+		this.filename = resource != null ? resource.getName() : info.getFileUri().toString();
+	}
+
+	@Override
+	public IStatus run(IProgressMonitor monitor) throws OperationCanceledException {
+		startTime = System.currentTimeMillis();
+		// Cancel last references future if needed.
+		if (references != null) {
+			references.cancel(true);
+		}
+		AbstractTextSearchResult textResult = (AbstractTextSearchResult) getSearchResult();
+		textResult.removeAll();
+
+		try {
+			// Execute LSP "references" service
+			ReferenceParams params = new ReferenceParams();
+			params.setContext(new ReferenceContext(true));
+			params.setTextDocument(new TextDocumentIdentifier(info.getFileUri().toString()));
+			params.setPosition(position);
+			info.getInitializedLanguageClient()
+					.thenCompose(languageServer -> ((RLSServerInterface) languageServer).implementations(params))
+					.thenAccept(locs -> {
+						// Loop for each LSP Location and convert it to Match search.
+						for (Location loc : locs) {
+							Match match = toMatch(loc);
+							result.addMatch(match);
+						}
+					});
+			return Status.OK_STATUS;
+		} catch (Exception ex) {
+			return new Status(IStatus.ERROR, LanguageServerPlugin.getDefault().getBundle().getSymbolicName(),
+					ex.getMessage(), ex);
+		}
+	}
+
+	/**
+	 * Convert the given LSP {@link Location} to Eclipse search {@link Match}.
+	 *
+	 * @param location
+	 *            the LSP location to convert.
+	 * @return the converted Eclipse search {@link Match}.
+	 */
+	private static Match toMatch(Location location) {
+		try {
+			IResource resource = LSPEclipseUtils.findResourceFor(location.getUri());
+			IDocument document = LSPEclipseUtils.getDocument(resource);
+			if (document != null) {
+				int startOffset = LSPEclipseUtils.toOffset(location.getRange().getStart(), document);
+				int endOffset = LSPEclipseUtils.toOffset(location.getRange().getEnd(), document);
+
+				IRegion lineInformation = document.getLineInformationOfOffset(startOffset);
+				LineElement lineEntry = new LineElement(resource, document.getLineOfOffset(startOffset),
+						lineInformation.getOffset(),
+						document.get(lineInformation.getOffset(), lineInformation.getLength()));
+				return new FileMatch((IFile) resource, startOffset, endOffset - startOffset, lineEntry);
+
+			}
+			Position startPosition = location.getRange().getStart();
+			LineElement lineEntry = new LineElement(resource, startPosition.getLine(), 0,
+					String.format("%s:%s", startPosition.getLine(), startPosition.getCharacter())); //$NON-NLS-1$
+			return new FileMatch((IFile) resource, 0, 0, lineEntry);
+		} catch (BadLocationException ex) {
+			LanguageServerPlugin.logError(ex);
+		}
+		return null;
+	}
+
+	@Override
+	public ISearchResult getSearchResult() {
+		if (result == null) {
+			result = new FileSearchResult(this);
+		}
+		return result;
+	}
+
+	@Override
+	public String getLabel() {
+		return "Implementations";
+	}
+
+	@Override
+	public String getResultLabel(int nMatches) {
+		long time = 0;
+		if (startTime > 0) {
+			time = System.currentTimeMillis() - startTime;
+		}
+		if (nMatches == 1) {
+			return NLS.bind("''{0}'' at [{1}:{2}] - 1 reference in {3}ms",
+					new Object[] { filename, position.getLine() + 1, position.getCharacter() + 1, time });
+		}
+		return NLS.bind("''{0}'' at [{1}:{2}] - {3} references in {4}ms",
+				new Object[] { filename, position.getLine() + 1, position.getCharacter() + 1, nMatches, time });
+	}
+
+	@Override
+	public boolean isFileNameSearch() {
+		// Return false to display lines where references are found
+		return false;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunDelegate.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunDelegate.java
new file mode 100644
index 0000000..3ab43ee
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunDelegate.java
@@ -0,0 +1,182 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.run;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.variables.IStringVariableManager;
+import org.eclipse.core.variables.VariablesPlugin;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.eclipse.debug.ui.ILaunchShortcut;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+
+public class CargoRunDelegate extends LaunchConfigurationDelegate implements ILaunchShortcut {
+
+	public static final String PROJECT_ATTRIBUTE = "PROJECT";
+	public static final String RUN_COMMAND_ATTRIBUTE = "RUN_COMMAND";
+
+	@Override
+	public void launch(ISelection selection, String mode) {
+
+		if (selection instanceof IStructuredSelection) {
+			Iterator<?> selectionIterator = ((IStructuredSelection) selection).iterator();
+			while (selectionIterator.hasNext()) {
+				Object element = selectionIterator.next();
+				IResource resource = null;
+				if (element instanceof IResource) {
+					resource = (IResource) element;
+				} else if (element instanceof IAdaptable) {
+					resource = ((IAdaptable) element).getAdapter(IResource.class);
+				}
+
+				if (resource != null) {
+					try {
+						ILaunchConfiguration launchConfig = getLaunchConfiguration(mode, resource);
+						if (launchConfig != null) {
+							launchConfig.launch(mode, new NullProgressMonitor());
+						}
+					} catch (CoreException e) {
+						CorrosionPlugin.logError(e);
+					}
+					return;
+				}
+			}
+		}
+		Display.getDefault().asyncExec(() -> {
+			MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Unable to Launch",
+					"Unable to launch Rust Project from selection.");
+		});
+	}
+
+	@Override
+	public void launch(IEditorPart editor, String mode) {
+		IEditorInput input = editor.getEditorInput();
+		IFile file = input.getAdapter(IFile.class);
+
+		try {
+			ILaunchConfiguration launchConfig = getLaunchConfiguration(mode, file);
+			if (launchConfig != null) {
+				launchConfig.launch(mode, new NullProgressMonitor());
+			}
+		} catch (CoreException e) {
+			CorrosionPlugin.logError(e);
+		}
+	}
+
+	@Override
+	public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
+			throws CoreException {
+		List<String> cargoRunCommand = new ArrayList<>();
+		IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+		String cargo = store.getString(CorrosionPreferenceInitializer.cargoPathPreference);
+		cargoRunCommand.add(cargo);
+		String projectName = configuration.getAttribute(PROJECT_ATTRIBUTE, "");
+		String runCommand = configuration.getAttribute(RUN_COMMAND_ATTRIBUTE, "");
+
+		IProject project = null;
+		if (!projectName.isEmpty()) {
+			project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+		}
+		if (project == null || !project.exists()) {
+			Display.getDefault().asyncExec(() -> {
+				MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+						"Unable to Launch", "Unable to find project.");
+			});
+			return;
+		}
+		IFile cargoManifest = project.getFile("Cargo.toml");
+		if (!cargoManifest.exists()) {
+			Display.getDefault().asyncExec(() -> {
+				MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+						"Unable to Launch", "Unable to find Cargo.toml file.");
+			});
+			return;
+		}
+		if (runCommand.isEmpty()) {
+			runCommand = "run";
+		}
+		IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
+		runCommand = manager.performStringSubstitution(runCommand);
+		cargoRunCommand.addAll(Arrays.asList(runCommand.replace('\n', ' ').split("(\n| )")));
+
+		final String cargoPathString = cargoManifest.getLocation().toPortableString();
+		cargoRunCommand.add("--manifest-path");
+		cargoRunCommand.add(cargoPathString);
+
+		final List<String> finalRunCommand = cargoRunCommand;
+		CompletableFuture.runAsync(() -> {
+			try {
+				String[] cmdLine = finalRunCommand.toArray(new String[finalRunCommand.size()]);
+				Process p = DebugPlugin.exec(cmdLine, null);
+				IProcess process = DebugPlugin.newProcess(launch, p, "cargo run");
+				process.setAttribute(IProcess.ATTR_CMDLINE, String.join(" ", cmdLine));
+			} catch (CoreException e) {
+				Display.getDefault().asyncExec(() -> {
+					MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+							"Unable to Launch", e.getLocalizedMessage());
+				});
+			}
+		});
+	}
+
+	private ILaunchConfiguration getLaunchConfiguration(String mode, IResource resource) {
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		ILaunchConfigurationType configType = launchManager
+				.getLaunchConfigurationType("org.eclipse.corrosion.run.CargoRunDelegate");
+		try {
+			ILaunchConfiguration[] launchConfigurations = launchManager.getLaunchConfigurations(configType);
+			final String projectName = resource.getProject().getName();
+
+			for (ILaunchConfiguration iLaunchConfiguration : launchConfigurations) {
+				if (iLaunchConfiguration.getAttribute("PROJECT", "").equals(projectName)) {
+					return iLaunchConfiguration;
+				}
+			}
+			String configName = launchManager.generateLaunchConfigurationName(projectName);
+			ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, configName);
+			wc.setAttribute("PROJECT", projectName);
+			return wc;
+		} catch (CoreException e) {
+			CorrosionPlugin.logError(e);
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTab.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTab.java
new file mode 100644
index 0000000..c87d702
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTab.java
@@ -0,0 +1,163 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen   (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.run;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.StringVariableSelectionDialog;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.corrosion.CargoProjectTester;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+public class CargoRunTab extends AbstractLaunchConfigurationTab {
+
+	private Text projectText;
+	private Text runCommandText;
+
+	private IProject project;
+
+	@Override
+	public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+		configuration.setAttribute(CargoRunDelegate.PROJECT_ATTRIBUTE, projectText.getText());
+		configuration.setAttribute(CargoRunDelegate.RUN_COMMAND_ATTRIBUTE, runCommandText.getText());
+		setDirty(false);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		Composite container = new Group(parent, SWT.BORDER);
+		setControl(container);
+		GridLayoutFactory.swtDefaults().numColumns(3).applyTo(container);
+		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		Label projectLabel = new Label(container, SWT.NONE);
+		projectLabel.setText("Project:");
+		projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		projectText = new Text(container, SWT.BORDER);
+		projectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		projectText.addModifyListener(e -> {
+			setDirty(true);
+			if (!projectText.getText().isEmpty()) {
+				project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectText.getText());
+			} else {
+				project = null;
+			}
+			updateLaunchConfigurationDialog();
+		});
+
+		Button browseButton = new Button(container, SWT.NONE);
+		browseButton.setText("Browse...");
+		browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+		browseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			ListSelectionDialog dialog = new ListSelectionDialog(browseButton.getShell(),
+					ResourcesPlugin.getWorkspace().getRoot(), new BaseWorkbenchContentProvider(),
+					new WorkbenchLabelProvider(), "Select the Project:");
+			dialog.setTitle("Project Selection");
+			int returnCode = dialog.open();
+			Object[] results = dialog.getResult();
+			if (returnCode == 0 && results.length > 0) {
+				projectText.setText(((IProject) results[0]).getName());
+				setDirty(true);
+				updateLaunchConfigurationDialog();
+			}
+		}));
+
+		Group runCommandGroup = new Group(container, SWT.NONE);
+		runCommandGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1));
+		runCommandGroup.setLayout(new GridLayout(2, false));
+		runCommandGroup.setText("Run Command");
+
+		runCommandText = new Text(runCommandGroup, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);
+		GridData buildCommandGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		buildCommandGridData.heightHint = 100;
+		runCommandText.setLayoutData(buildCommandGridData);
+		runCommandText.addModifyListener(e -> {
+			setDirty(true);
+			updateLaunchConfigurationDialog();
+		});
+
+		Button variableButton = new Button(runCommandGroup, SWT.NONE);
+		variableButton.setText("Variables");
+		variableButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
+		variableButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			StringVariableSelectionDialog variableSelector = new StringVariableSelectionDialog(
+					variableButton.getShell());
+			int returnCode = variableSelector.open();
+			String result = variableSelector.getVariableExpression();
+			if (returnCode == 0 && result != null) {
+				runCommandText.append(result);
+			}
+			setDirty(true);
+			updateLaunchConfigurationDialog();
+		}));
+	}
+
+	@Override
+	public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+		configuration.setAttribute(CargoRunDelegate.PROJECT_ATTRIBUTE, "");
+		configuration.setAttribute(CargoRunDelegate.RUN_COMMAND_ATTRIBUTE, "run");
+	}
+
+	@Override
+	public void initializeFrom(ILaunchConfiguration configuration) {
+		try {
+			projectText.setText(configuration.getAttribute(CargoRunDelegate.PROJECT_ATTRIBUTE, ""));
+		} catch (CoreException ce) {
+			projectText.setText("");
+		}
+		try {
+			runCommandText.setText(configuration.getAttribute(CargoRunDelegate.RUN_COMMAND_ATTRIBUTE, "run"));
+		} catch (CoreException ce) {
+			runCommandText.setText("");
+		}
+	}
+
+	@Override
+	public boolean isValid(ILaunchConfiguration launchConfig) {
+		return canSave();
+	}
+
+	private static CargoProjectTester tester = new CargoProjectTester();
+
+	@Override
+	public boolean canSave() {
+		if (project != null && project.exists() && tester.test(project, "isCargoProject", null, null)) {
+			setErrorMessage(null);
+			return true;
+		}
+		setErrorMessage("Input a valid cargo project name");
+		return false;
+	}
+
+	@Override
+	public String getName() {
+		return "Main";
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTabGroup.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTabGroup.java
new file mode 100644
index 0000000..2e08e4e
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/run/CargoRunTabGroup.java
@@ -0,0 +1,27 @@
+/*********************************************************************
+ * Copyright (c) 2017 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.run;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+
+public class CargoRunTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+	@Override
+	public void createTabs(ILaunchConfigurationDialog arg0, String arg1) {
+		setTabs(new ILaunchConfigurationTab[] { new CargoRunTab(), new EnvironmentTab(), new CommonTab() });
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/Snippet.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/Snippet.java
new file mode 100644
index 0000000..99ce896
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/Snippet.java
@@ -0,0 +1,83 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.snippet;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.lsp4e.operations.completion.LSCompletionProposal;
+import org.eclipse.lsp4j.CompletionItem;
+import org.eclipse.lsp4j.CompletionItemKind;
+import org.eclipse.lsp4j.InsertTextFormat;
+import org.eclipse.lsp4j.Position;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.TextEdit;
+
+@SuppressWarnings("restriction")
+public class Snippet {
+	private String[] replacementLines;
+	private String display;
+	private CompletionItemKind kind;
+
+	public Snippet(String display, CompletionItemKind kind, String[] replacementLines) {
+		this.replacementLines = replacementLines;
+		this.display = display;
+		this.kind = kind;
+	}
+
+	public ICompletionProposal convertToCompletionProposal(int offset, LSPDocumentInfo info, String prefix,
+			String lineIndentation) {
+		CompletionItem item = new CompletionItem();
+		item.setLabel(display);
+		item.setKind(kind);
+		item.setInsertTextFormat(InsertTextFormat.Snippet);
+
+		Range r = null;
+		try {
+			int line = info.getDocument().getLineOfOffset(offset);
+			int lineOffset = offset - info.getDocument().getLineOffset(line);
+			r = new Range(new Position(line, lineOffset - prefix.length()), new Position(line, lineOffset));
+		} catch (BadLocationException e) {
+			// Caught by null return
+		}
+		if (r == null) {
+			return null;
+		}
+		item.setTextEdit(new TextEdit(r, createReplacement(lineIndentation)));
+		return new LSCompletionProposal(item, offset, info);
+	}
+
+	public boolean matchesPrefix(String prefix) {
+		// TODO: expand matching if not extensive enough
+		return this.display.startsWith(prefix);
+	}
+
+	private String createReplacement(String lineIndentation) {
+		StringBuilder responseBuilder = new StringBuilder();
+
+		if (replacementLines.length == 1) {
+			return replacementLines[0];
+		} else if (replacementLines.length > 1) {
+			for (String line : replacementLines) {
+				if (responseBuilder.length() == 0) {
+					responseBuilder.append(line);
+					continue;
+				}
+				responseBuilder.append('\n');
+				responseBuilder.append(lineIndentation);
+				responseBuilder.append(line);
+			}
+		}
+		return responseBuilder.toString();
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/SnippetContentAssistProcessor.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/SnippetContentAssistProcessor.java
new file mode 100644
index 0000000..68fb6c2
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/snippet/SnippetContentAssistProcessor.java
@@ -0,0 +1,132 @@
+/*********************************************************************
+ * Copyright (c) 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.snippet;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+import org.eclipse.lsp4e.LanguageServiceAccessor;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.lsp4j.CompletionItemKind;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+@SuppressWarnings("restriction")
+public class SnippetContentAssistProcessor implements IContentAssistProcessor {
+
+	private static final String ENDS_WITH_WORD = "(?<indent>\\s*).*?(?<prefix>\\w*)";
+	private static final Pattern ENDS_WITH_WORD_PATTERN = Pattern.compile(ENDS_WITH_WORD);
+	private static final List<Snippet> snippets = new ArrayList<>();
+	static {
+		JsonArray snippetArray = null;
+		JsonParser parser = new JsonParser();
+		try {
+			URL url = FileLocator.toFileURL(FileLocator.find(Platform.getBundle("org.eclipse.corrosion"),
+					Path.fromPortableString("snippets/rust.json"), Collections.emptyMap()));
+			StringBuilder snippetsBuilder = new StringBuilder();
+			Files.readAllLines(new File(url.getFile()).toPath()).forEach(line -> snippetsBuilder.append(line));
+			snippetArray = parser.parse(snippetsBuilder.toString()).getAsJsonArray();
+		} catch (IOException e) {
+			// Caught with null snippetArray
+		}
+
+		if (snippetArray != null) {
+			for (JsonElement jsonElement : snippetArray) {
+				JsonObject snippet = jsonElement.getAsJsonObject();
+
+				String name = snippet.get("display").getAsString();
+				int completionItemKind = snippet.get("completionItemKind").getAsInt();
+
+				JsonArray replacementLines = snippet.get("replacementLines").getAsJsonArray();
+				String[] lines = new String[replacementLines.size()];
+				for (int i = 0; i < replacementLines.size(); i++) {
+					lines[i] = replacementLines.get(i).getAsString();
+				}
+
+				addSnippet(new Snippet(name, CompletionItemKind.forValue(completionItemKind), lines));
+			}
+		}
+	}
+
+	private static void addSnippet(Snippet snippet) {
+		snippets.add(snippet);
+	}
+
+	@Override
+	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+		IDocument document = viewer.getDocument();
+		String textToOffset = document.get().substring(0, offset);
+
+		Matcher matcher = ENDS_WITH_WORD_PATTERN.matcher(textToOffset.substring(textToOffset.lastIndexOf('\n') + 1));
+		matcher.matches();
+		String indent = matcher.group("indent");
+		String prefix = matcher.group("prefix");
+
+		Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(document,
+				capabilities -> Boolean.TRUE.equals(capabilities.getReferencesProvider()));
+
+		List<ICompletionProposal> proposals = new ArrayList<>();
+		for (Snippet snippet : snippets) {
+			if (snippet.matchesPrefix(prefix)) {
+				proposals.add(snippet.convertToCompletionProposal(offset, infos.iterator().next(), prefix, indent));
+			}
+		}
+		return proposals.toArray(new ICompletionProposal[proposals.size()]);
+	}
+
+	@Override
+	public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
+		return null;
+	}
+
+	@Override
+	public char[] getCompletionProposalAutoActivationCharacters() {
+		return null;
+	}
+
+	@Override
+	public char[] getContextInformationAutoActivationCharacters() {
+		return null;
+	}
+
+	@Override
+	public String getErrorMessage() {
+		return null;
+	}
+
+	@Override
+	public IContextInformationValidator getContextInformationValidator() {
+		return null;
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizard.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizard.java
new file mode 100644
index 0000000..5dbc3d2
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizard.java
@@ -0,0 +1,143 @@
+/*********************************************************************
+ * Copyright (c) 2017,2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.wizards.export;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ICoreRunnable;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.Launch;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IExportWizard;
+import org.eclipse.ui.IWorkbench;
+
+public class CargoExportWizard extends Wizard implements IExportWizard {
+	private CargoExportWizardPage wizardPage;
+
+	public CargoExportWizard() {
+		super();
+		setNeedsProgressMonitor(true);
+	}
+
+	@Override
+	public void init(IWorkbench workbench, IStructuredSelection selection) {
+		setWindowTitle("Package Cargo Based Rust Project");
+
+		Iterator<?> selectionIterator = selection.iterator();
+		IProject project = null;
+
+		while (selectionIterator.hasNext() && project == null) {
+			IResource resource = (IResource) selectionIterator.next();
+			if (resource.getProject().getFile("Cargo.toml").exists()) {
+				project = resource.getProject();
+			}
+		}
+		wizardPage = new CargoExportWizardPage(project);
+	}
+
+	@Override
+	public void addPages() {
+		addPage(wizardPage);
+	}
+
+	@Override
+	public boolean performFinish() {
+		IProject project = wizardPage.getProject();
+		String toolchain = wizardPage.getToolchain();
+		Boolean noVerify = wizardPage.noVerify();
+		Boolean noMetadata = wizardPage.noMetadata();
+		Boolean allowDirty = wizardPage.allowDirty();
+
+		IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+		String cargo = store.getString(CorrosionPreferenceInitializer.cargoPathPreference);
+
+		List<String> exportCommandList = new ArrayList<>();
+		exportCommandList.add(cargo);
+		exportCommandList.add("package");
+		if (noVerify) {
+			exportCommandList.add("--no-verify");
+		}
+		if (noMetadata) {
+			exportCommandList.add("--no-metadata");
+		}
+		if (allowDirty) {
+			exportCommandList.add("--allow-dirty");
+		}
+		if (!toolchain.isEmpty()) {
+			exportCommandList.add("--target");
+			exportCommandList.add(toolchain);
+		}
+		exportCommandList.add("--manifest-path");
+		exportCommandList.add(project.getFile("Cargo.toml").getLocation().toString());
+
+		Job.create("Cargo Package", (ICoreRunnable) monitor -> {
+			try {
+				ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+				ILaunch newLaunch = new Launch(null, ILaunchManager.RUN_MODE, null);
+
+				Process packageProcess = DebugPlugin
+						.exec(exportCommandList.toArray(new String[exportCommandList.size()]), null);
+				DebugPlugin.newProcess(newLaunch, packageProcess, "cargo package");
+				launchManager.addLaunch(newLaunch);
+
+				try {
+					packageProcess.waitFor();
+				} catch (InterruptedException e) { // errors will be shown in console
+				}
+				if (packageProcess.exitValue() == 0) {
+					project.refreshLocal(IResource.DEPTH_INFINITE, null);
+				} else {
+					String errorOutput = "";
+					try (BufferedReader in = new BufferedReader(
+							new InputStreamReader(packageProcess.getErrorStream()))) {
+						String errorLine;
+						while ((errorLine = in.readLine()) != null) {
+							errorOutput += errorLine + "\n";
+						}
+					} catch (IOException e) {
+						errorOutput = "Unable to generate error log.";
+					}
+					final String finalErrorOutput = errorOutput;
+					Display.getDefault().asyncExec(() -> {
+						MessageDialog.openError(getShell(), "Cannot Create Rust Project", "Create unsuccessful.`"
+								+ String.join(" ", exportCommandList) + "` error log:\n\n" + finalErrorOutput);
+					});
+				}
+
+			} catch (CoreException e) {
+				Display.getDefault().asyncExec(() -> {
+					MessageDialog.openError(getShell(), "Cannot Package Cargo Based Rust Project",
+							"The '" + String.join(" ", exportCommandList) + "' command failed: " + e);
+				});
+			}
+		}).schedule();
+		return true;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizardPage.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizardPage.java
new file mode 100644
index 0000000..923f131
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/export/CargoExportWizardPage.java
@@ -0,0 +1,198 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.wizards.export;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import java.io.File;
+import java.net.URL;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.corrosion.CargoProjectTester;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.corrosion.RustManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.model.BaseWorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+public class CargoExportWizardPage extends WizardPage {
+	private IProject project;
+
+	private Text projectText;
+	private Label outputLocationLabel;
+	private ControlDecoration projectControlDecoration;
+	private Combo toolchainCombo;
+	private Button allowDirtyCheckbox;
+	private Button noVerifyCheckbox;
+	private Button noMetadataCheckbox;
+
+	public IProject getProject() {
+		return project;
+	}
+
+	public String getToolchain() {
+		int toolchainIndex = toolchainCombo.getSelectionIndex();
+		if (toolchainIndex != 0) {
+			return toolchainCombo.getItem(toolchainIndex);
+		}
+		return "";
+	}
+
+	public Boolean noVerify() {
+		return noVerifyCheckbox.getSelection();
+	}
+
+	public Boolean noMetadata() {
+		return noMetadataCheckbox.getSelection();
+	}
+
+	public Boolean allowDirty() {
+		return allowDirtyCheckbox.getSelection();
+	}
+
+	protected CargoExportWizardPage(IProject project) {
+		super(CargoExportWizardPage.class.getName());
+		setTitle("Package Cargo Based Rust Project");
+		setDescription("Package a Cargo based Rust project into a crate, using the `cargo package` command");
+		Bundle bundle = FrameworkUtil.getBundle(this.getClass());
+		URL url = bundle.getEntry("images/cargo.png");
+		ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url);
+		setImageDescriptor(imageDescriptor);
+
+		if (project != null) {
+			this.project = project;
+		}
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		Image errorImage = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)
+				.getImage();
+
+		Composite container = new Composite(parent, SWT.BORDER);
+		setControl(container);
+		GridLayoutFactory.swtDefaults().numColumns(3).applyTo(container);
+		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		Label projectLabelLabel = new Label(container, SWT.NONE);
+		projectLabelLabel.setText("Project:");
+		projectLabelLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+
+		projectText = new Text(container, SWT.BORDER);
+		projectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		if (project != null) {
+			projectText.setText(project.getName());
+		}
+		projectText.addModifyListener(e -> {
+			if (!projectText.getText().isEmpty()) {
+				project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectText.getText());
+			} else {
+				project = null;
+			}
+			setPageComplete(isPageComplete());
+		});
+		projectControlDecoration = new ControlDecoration(projectText, SWT.TOP | SWT.LEFT);
+		projectControlDecoration.setImage(errorImage);
+
+		Button browseButton = new Button(container, SWT.NONE);
+		browseButton.setText("Browse...");
+		browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+		browseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			ListSelectionDialog dialog = new ListSelectionDialog(browseButton.getShell(),
+					ResourcesPlugin.getWorkspace().getRoot(), new BaseWorkbenchContentProvider(),
+					new WorkbenchLabelProvider(), "Select the Project:");
+			dialog.setTitle("Project Selection");
+			int returnCode = dialog.open();
+			Object[] results = dialog.getResult();
+			if (returnCode == 0 && results.length > 0) {
+				project = (IProject) results[0];
+				projectText.setText(project.getName());
+			}
+		}));
+
+		new Label(container, SWT.NONE);
+		outputLocationLabel = new Label(container, SWT.NONE);
+		outputLocationLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+		Label toolchainLabel = new Label(container, SWT.NONE);
+		toolchainLabel.setText("Toolchain:");
+		toolchainLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+		toolchainCombo = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY);
+		toolchainCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+		String defaultString = "Default";
+		final String defaultToolchain = RustManager.getDefaultToolchain();
+		if (!defaultToolchain.isEmpty()) {
+			defaultString += "(Currently " + defaultToolchain + ")";
+		}
+		toolchainCombo.add(defaultString);
+		toolchainCombo.select(0);
+		for (String toolchain : RustManager.getToolchains()) {
+			toolchainCombo.add(toolchain);
+		}
+		new Label(container, SWT.NONE);
+
+		noVerifyCheckbox = new Button(container, SWT.CHECK);
+		noVerifyCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+		noVerifyCheckbox.setText("Don't verify the contents by building them");
+
+		noMetadataCheckbox = new Button(container, SWT.CHECK);
+		noMetadataCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+		noMetadataCheckbox.setText("Ignore warnings about a lack of human-usable metadata");
+
+		allowDirtyCheckbox = new Button(container, SWT.CHECK);
+		allowDirtyCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+		allowDirtyCheckbox.setText("Allow dirty working directories to be packaged");
+		setPageComplete(isPageComplete());
+	}
+
+	private IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+	private static CargoProjectTester tester = new CargoProjectTester();
+
+	@Override
+	public boolean isPageComplete() {
+		File cargo = new File(store.getString(CorrosionPreferenceInitializer.cargoPathPreference));
+		if (!(cargo.exists() && cargo.isFile() && cargo.canExecute())) {
+			setErrorMessage("Cargo command not found. Fix path in the Rust Preferences Page.");
+			return false;
+		}
+		if (!(project != null && project.exists() && tester.test(project, "isCargoProject", null, null))) {
+			setErrorMessage("Please specify a valid cargo project");
+			outputLocationLabel.setText("");
+			projectControlDecoration.show();
+			return false;
+		}
+		outputLocationLabel.setText("Crate will be created in: " + project.getName() + "/target/package/");
+		projectControlDecoration.hide();
+		setErrorMessage(null);
+		return true;
+	}
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizard.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizard.java
new file mode 100644
index 0000000..c96551c
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizard.java
@@ -0,0 +1,287 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.wizards.newCargo;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.resources.ICommand;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.corrosion.builder.IncrementalCargoBuilder;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+public class NewCargoProjectWizard extends Wizard implements INewWizard {
+	private NewCargoProjectWizardPage wizardPage;
+	public static final String ID = "org.eclipse.corrosion.wizards.newCargo";
+
+	public NewCargoProjectWizard() {
+		super();
+		setNeedsProgressMonitor(true);
+	}
+
+	@Override
+	public void init(IWorkbench workbench, IStructuredSelection selection) {
+		wizardPage = new NewCargoProjectWizardPage();
+		setWindowTitle("New Cargo Based Rust Project");
+
+		Iterator<?> selectionIterator = selection.iterator();
+		Set<IWorkingSet> workingSets = new HashSet<>();
+		IResource selectedResource = null;
+
+		while (selectionIterator.hasNext()) {
+			Object element = selectionIterator.next();
+			IResource asResource = toResource(element);
+
+			if (asResource != null && selectedResource == null) {
+				selectedResource = asResource;
+			} else {
+				IWorkingSet asWorkingSet = Adapters.adapt(element, IWorkingSet.class);
+				if (asWorkingSet != null) {
+					workingSets.add(asWorkingSet);
+				}
+			}
+		}
+
+		if (workingSets.isEmpty() && selectedResource != null) {
+			workingSets.addAll(getWorkingSets(selectedResource));
+		}
+		wizardPage.setWorkingSets(workingSets);
+
+		if (selectedResource != null) {
+			wizardPage.setDirectory(toFile(selectedResource));
+		} else {
+			wizardPage.setDirectory(newFolderLocation());
+		}
+	}
+
+	@Override
+	public void addPages() {
+		addPage(wizardPage);
+	}
+
+	@Override
+	public boolean performFinish() {
+		File location = wizardPage.getDirectory();
+		String projectName = wizardPage.getProjectName();
+		Boolean isBin = wizardPage.isBinaryTemplate();
+		String vcs = wizardPage.getVCS();
+
+		IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+		String cargo = store.getString(CorrosionPreferenceInitializer.cargoPathPreference);
+
+		Boolean makeLocation = !location.exists();
+		if (makeLocation) {
+			location.mkdirs();
+		}
+
+		try {
+			getContainer().run(true, true, monitor -> {
+				monitor.beginTask("Creating Rust project", 0);
+				List<String> commandLine = new ArrayList<>();
+				commandLine.add(cargo);
+				commandLine.add("init");
+
+				commandLine.add("--name");
+				commandLine.add(projectName);
+
+				commandLine.add("--vcs");
+				commandLine.add(vcs);
+
+				if (isBin) {
+					commandLine.add("--bin");
+				} else {
+					commandLine.add("--lib");
+				}
+
+				ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
+				processBuilder.directory(location);
+
+				try {
+					Process process = processBuilder.start();
+					boolean isProcessDone = false;
+					while (!isProcessDone) {
+						if (monitor.isCanceled()) {
+							process.destroyForcibly();
+						}
+						isProcessDone = process.waitFor(100, TimeUnit.MILLISECONDS);
+					}
+					if (process.exitValue() == 0) {
+						String mainFileName;
+						if (isBin) {
+							mainFileName = "main.rs";
+						} else {
+							mainFileName = "lib.rs";
+						}
+						createProject(projectName, location, mainFileName, monitor);
+					} else {
+						String errorOutput = "";
+						try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+							String errorLine;
+							while ((errorLine = in.readLine()) != null) {
+								errorOutput += errorLine + "\n";
+							}
+						}
+						final String finalErrorOutput = errorOutput;
+						Display.getDefault().asyncExec(() -> {
+							MessageDialog.openError(getShell(), "Cannot Create Rust Project", "Create unsuccessful.`"
+									+ String.join(" ", commandLine) + "` error log:\n\n" + finalErrorOutput);
+						});
+						if (makeLocation) {
+							location.delete();
+						}
+					}
+					monitor.done();
+				} catch (IOException e) {
+					monitor.done();
+					MessageDialog.openError(getShell(), "Cannot Create Rust project", e.toString());
+					if (makeLocation) {
+						location.delete();
+					}
+				}
+			});
+		} catch (InvocationTargetException | InterruptedException e) {
+			MessageDialog.openError(getShell(), "Cannot Create Rust Project", e.toString());
+			return false;
+		}
+		return true;
+	}
+
+	private void createProject(String name, File directory, String mainFileName, IProgressMonitor monitor) {
+		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+		IProject project = root.getProject(name);
+		try {
+			if (!project.exists()) {
+				final IWorkspace workspace = ResourcesPlugin.getWorkspace();
+				IProjectDescription projectDescription = workspace.newProjectDescription(project.getName());
+
+				String projectLocation = directory.getAbsolutePath();
+				IPath projectPath = new Path(projectLocation);
+
+				projectDescription.setLocation(projectPath);
+
+				ICommand[] commands = projectDescription.getBuildSpec();
+				ICommand command = projectDescription.newCommand();
+				command.setBuilderName(IncrementalCargoBuilder.BUILDER_ID);
+				ICommand[] nc = new ICommand[commands.length + 1];
+				System.arraycopy(commands, 0, nc, 1, commands.length);
+				nc[0] = command;
+				projectDescription.setBuildSpec(nc);
+
+				project.create(projectDescription, monitor);
+			}
+			project.open(monitor);
+			project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
+
+		} catch (CoreException e) {
+			MessageDialog.openError(getShell(), "Unable to load project description", e.toString());
+		}
+
+		IWorkingSetManager wsm = PlatformUI.getWorkbench().getWorkingSetManager();
+		IFile rsPrgramFile = project.getFile("src/" + mainFileName);
+
+		Display.getDefault().asyncExec(() -> {
+
+			wsm.addToWorkingSets(project, wizardPage.getWorkingSets());
+
+			IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			if (page != null) {
+				try {
+					if (rsPrgramFile.exists()) {
+						IDE.openEditor(page, rsPrgramFile);
+					}
+				} catch (CoreException e) {
+					MessageDialog.openError(getShell(), "Cannot open project", e.toString());
+				}
+			}
+		});
+	}
+
+	private File newFolderLocation() {
+		IPath workspacePath = ResourcesPlugin.getWorkspace().getRoot().getLocation();
+		int appendedNumber = 0;
+		File newFile = workspacePath.append("new_rust_project").toFile();
+		while (newFile.isDirectory()) {
+			appendedNumber++;
+			newFile = workspacePath.append("new_rust_project_" + appendedNumber).toFile();
+		}
+		return newFile;
+	}
+
+	private Set<IWorkingSet> getWorkingSets(IResource resource) {
+		IWorkingSet[] allWorkingSets = PlatformUI.getWorkbench().getWorkingSetManager().getAllWorkingSets();
+		Set<IWorkingSet> fileWorkingSets = new HashSet<>();
+
+		for (IWorkingSet iWorkingSet : allWorkingSets) {
+			IAdaptable[] elements = iWorkingSet.getElements();
+			if (Arrays.asList(elements).contains(resource.getProject())) {
+				fileWorkingSets.add(iWorkingSet);
+			}
+		}
+
+		return fileWorkingSets;
+	}
+
+	private IResource toResource(Object o) {
+		if (o instanceof IResource) {
+			return (IResource) o;
+		} else if (o instanceof IAdaptable) {
+			return ((IAdaptable) o).getAdapter(IResource.class);
+		} else {
+			return null;
+		}
+	}
+
+	private File toFile(IResource r) {
+		IPath location = r.getLocation();
+		if (location.toFile().isFile()) {
+			return location.toFile().getParentFile().getAbsoluteFile();
+		}
+		return location == null ? null : location.toFile();
+	}
+
+}
diff --git a/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizardPage.java b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizardPage.java
new file mode 100644
index 0000000..6057d85
--- /dev/null
+++ b/org.eclipse.corrosion/src/org/eclipse/corrosion/wizards/newCargo/NewCargoProjectWizardPage.java
@@ -0,0 +1,377 @@
+/*********************************************************************
+ * Copyright (c) 2017, 2018 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *  Lucas Bullen (Red Hat Inc.) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.corrosion.wizards.newCargo;
+
+import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.corrosion.CorrosionPlugin;
+import org.eclipse.corrosion.CorrosionPreferenceInitializer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.dialogs.WorkingSetGroup;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+public class NewCargoProjectWizardPage extends WizardPage {
+
+	private Set<IWorkingSet> workingSets;
+	private File directory;
+	private String projectName;
+	private Boolean isDirectoryAndProjectLinked = true;
+
+	protected NewCargoProjectWizardPage() {
+		super(NewCargoProjectWizardPage.class.getName());
+		setTitle("Create a Cargo Based Rust Project");
+		setDescription("Create a new Rust project, using the `cargo init` command");
+
+		Bundle bundle = FrameworkUtil.getBundle(this.getClass());
+		URL url = bundle.getEntry("images/cargo.png");
+		ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url);
+		setImageDescriptor(imageDescriptor);
+	}
+
+	public void setDirectory(File directory) {
+		this.directory = directory;
+	}
+
+	public File getDirectory() {
+		if (isDirectoryAndProjectLinked) {
+			return directory;
+		} else {
+			return new File(directory.toString() + "/" + projectName);
+		}
+	}
+
+	public String getProjectName() {
+		return projectName;
+	}
+
+	public IWorkingSet[] getWorkingSets() {
+		return workingSetsGroup.getSelectedWorkingSets();
+	}
+
+	public void setWorkingSets(Set<IWorkingSet> workingSets) {
+		this.workingSets = workingSets;
+	}
+
+	public boolean isBinaryTemplate() {
+		return binCheckBox.getSelection();
+	}
+
+	public String getVCS() {
+		if (vcsCheckBox.getSelection()) {
+			if (gitRadioButton.getSelection()) {
+				return "git";
+			}
+			if (hgRadioButton.getSelection()) {
+				return "hg";
+			}
+			if (pijulRadioButton.getSelection()) {
+				return "pijul";
+			}
+			if (fossilRadioButton.getSelection()) {
+				return "fossil";
+			}
+		}
+		return "none";
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		Composite container = new Composite(parent, SWT.NULL);
+		setControl(container);
+		container.setLayout(new GridLayout(4, false));
+
+		createLocationPart(container);
+		createTemplatePart(container);
+		createVcsPart(container);
+		createWorkingSetPart(container);
+
+		if (directory != null) {
+			updateDirectory(directory.getAbsolutePath());
+		}
+	}
+
+	private IPreferenceStore store = CorrosionPlugin.getDefault().getPreferenceStore();
+
+	@Override
+	public boolean isPageComplete() {
+		String locationError = "";
+		String projectNameError = "";
+		String cargoError = "";
+
+		File cargo = new File(store.getString(CorrosionPreferenceInitializer.cargoPathPreference));
+		if (!(cargo.exists() && cargo.isFile() && cargo.canExecute())) {
+			cargoError = "Cargo command not found. Fix path in the Rust Preferences Page.";
+		} else if (directory == null || directory.getPath().isEmpty()) {
+			locationError = "Please specify a directory";
+		} else if (projectName == null || projectName.isEmpty()) {
+			projectNameError = "Please specify project name";
+		} else if (directory.isFile()) {
+			locationError = "Invalid location: it is an existing file.";
+		} else if (directory.getParentFile() == null
+				|| (!directory.exists() && !directory.getParentFile().canWrite())) {
+			locationError = "Unable to create such directory";
+		} else if (directory.exists() && !directory.canWrite()) {
+			locationError = "Cannot write in this directory";
+		} else {
+			File cargoProject = new File(directory, IProjectDescription.DESCRIPTION_FILE_NAME);
+			if (cargoProject.exists()) {
+				try {
+					IProjectDescription desc = ResourcesPlugin.getWorkspace()
+							.loadProjectDescription(Path.fromOSString(cargoProject.getAbsolutePath()));
+					if (!desc.getName().equals(projectName)) {
+						projectNameError = "Project name must match one in .project file: " + desc.getName();
+					}
+				} catch (CoreException e) {
+					projectNameError = "Invalid .project file in directory";
+				}
+			} else {
+				IProject project = null;
+				try {
+					project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+					if (project.exists() && (project.getLocation() == null
+							|| !directory.getAbsoluteFile().equals(project.getLocation().toFile().getAbsoluteFile()))) {
+						projectNameError = "Another project with same name already exists in workspace.";
+					}
+				} catch (IllegalArgumentException ex) {
+					projectNameError = "Invalid project name";
+				}
+			}
+		}
+
+		String error = locationError + projectNameError + cargoError;
+
+		if (error.isEmpty()) {
+			setErrorMessage(null);
+			projectNameControlDecoration.hide();
+			locationControlDecoration.hide();
+		} else {
+			if (!locationError.isEmpty()) {
+				locationControlDecoration.showHoverText(locationError);
+				locationControlDecoration.show();
+				projectNameControlDecoration.hide();
+			} else if (!projectNameError.isEmpty()) {
+				projectNameControlDecoration.showHoverText(projectNameError);
+				projectNameControlDecoration.show();
+				locationControlDecoration.hide();
+			}
+			setErrorMessage(error);
+		}
+		return error.isEmpty();
+	}
+
+	private Text locationText;
+	private Label projectNameLabel;
+	private Text projectNameText;
+	private Image linkImage;
+	private Button linkButton;
+	private ControlDecoration locationControlDecoration;
+	private ControlDecoration projectNameControlDecoration;
+
+	private void createLocationPart(Composite container) {
+		Label locationLabel = new Label(container, SWT.NONE);
+		locationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+		locationLabel.setText("Location");
+
+		Image errorImage = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)
+				.getImage();
+
+		locationText = new Text(container, SWT.BORDER);
+		GridData locationGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
+		locationGridData.widthHint = convertWidthInCharsToPixels(50);
+		locationText.setLayoutData(locationGridData);
+		locationControlDecoration = new ControlDecoration(locationText, SWT.TOP | SWT.LEFT);
+		locationControlDecoration.setImage(errorImage);
+		locationControlDecoration.setShowOnlyOnFocus(true);
+		locationText.addModifyListener(e -> {
+			updateDirectory(locationText.getText());
+			setPageComplete(isPageComplete());
+		});
+
+		Button browseButton = new Button(container, SWT.NONE);
+		browseButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
+		browseButton.setText("Browse...");
+		browseButton.addSelectionListener(widgetSelectedAdapter(e -> {
+			DirectoryDialog dialog = new DirectoryDialog(browseButton.getShell());
+			String path = dialog.open();
+			if (path != null) {
+				updateDirectory(path);
+			}
+			setPageComplete(isPageComplete());
+		}));
+		Composite linesAboveLink = new Composite(container, SWT.NONE);
+		GridData linesAboveLinkLayoutData = new GridData(SWT.FILL, SWT.FILL);
+		linesAboveLinkLayoutData.heightHint = linesAboveLinkLayoutData.widthHint = 30;
+		linesAboveLink.setLayoutData(linesAboveLinkLayoutData);
+		linesAboveLink.addPaintListener(e -> {
+			e.gc.setForeground(((Control) e.widget).getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+			e.gc.drawLine(0, e.height / 2, e.width / 2, e.height / 2);
+			e.gc.drawLine(e.width / 2, e.height / 2, e.width / 2, e.height);
+		});
+
+		new Label(container, SWT.NONE);
+		new Label(container, SWT.NONE);
+		new Label(container, SWT.NONE);
+
+		linkButton = new Button(container, SWT.TOGGLE);
+		linkButton.setToolTipText("Link project name and folder name");
+		linkButton.setSelection(true);
+		try (InputStream iconStream = getClass().getResourceAsStream("/icons/link_obj.png")) {
+			linkImage = new Image(linkButton.getDisplay(), iconStream);
+			linkButton.setImage(linkImage);
+		} catch (IOException e) {
+			CorrosionPlugin.logError(e);
+		}
+		linkButton.addSelectionListener(widgetSelectedAdapter(s -> {
+			isDirectoryAndProjectLinked = linkButton.getSelection();
+			projectNameText.setEnabled(!linkButton.getSelection());
+			projectNameLabel.setEnabled(!linkButton.getSelection());
+			updateProjectName();
+		}));
+
+		projectNameLabel = new Label(container, SWT.NONE);
+		projectNameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+		projectNameLabel.setText("Project name");
+
+		projectNameText = new Text(container, SWT.BORDER);
+		projectNameText.setEnabled(false);
+		projectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+		projectNameControlDecoration = new ControlDecoration(projectNameText, SWT.TOP | SWT.LEFT);
+		projectNameControlDecoration.setImage(errorImage);
+		projectNameControlDecoration.setShowOnlyOnFocus(true);
+		projectNameText.addModifyListener(e -> {
+			updateProjectName();
+			setPageComplete(isPageComplete());
+		});
+		Composite linesBelowLink = new Composite(container, SWT.NONE);
+		GridData linesBelowLinkLayoutData = new GridData(SWT.FILL, SWT.FILL);
+		linesBelowLinkLayoutData.heightHint = linesBelowLinkLayoutData.widthHint = 30;
+		linesBelowLink.setLayoutData(linesAboveLinkLayoutData);
+		linesBelowLink.addPaintListener(e -> {
+			e.gc.setForeground(((Control) e.widget).getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
+			e.gc.drawLine(0, e.height / 2, e.width / 2, e.height / 2);
+			e.gc.drawLine(e.width / 2, e.height / 2, e.width / 2, 0);
+		});
+	}
+
+	private void updateProjectName() {
+		if (!isDirectoryAndProjectLinked) {
+			projectName = projectNameText.getText();
+		} else if (projectName == null || (directory != null && !projectName.equals(directory.getName()))) {
+			projectName = directory.getName();
+			projectNameText.setText(projectName);
+		}
+	}
+
+	private void updateDirectory(String directoryPath) {
+		directory = new File(directoryPath);
+		if (!locationText.getText().equals(directoryPath)) {
+			locationText.setText(directoryPath);
+		} else if (isDirectoryAndProjectLinked) {
+			updateProjectName();
+		}
+	}
+
+	private Button binCheckBox;
+
+	private void createTemplatePart(Composite container) {
+		new Label(container, SWT.NONE);
+		binCheckBox = new Button(container, SWT.CHECK);
+		binCheckBox.setText("Use a binary application template");
+		binCheckBox.setSelection(true);
+		binCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+	}
+
+	private Button vcsCheckBox;
+	private Button gitRadioButton;
+	private Button hgRadioButton;
+	private Button pijulRadioButton;
+	private Button fossilRadioButton;
+
+	private void createVcsPart(Composite container) {
+		new Label(container, SWT.NONE);
+		vcsCheckBox = new Button(container, SWT.CHECK);
+		vcsCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+		vcsCheckBox.setText("Initialize with version control system");
+		vcsCheckBox.addSelectionListener(widgetSelectedAdapter(s -> {
+			Boolean shouldBeEnabled = vcsCheckBox.getSelection();
+			gitRadioButton.setEnabled(shouldBeEnabled);
+			hgRadioButton.setEnabled(shouldBeEnabled);
+			pijulRadioButton.setEnabled(shouldBeEnabled);
+			fossilRadioButton.setEnabled(shouldBeEnabled);
+		}));
+
+		new Label(container, SWT.NONE);
+		Composite radioGroup = new Composite(container, SWT.NONE);
+		radioGroup.setLayout(new GridLayout(4, false));
+		GridData radioGroupdGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1);
+		radioGroupdGridData.horizontalIndent = 15;
+		radioGroup.setLayoutData(radioGroupdGridData);
+		gitRadioButton = new Button(radioGroup, SWT.RADIO);
+		gitRadioButton.setText("Git");
+		gitRadioButton.setEnabled(false);
+		gitRadioButton.setSelection(true);
+		hgRadioButton = new Button(radioGroup, SWT.RADIO);
+		hgRadioButton.setText("Mercurial (hg)");
+		hgRadioButton.setEnabled(false);
+		pijulRadioButton = new Button(radioGroup, SWT.RADIO);
+		pijulRadioButton.setText("Pijul");
+		pijulRadioButton.setEnabled(false);
+		fossilRadioButton = new Button(radioGroup, SWT.RADIO);
+		fossilRadioButton.setText("Fossil");
+		fossilRadioButton.setEnabled(false);
+	}
+
+	private WorkingSetGroup workingSetsGroup;
+
+	private void createWorkingSetPart(Composite container) {
+		Composite workingSetComposite = new Composite(container, SWT.NONE);
+		GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, false, 4, 1);
+		workingSetComposite.setLayoutData(layoutData);
+		workingSetComposite.setLayout(new GridLayout(1, false));
+		String[] workingSetIds = new String[] { "org.eclipse.ui.resourceWorkingSetPage" };
+		IStructuredSelection wsSel = null;
+		if (this.workingSets != null) {
+			wsSel = new StructuredSelection(this.workingSets.toArray());
+		}
+		this.workingSetsGroup = new WorkingSetGroup(workingSetComposite, wsSel, workingSetIds);
+	}
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..751d187
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,218 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>org.eclipse.corrosion</groupId>
+	<artifactId>parent</artifactId>
+	<version>0.1.0-SNAPSHOT</version>
+	<packaging>pom</packaging>
+	
+	<prerequisites>
+		<maven>3.1.1</maven>
+	</prerequisites>
+	<properties>
+		<tycho-version>1.0.0</tycho-version>
+		<tycho-extras-version>${tycho-version}</tycho-extras-version>
+		<tycho.scmUrl>scm:git:https://github.com/lucasbullen/corrosion.git</tycho.scmUrl>
+	</properties>
+
+	<modules>
+		<module>target-platform</module>
+		<module>org.eclipse.corrosion</module>
+		<module>org.eclipse.corrosion.tests</module>
+	</modules>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-maven-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<extensions>true</extensions>
+			</plugin>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>target-platform-configuration</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<includePackedArtifacts>true</includePackedArtifacts>
+					<target>
+						<artifact>
+							<groupId>${project.groupId}</groupId>
+							<artifactId>target-platform</artifactId>
+							<version>${project.version}</version>
+						</artifact>
+					</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-source-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<executions>
+					<execution>
+						<id>plugin-source</id>
+						<goals>
+							<goal>plugin-source</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-packaging-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<sourceReferences>
+						<generate>true</generate>
+					</sourceReferences>
+				</configuration>
+				<dependencies>
+					<dependency>
+						<groupId>org.eclipse.tycho.extras</groupId>
+						<artifactId>tycho-sourceref-jgit</artifactId>
+						<version>${tycho-extras-version}</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+			<plugin>
+				<groupId>org.jacoco</groupId>
+				<artifactId>jacoco-maven-plugin</artifactId>
+				<version>0.7.9</version>
+				<executions>
+					<execution>
+						<goals><goal>prepare-agent</goal></goals>
+					</execution>
+				</executions>
+				<configuration>
+					<append>true</append>
+					<destFile>${sonar.jacoco.reportPath}</destFile>
+					<includes>
+						<include>org.eclipse.corrosion*</include>
+					</includes>
+				</configuration>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.eclipse.tycho</groupId>
+					<artifactId>tycho-packaging-plugin</artifactId>
+					<version>${tycho-version}</version>
+					<dependencies>
+						<dependency>
+							<groupId>org.eclipse.tycho.extras</groupId>
+							<artifactId>tycho-buildtimestamp-jgit</artifactId>
+							<version>${tycho-extras-version}</version>
+						</dependency>
+					</dependencies>
+					<configuration>
+						<timestampProvider>jgit</timestampProvider>
+						<jgit.ignore>pom.xml</jgit.ignore>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
+
+	<profiles>
+		<profile>
+			<id>packAndSign</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.eclipse.tycho.extras</groupId>
+						<artifactId>tycho-pack200a-plugin</artifactId>
+						<version>${tycho-extras-version}</version>
+						<executions>
+							<execution>
+								<id>pack200-normalize</id>
+								<phase>package</phase>
+								<goals>
+									<goal>normalize</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.eclipse.cbi.maven.plugins</groupId>
+						<artifactId>eclipse-jarsigner-plugin</artifactId>
+						<version>1.1.4</version>
+						<executions>
+							<execution>
+								<id>sign</id>
+								<phase>package</phase>
+								<goals>
+									<goal>sign</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.eclipse.tycho.extras</groupId>
+						<artifactId>tycho-pack200b-plugin</artifactId>
+						<version>${tycho-extras-version}</version>
+						<executions>
+							<execution>
+								<id>pack200-pack</id>
+								<phase>package</phase>
+								<goals>
+									<goal>pack</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.eclipse.tycho</groupId>
+						<artifactId>tycho-p2-plugin</artifactId>
+						<version>${tycho-extras-version}</version>
+						<executions>
+							<execution>
+								<id>p2-metadata</id>
+								<phase>package</phase>
+								<goals>
+									<goal>p2-metadata</goal>
+								</goals>
+							</execution>
+						</executions>
+						<configuration>
+							<defaultP2Metadata>false</defaultP2Metadata>
+						</configuration>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<!-- Automatic profile for Mac-specific settings -->
+		<profile>
+			<id>macos</id>
+			<activation>
+				<os>
+					<family>mac</family>
+				</os>
+			</activation>
+			<properties>
+				<ui.test.vmargs>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts -Djava.awt.headless=false</ui.test.vmargs>
+			</properties>
+		</profile>
+	</profiles>
+
+	<pluginRepositories>
+		<pluginRepository>
+			<id>cbi</id>
+			<url>https://repo.eclipse.org/content/groups/cbi</url>
+			<snapshots><enabled>true</enabled></snapshots>
+		</pluginRepository>
+		<pluginRepository>
+			<id>jboss</id>
+			<url>https://repository.jboss.org/</url>
+			<snapshots><enabled>true</enabled></snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+
+	<distributionManagement>
+		<snapshotRepository>
+			<id>jboss-snapshots-repository</id>
+			<name>JBoss Snapshots Repository</name>
+			<url>https://repository.jboss.org/nexus/content/repositories/snapshots/</url>
+			<uniqueVersion>false</uniqueVersion>
+		</snapshotRepository>
+	</distributionManagement>
+</project>
diff --git a/site/.project b/site/.project
new file mode 100644
index 0000000..4386b92
--- /dev/null
+++ b/site/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>site</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.UpdateSiteBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.UpdateSiteNature</nature>
+	</natures>
+</projectDescription>
diff --git a/site/images/installNewSoftwareDropdown.png b/site/images/installNewSoftwareDropdown.png
new file mode 100644
index 0000000..1a88fa3
--- /dev/null
+++ b/site/images/installNewSoftwareDropdown.png
Binary files differ
diff --git a/site/images/installSoftwareWizard.png b/site/images/installSoftwareWizard.png
new file mode 100644
index 0000000..d5354b4
--- /dev/null
+++ b/site/images/installSoftwareWizard.png
Binary files differ
diff --git a/site/index.html b/site/index.html
new file mode 100644
index 0000000..6d52783
--- /dev/null
+++ b/site/index.html
@@ -0,0 +1,50 @@
+<html>
+	<body>
+		<h1>How to install Eclipse Corrosion</h1>
+		<h3>Rust IDE built in Eclipse</h3>
+		<style>
+			body{
+			width:100%;
+				background-color:#ededed;
+				margin:50px;
+			}
+			h1,h3{
+				text-align:center;
+			}
+			li{
+				margin-top:15px;
+				margin-bottom:15px;
+			}
+			a{
+				color:black;
+			}
+		</style>
+		<div style="width: 50%; margin: 0 auto;">
+			<ol>
+				<li>Open Eclipse IDE (<a href="http://download.eclipse.org/eclipse/downloads/">Download</a>)</li>
+
+				<li>Open the Install New Software Wizard</li>
+				<img style="width:450px" src="images/installNewSoftwareDropdown.png" alt="dropdown menu location" />
+
+				<li>Enter <b>https://lucasbullen.github.io/corrosion/site/</b> in the site field</li>
+
+				<li>Select <b>Corrosion - Rust in Eclipse IDE</b> and click <b>Next</b></li>
+				<img style="width:450px" src="images/installSoftwareWizard.png" alt="install software wizard"/>
+
+				<li>Wait for the dependencies to load</li>
+
+				<li>Press <b>Next</b> again</li>
+
+				<li>Accept the license and press <b>Finish</b></li>
+
+				<li>Restart Eclipse</li>
+
+				<li><b>Start developing your Rust projects in Eclipse IDE!</b></li>
+
+				<li><a href="https://github.com/LucasBullen/corrosion/issues">Make requests and PRs for new features and bug fixes</a></li>
+
+				<li><a href="https://github.com/LucasBullen/corrosion">Learn more about Corrosion</a></li>
+			</ol>
+		<div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/site/site.xml b/site/site.xml
new file mode 100644
index 0000000..89c3595
--- /dev/null
+++ b/site/site.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+   <feature url="features/org.eclipse.corrosion.feature_0.1.0.201802080934.jar" id="org.eclipse.corrosion.feature" version="0.1.0.201802080934">
+      <category name="org.eclipse.corrosion.category"/>
+   </feature>
+   <category-def name="org.eclipse.corrosion.category" label="Corrosion: Rust edition in Eclipse IDE">
+      <description>
+         Corrosion enables Rust application development in the Eclipse IDE.
+      </description>
+   </category-def>
+</site>
diff --git a/target-platform/.gitignore b/target-platform/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/target-platform/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/target-platform/.project b/target-platform/.project
new file mode 100644
index 0000000..deeeab4
--- /dev/null
+++ b/target-platform/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>target-platform</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>
diff --git a/target-platform/.settings/org.eclipse.m2e.core.prefs b/target-platform/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/target-platform/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/target-platform/pom.xml b/target-platform/pom.xml
new file mode 100644
index 0000000..236983f
--- /dev/null
+++ b/target-platform/pom.xml
@@ -0,0 +1,10 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>target-platform</artifactId>
+	<parent>
+		<groupId>org.eclipse.corrosion</groupId>
+		<artifactId>parent</artifactId>
+		<version>0.1.0-SNAPSHOT</version>
+	</parent>
+	<packaging>eclipse-target-definition</packaging>
+</project>
diff --git a/target-platform/target-platform.target b/target-platform/target-platform.target
new file mode 100644
index 0000000..d80708f
--- /dev/null
+++ b/target-platform/target-platform.target
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde version="3.8"?><target name="corrosion" sequenceNumber="3">
+<locations>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.lsp4e" version="0.0.0"/>
+<repository location="http://download.eclipse.org/lsp4e/0.5.x-snapshots/"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="tm-feature.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/tm4e/snapshots/"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/mylyn/releases/latest"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.mylyn.wikitext_feature.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/mylyn/docs/releases/3.0"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.jface.text" version="0.0.0"/>
+<unit id="org.eclipse.jdt.annotation" version="0.0.0"/>
+<unit id="org.eclipse.platform.ide" version="0.0.0"/>
+<unit id="org.eclipse.sdk.ide" version="0.0.0"/>
+<unit id="org.eclipse.ui.genericeditor" version="0.0.0"/>
+<unit id="org.eclipse.ui.tests.harness" version="0.0.0"/>
+<unit id="org.junit" version="0.0.0"/>
+<repository location="http://download.eclipse.org/eclipse/updates/4.7/"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
+<repository location="http://download.eclipse.org/releases/oxygen/"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.cdt.debug.core" version="0.0.0"/>
+<unit id="org.eclipse.cdt.core" version="0.0.0"/>
+<unit id="org.eclipse.cdt.launch" version="0.0.0"/>
+<unit id="org.eclipse.cdt.dsf.gdb" version="0.0.0"/>
+<unit id="org.eclipse.cdt.dsf.gdb.ui" version="0.0.0"/>
+<unit id="org.eclipse.cdt.dsf" version="0.0.0"/>
+<repository location="http://download.eclipse.org/tools/cdt/releases/9.2"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.launchbar.core" version="0.0.0"/>
+<repository location="http://download.eclipse.org/tools/cdt/launchbar/oxygen/"/>
+</location>
+
+<location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.tm.terminal.control" version="0.0.0"/>
+<repository location="http://download.eclipse.org/tm/terminal/updates/4.0"/>
+</location>
+
+<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.license.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/cbi/updates/license/"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.apache.commons.io" version="0.0.0"/>
+<repository location="http://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository"/>
+</location>
+</locations>
+</target>
\ No newline at end of file