From 11f4a8a797816cfa8272718cc05baaf7be345d75 Mon Sep 17 00:00:00 2001
From: Darius Roberts <darius.roberts@gmail.com>
Date: Wed, 25 Sep 2013 09:25:50 -0400
Subject: [PATCH] adding gherkin mode

---
 AUTHORS                 |   1 +
 doc/compress.html       |   1 +
 mode/gherkin/gherkin.js | 170 ++++++++++++++++++++++++++++++++++++++++
 mode/gherkin/index.html |  48 ++++++++++++
 mode/index.html         |   1 +
 mode/meta.js            |   3 +-
 6 files changed, 223 insertions(+), 1 deletion(-)
 create mode 100644 mode/gherkin/gherkin.js
 create mode 100644 mode/gherkin/index.html

diff --git a/AUTHORS b/AUTHORS
index ad2ec9957..260c13a86 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -84,6 +84,7 @@ Ford_Lawnmower
 Gabriel Nahmias
 galambalazs
 Gautam Mehta
+Glenn Jorde
 Glenn Ruehle
 Golevka
 Gordon Smith
diff --git a/doc/compress.html b/doc/compress.html
index 5ae53c483..567c68f45 100644
--- a/doc/compress.html
+++ b/doc/compress.html
@@ -93,6 +93,7 @@
           <option value="http://codemirror.net/mode/fortran/fortran.js">fortran.js</option>
           <option value="http://codemirror.net/mode/gfm/gfm.js">gfm.js</option>
           <option value="http://codemirror.net/mode/gas/gas.js">gas.js</option>
+          <option value="http://codemirror.net/mode/gherkin/gherkin.js">gherkin.js</option>
           <option value="http://codemirror.net/mode/go/go.js">go.js</option>
           <option value="http://codemirror.net/mode/groovy/groovy.js">groovy.js</option>
           <option value="http://codemirror.net/mode/haml/haml.js">haml.js</option>
diff --git a/mode/gherkin/gherkin.js b/mode/gherkin/gherkin.js
new file mode 100644
index 000000000..580587a02
--- /dev/null
+++ b/mode/gherkin/gherkin.js
@@ -0,0 +1,170 @@
+/*
+Gherkin mode - http://www.cukes.info/
+Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues
+*/
+
+// Following Objs from Brackets implementation: https://github.com/tregusti/brackets-gherkin/blob/master/main.js
+//var Quotes = {
+//  SINGLE: 1,
+//  DOUBLE: 2
+//};
+
+//var regex = {
+//  keywords: /(Feature| {2}(Scenario|In order to|As|I)| {4}(Given|When|Then|And))/
+//};
+
+CodeMirror.defineMode("gherkin", function () {
+  return {
+    startState: function () {
+      return {
+        lineNumber: 0,
+        tableHeaderLine: null,
+        allowFeature: true,
+        allowBackground: false,
+        allowScenario: false,
+        allowSteps: false,
+        allowPlaceholders: false,
+        inMultilineArgument: false,
+        inMultilineString: false,
+        inMultilineTable: false
+      };
+    },
+    token: function (stream, state) {
+      if (stream.sol()) {
+        state.lineNumber++;
+      }
+      stream.eatSpace();
+
+      // INSIDE OF MULTILINE ARGUMENTS
+      if (state.inMultilineArgument) {
+
+        // STRING
+        if (state.inMultilineString) {
+          if (stream.match('"""')) {
+            state.inMultilineString = false;
+            state.inMultilineArgument = false;
+          } else {
+            stream.match(/.*/);
+          }
+          return "string";
+        }
+
+        // TABLE
+        if (state.inMultilineTable) {
+          // New table, assume first row is headers
+          if (state.tableHeaderLine === null) {
+            state.tableHeaderLine = state.lineNumber;
+          }
+
+          if (stream.match(/\|\s*/)) {
+            if (stream.eol()) {
+              state.inMultilineTable = false;
+            }
+            return "bracket";
+          } else {
+            stream.match(/[^\|]*/);
+            return state.tableHeaderLine === state.lineNumber ? "property" : "string";
+          }
+        }
+
+        // DETECT START
+        if (stream.match('"""')) {
+          // String
+          state.inMultilineString = true;
+          return "string";
+        } else if (stream.match("|")) {
+          // Table
+          state.inMultilineTable = true;
+          return "bracket";
+        } else {
+          // Or abort
+          state.inMultilineArgument = false;
+          state.tableHeaderLine = null;
+        }
+
+
+        return null;
+      }
+
+      // LINE COMMENT
+      if (stream.match(/#.*/)) {
+        return "comment";
+
+      // TAG
+      } else if (stream.match(/@\S+/)) {
+        return "def";
+
+      // FEATURE
+      } else if (state.allowFeature && stream.match(/Feature:/)) {
+        state.allowScenario = true;
+        state.allowBackground = true;
+        state.allowPlaceholders = false;
+        state.allowSteps = false;
+        return "keyword";
+
+      // BACKGROUND
+      } else if (state.allowBackground && stream.match("Background:")) {
+        state.allowPlaceholders = false;
+        state.allowSteps = true;
+        state.allowBackground = false;
+        return "keyword";
+
+      // SCENARIO OUTLINE
+      } else if (state.allowScenario && stream.match("Scenario Outline:")) {
+        state.allowPlaceholders = true;
+        state.allowSteps = true;
+        return "keyword";
+
+      // EXAMPLES
+      } else if (state.allowScenario && stream.match("Examples:")) {
+        state.allowPlaceholders = false;
+        state.allowSteps = true;
+        state.allowBackground = false;
+        state.inMultilineArgument = true;
+        return "keyword";
+
+      // SCENARIO
+      } else if (state.allowScenario && stream.match(/Scenario:/)) {
+        state.allowPlaceholders = false;
+        state.allowSteps = true;
+        state.allowBackground = false;
+        return "keyword";
+
+      // STEPS
+      } else if (state.allowSteps && stream.match(/(Given|When|Then|And|But)/)) {
+        return "keyword";
+
+      // INLINE STRING
+      } else if (!state.inMultilineArgument && stream.match(/"/)) {
+        stream.match(/.*?"/);
+        return "string";
+
+      // MULTILINE ARGUMENTS
+      } else if (state.allowSteps && stream.eat(":")) {
+        if (stream.match(/\s*$/)) {
+          state.inMultilineArgument = true;
+          return "keyword";
+        } else {
+          return null;
+        }
+
+      } else if (state.allowSteps && stream.match("<")) {
+        if (stream.match(/.*?>/)) {
+          return "property";
+        } else {
+          return null;
+        }
+
+      // Fall through
+      } else {
+        stream.eatWhile(/[^":<]/);
+      }
+
+      return null;
+    }
+  };
+});
+
+CodeMirror.defineMIME("text/x-feature", "gherkin");
+if (!CodeMirror.mimeModes.hasOwnProperty("text/x-feature"))
+  CodeMirror.defineMIME("text/x-feature", "gherkin");
diff --git a/mode/gherkin/index.html b/mode/gherkin/index.html
new file mode 100644
index 000000000..b76877acd
--- /dev/null
+++ b/mode/gherkin/index.html
@@ -0,0 +1,48 @@
+<!doctype html>
+
+<title>CodeMirror: Gherkin mode</title>
+<meta charset="utf-8"/>
+<link rel=stylesheet href="../../doc/docs.css">
+
+<link rel="stylesheet" href="../../lib/codemirror.css">
+<script src="../../lib/codemirror.js"></script>
+<script src="gherkin.js"></script>
+<style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>
+<div id=nav>
+  <a href="http://codemirror.net"><img id=logo src="../../doc/logo.png"></a>
+
+  <ul>
+    <li><a href="../../index.html">Home</a>
+    <li><a href="../../doc/manual.html">Manual</a>
+    <li><a href="https://github.com/marijnh/codemirror">Code</a>
+  </ul>
+  <ul>
+    <li><a href="../index.html">Language modes</a>
+    <li><a class=active href="#">Gherkin</a>
+  </ul>
+</div>
+
+<article>
+<h2>Gherkin mode</h2>
+<form><textarea id="code" name="code">
+Feature: Using Google
+  Background: 
+    Something something
+    Something else
+  Scenario: Has a homepage
+    When I navigate to the google home page
+    Then the home page should contain the menu and the search form
+  Scenario: Searching for a term 
+    When I navigate to the google home page
+    When I search for Tofu
+    Then the search results page is displayed
+    Then the search results page contains 10 individual search results
+    Then the search results contain a link to the wikipedia tofu page
+</textarea></form>
+    <script>
+      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
+    </script>
+
+    <p><strong>MIME types defined:</strong> <code>text/x-feature</code>.</p>
+
+  </article>
diff --git a/mode/index.html b/mode/index.html
index 063e69b6c..f72b1f062 100644
--- a/mode/index.html
+++ b/mode/index.html
@@ -46,6 +46,7 @@ option.</p>
       <li><a href="erlang/index.html">Erlang</a></li>
       <li><a href="fortran/index.html">Fortran</a></li>
       <li><a href="gas/index.html">Gas</a> (AT&amp;T-style assembly)</li>
+      <li><a href="gherkin/index.html">Gherkin</a></li>
       <li><a href="go/index.html">Go</a></li>
       <li><a href="groovy/index.html">Groovy</a></li>
       <li><a href="haml/index.html">HAML</a></li>
diff --git a/mode/meta.js b/mode/meta.js
index ce51c8ae1..fe5cd848a 100644
--- a/mode/meta.js
+++ b/mode/meta.js
@@ -18,8 +18,9 @@ CodeMirror.modeInfo = [
   {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'},
   {name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'},
   {name: 'Gas', mime: 'text/x-gas', mode: 'gas'},
+  {name: 'Gherkin', mime: 'text/x-feature', mode: 'gherkin'},
   {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'},
-  {name: 'GO', mime: 'text/x-go', mode: 'go'},
+  {name: 'Go', mime: 'text/x-go', mode: 'go'},
   {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'},
   {name: 'HAML', mime: 'text/x-haml', mode: 'haml'},
   {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'},
-- 
GitLab