From a66e29f8d0df845fdde425a1fbe7f06b75ff464e Mon Sep 17 00:00:00 2001
From: Vitaly Puzrin <vitaly@rcdesign.ru>
Date: Wed, 31 Dec 2014 13:24:25 +0300
Subject: [PATCH] Place md link to states and remove other aliases

---
 lib/helpers/parse_link_destination.js |  4 ++--
 lib/helpers/parse_link_label.js       |  2 +-
 lib/index.js                          | 23 +++++------------------
 lib/parser_block.js                   | 14 +++++---------
 lib/parser_core.js                    |  2 ++
 lib/parser_inline.js                  |  8 +++++---
 lib/rules_block/blockquote.js         |  6 +++---
 lib/rules_block/deflist.js            |  4 ++--
 lib/rules_block/footnote.js           |  4 ++--
 lib/rules_block/htmlblock.js          |  2 +-
 lib/rules_block/list.js               |  6 +++---
 lib/rules_block/paragraph.js          |  2 +-
 lib/rules_block/state_block.js        |  8 +++-----
 lib/rules_core/block.js               |  2 +-
 lib/rules_core/inline.js              |  2 +-
 lib/rules_core/linkify.js             |  4 ++--
 lib/rules_core/references.js          |  7 +++----
 lib/rules_core/replacements.js        |  2 +-
 lib/rules_core/smartquotes.js         | 13 ++++++++-----
 lib/rules_core/state_core.js          | 11 +++++++++++
 lib/rules_inline/autolink.js          |  4 ++--
 lib/rules_inline/del.js               |  6 +++---
 lib/rules_inline/emphasis.js          |  6 +++---
 lib/rules_inline/footnote_inline.js   |  4 ++--
 lib/rules_inline/footnote_ref.js      |  2 +-
 lib/rules_inline/htmltag.js           |  2 +-
 lib/rules_inline/ins.js               |  6 +++---
 lib/rules_inline/links.js             | 12 +++++-------
 lib/rules_inline/mark.js              |  6 +++---
 lib/rules_inline/state_inline.js      |  6 +++---
 lib/rules_inline/sub.js               |  4 ++--
 lib/rules_inline/sup.js               |  4 ++--
 32 files changed, 92 insertions(+), 96 deletions(-)
 create mode 100644 lib/rules_core/state_core.js

diff --git a/lib/helpers/parse_link_destination.js b/lib/helpers/parse_link_destination.js
index 3f35da4..01549ee 100644
--- a/lib/helpers/parse_link_destination.js
+++ b/lib/helpers/parse_link_destination.js
@@ -22,7 +22,7 @@ module.exports = function parseLinkDestination(state, pos) {
       if (code === 0x0A /* \n */) { return false; }
       if (code === 0x3E /* > */) {
         link = normalizeLink(unescapeMd(state.src.slice(start + 1, pos)));
-        if (!state.parser.validateLink(link)) { return false; }
+        if (!state.md.inline.validateLink(link)) { return false; }
         state.pos = pos + 1;
         state.linkContent = link;
         return true;
@@ -71,7 +71,7 @@ module.exports = function parseLinkDestination(state, pos) {
   if (start === pos) { return false; }
 
   link = normalizeLink(unescapeMd(state.src.slice(start, pos)));
-  if (!state.parser.validateLink(link)) { return false; }
+  if (!state.md.inline.validateLink(link)) { return false; }
 
   state.linkContent = link;
   state.pos = pos;
diff --git a/lib/helpers/parse_link_label.js b/lib/helpers/parse_link_label.js
index 9ac8364..5435cb0 100644
--- a/lib/helpers/parse_link_label.js
+++ b/lib/helpers/parse_link_label.js
@@ -30,7 +30,7 @@ module.exports = function parseLinkLabel(state, start, disableNested) {
     }
 
     prevPos = state.pos;
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
     if (marker === 0x5B /* [ */) {
       if (prevPos === state.pos - 1) {
         // increase level if we find text `[`, which is not a part of any token
diff --git a/lib/index.js b/lib/index.js
index 75039e1..2cf622a 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -18,19 +18,6 @@ var config = {
 };
 
 
-function StateCore(self, src, env) {
-  this.src = src;
-  this.env = env;
-  this.options = self.options;
-  this.tokens = [];
-  this.inlineMode = false;
-
-  this.inline = self.inline;
-  this.block = self.block;
-  this.renderer = self.renderer;
-  this.typographer = self.typographer;
-}
-
 /**
  * class MarkdownIt
  *
@@ -215,7 +202,7 @@ function MarkdownIt(presetName, options) {
    * Assorted utility functions, useful to write plugins. See details
    * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js).
    **/
-  this.utils    = utils;
+  this.utils = utils;
 
   /**
    * MarkdownIt#helpers -> helpers
@@ -223,10 +210,10 @@ function MarkdownIt(presetName, options) {
    * Link components parser functions, useful to write plugins. See details
    * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).
    **/
-  this.helpers  = helpers;
+  this.helpers = helpers;
 
 
-  this.options  = {};
+  this.options = {};
   this.configure(config[presetName]);
 
   if (options) { this.set(options); }
@@ -359,7 +346,7 @@ MarkdownIt.prototype.use = function (plugin /*, params, ... */) {
  * You will not need it with high probability.
  **/
 MarkdownIt.prototype.parse = function (src, env) {
-  var state = new StateCore(this, src, env);
+  var state = new this.core.State(src, this, env);
 
   this.core.process(state);
 
@@ -395,7 +382,7 @@ MarkdownIt.prototype.render = function (src, env) {
  * tokens in `children` property.
  **/
 MarkdownIt.prototype.parseInline = function (src, env) {
-  var state = new StateCore(this, src, env);
+  var state = new this.core.State(src, this, env);
 
   state.inlineMode = true;
   this.core.process(state);
diff --git a/lib/parser_block.js b/lib/parser_block.js
index b140993..8a641b6 100644
--- a/lib/parser_block.js
+++ b/lib/parser_block.js
@@ -7,7 +7,6 @@
 
 
 var Ruler           = require('./ruler');
-var StateBlock      = require('./rules_block/state_block');
 
 
 var _rules = [
@@ -104,7 +103,7 @@ var NULL_RE      = /\u0000/g;
  *
  * Process input string and push block tokens into `outTokens`
  **/
-ParserBlock.prototype.parse = function (src, options, env, outTokens) {
+ParserBlock.prototype.parse = function (src, md, env, outTokens) {
   var state, lineStart = 0, lastTabPos = 0;
 
   if (!src) { return []; }
@@ -133,16 +132,13 @@ ParserBlock.prototype.parse = function (src, options, env, outTokens) {
     });
   }
 
-  state = new StateBlock(
-    src,
-    this,
-    options,
-    env,
-    outTokens
-  );
+  state = new this.State(src, md, env, outTokens);
 
   this.tokenize(state, state.line, state.lineMax);
 };
 
 
+ParserBlock.prototype.State = require('./rules_block/state_block');
+
+
 module.exports = ParserBlock;
diff --git a/lib/parser_core.js b/lib/parser_core.js
index 6d45f00..4be6c94 100644
--- a/lib/parser_core.js
+++ b/lib/parser_core.js
@@ -55,5 +55,7 @@ Core.prototype.process = function (state) {
   }
 };
 
+Core.prototype.State = require('./rules_core/state_core');
+
 
 module.exports = Core;
diff --git a/lib/parser_inline.js b/lib/parser_inline.js
index 8f555a0..8664f06 100644
--- a/lib/parser_inline.js
+++ b/lib/parser_inline.js
@@ -7,7 +7,6 @@
 
 
 var Ruler           = require('./ruler');
-var StateInline     = require('./rules_inline/state_inline');
 var replaceEntities = require('./common/utils').replaceEntities;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -146,11 +145,14 @@ ParserInline.prototype.tokenize = function (state) {
  *
  * Process input string and push inline tokens into `outTokens`
  **/
-ParserInline.prototype.parse = function (str, options, env, outTokens) {
-  var state = new StateInline(str, this, options, env, outTokens);
+ParserInline.prototype.parse = function (str, md, env, outTokens) {
+  var state = new this.State(str, md, env, outTokens);
 
   this.tokenize(state);
 };
 
 
+ParserInline.prototype.State = require('./rules_inline/state_inline');
+
+
 module.exports = ParserInline;
diff --git a/lib/rules_block/blockquote.js b/lib/rules_block/blockquote.js
index ca7b026..99d2ef3 100644
--- a/lib/rules_block/blockquote.js
+++ b/lib/rules_block/blockquote.js
@@ -15,7 +15,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
   // check the block quote marker
   if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   // we know that it's going to be a valid blockquote,
   // so no point trying to find the end of it in silent mode
@@ -37,7 +37,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
   oldTShift = [ state.tShift[startLine] ];
   state.tShift[startLine] = pos - state.bMarks[startLine];
 
-  terminatorRules = state.parser.ruler.getRules('blockquote');
+  terminatorRules = state.md.block.ruler.getRules('blockquote');
 
   // Search the end of the block
   //
@@ -113,7 +113,7 @@ module.exports = function blockquote(state, startLine, endLine, silent) {
     lines: lines = [ startLine, 0 ],
     level: state.level++
   });
-  state.parser.tokenize(state, startLine, nextLine);
+  state.md.block.tokenize(state, startLine, nextLine);
   state.tokens.push({
     type: 'blockquote_close',
     level: --state.level
diff --git a/lib/rules_block/deflist.js b/lib/rules_block/deflist.js
index 7fde6cc..996fb1e 100644
--- a/lib/rules_block/deflist.js
+++ b/lib/rules_block/deflist.js
@@ -71,7 +71,7 @@ module.exports = function deflist(state, startLine, endLine, silent) {
   contentStart = skipMarker(state, nextLine);
   if (contentStart < 0) { return false; }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   // Start list
   listTokIdx = state.tokens.length;
@@ -135,7 +135,7 @@ module.exports = function deflist(state, startLine, endLine, silent) {
       state.tight = true;
       state.parentType = 'deflist';
 
-      state.parser.tokenize(state, ddLine, endLine, true);
+      state.md.block.tokenize(state, ddLine, endLine, true);
 
       // If any of list item is tight, mark list as tight
       if (!state.tight || prevEmptyEnd) {
diff --git a/lib/rules_block/footnote.js b/lib/rules_block/footnote.js
index 7c8c5e4..2516f5a 100644
--- a/lib/rules_block/footnote.js
+++ b/lib/rules_block/footnote.js
@@ -13,7 +13,7 @@ module.exports = function footnote(state, startLine, endLine, silent) {
 
   if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; }
   if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   for (pos = start + 2; pos < max; pos++) {
     if (state.src.charCodeAt(pos) === 0x20) { return false; }
@@ -51,7 +51,7 @@ module.exports = function footnote(state, startLine, endLine, silent) {
     state.bMarks[startLine] -= state.blkIndent;
   }
 
-  state.parser.tokenize(state, startLine, endLine, true);
+  state.md.block.tokenize(state, startLine, endLine, true);
 
   state.parentType = oldParentType;
   state.blkIndent -= 4;
diff --git a/lib/rules_block/htmlblock.js b/lib/rules_block/htmlblock.js
index c585193..c7bd831 100644
--- a/lib/rules_block/htmlblock.js
+++ b/lib/rules_block/htmlblock.js
@@ -23,7 +23,7 @@ module.exports = function htmlblock(state, startLine, endLine, silent) {
 
   pos += shift;
 
-  if (!state.options.html) { return false; }
+  if (!state.md.options.html) { return false; }
 
   if (shift > 3 || pos + 2 >= max) { return false; }
 
diff --git a/lib/rules_block/list.js b/lib/rules_block/list.js
index 65b653b..d9d6ccb 100644
--- a/lib/rules_block/list.js
+++ b/lib/rules_block/list.js
@@ -114,7 +114,7 @@ module.exports = function list(state, startLine, endLine, silent) {
     return false;
   }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   // We should terminate list on style change. Remember first one to compare.
   markerCharCode = state.src.charCodeAt(posAfterMarker - 1);
@@ -150,7 +150,7 @@ module.exports = function list(state, startLine, endLine, silent) {
 
   nextLine = startLine;
   prevEmptyEnd = false;
-  terminatorRules = state.parser.ruler.getRules('list');
+  terminatorRules = state.md.block.ruler.getRules('list');
 
   while (nextLine < endLine) {
     contentStart = state.skipSpaces(posAfterMarker);
@@ -191,7 +191,7 @@ module.exports = function list(state, startLine, endLine, silent) {
     state.tight = true;
     state.parentType = 'list';
 
-    state.parser.tokenize(state, startLine, endLine, true);
+    state.md.block.tokenize(state, startLine, endLine, true);
 
     // If any of list item is tight, mark list as tight
     if (!state.tight || prevEmptyEnd) {
diff --git a/lib/rules_block/paragraph.js b/lib/rules_block/paragraph.js
index d25e5da..4f6c10e 100644
--- a/lib/rules_block/paragraph.js
+++ b/lib/rules_block/paragraph.js
@@ -12,7 +12,7 @@ module.exports = function paragraph(state, startLine/*, endLine*/) {
 
   // jump line-by-line until empty one or EOF
   if (nextLine < endLine && !state.isEmpty(nextLine)) {
-    terminatorRules = state.parser.ruler.getRules('paragraph');
+    terminatorRules = state.md.block.ruler.getRules('paragraph');
 
     for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
       // this would be a code block normally, but after paragraph
diff --git a/lib/rules_block/state_block.js b/lib/rules_block/state_block.js
index c59355f..018fd3f 100644
--- a/lib/rules_block/state_block.js
+++ b/lib/rules_block/state_block.js
@@ -3,15 +3,13 @@
 'use strict';
 
 
-function StateBlock(src, parser, options, env, tokens) {
+function StateBlock(src, md, env, tokens) {
   var ch, s, start, pos, len, indent, indent_found;
 
   this.src = src;
 
-  // Shortcuts to simplify nested calls
-  this.parser = parser;
-
-  this.options = options;
+  // link to parser instance
+  this.md     = md;
 
   this.env = env;
 
diff --git a/lib/rules_core/block.js b/lib/rules_core/block.js
index f3bbb6d..39b2d5e 100644
--- a/lib/rules_core/block.js
+++ b/lib/rules_core/block.js
@@ -12,6 +12,6 @@ module.exports = function block(state) {
     });
 
   } else {
-    state.block.parse(state.src, state.options, state.env, state.tokens);
+    state.md.block.parse(state.src, state.md, state.env, state.tokens);
   }
 };
diff --git a/lib/rules_core/inline.js b/lib/rules_core/inline.js
index 8b2280b..4c33d0d 100644
--- a/lib/rules_core/inline.js
+++ b/lib/rules_core/inline.js
@@ -7,7 +7,7 @@ module.exports = function inline(state) {
   for (i = 0, l = tokens.length; i < l; i++) {
     tok = tokens[i];
     if (tok.type === 'inline') {
-      state.inline.parse(tok.content, state.options, state.env, tok.children);
+      state.md.inline.parse(tok.content, state.md, state.env, tok.children);
     }
   }
 };
diff --git a/lib/rules_core/linkify.js b/lib/rules_core/linkify.js
index 6d805a5..907077e 100644
--- a/lib/rules_core/linkify.js
+++ b/lib/rules_core/linkify.js
@@ -63,7 +63,7 @@ module.exports = function linkify(state) {
       blockTokens = state.tokens,
       linkifier = null, links, autolinker;
 
-  if (!state.options.linkify) { return; }
+  if (!state.md.options.linkify) { return; }
 
   for (j = 0, l = blockTokens.length; j < l; j++) {
     if (blockTokens[j].type !== 'inline') { continue; }
@@ -117,7 +117,7 @@ module.exports = function linkify(state) {
 
         for (ln = 0; ln < links.length; ln++) {
 
-          if (!state.inline.validateLink(links[ln].url)) { continue; }
+          if (!state.md.inline.validateLink(links[ln].url)) { continue; }
 
           pos = text.indexOf(links[ln].text);
 
diff --git a/lib/rules_core/references.js b/lib/rules_core/references.js
index d64c46d..2558c8e 100644
--- a/lib/rules_core/references.js
+++ b/lib/rules_core/references.js
@@ -1,13 +1,12 @@
 'use strict';
 
 
-var StateInline          = require('../rules_inline/state_inline');
 var parseLinkDestination = require('../helpers/parse_link_destination');
 var parseLinkTitle       = require('../helpers/parse_link_title');
 var normalizeReference   = require('../helpers/normalize_reference');
 
 
-function parseReference(str, parser, options, env) {
+function parseReference(str, md, env) {
   var state, pos, code, start, href, title, label, ch, max,
       labelEnd = -1;
 
@@ -15,7 +14,7 @@ function parseReference(str, parser, options, env) {
 
   if (str.indexOf(']:') === -1) { return -1; }
 
-  state = new StateInline(str, parser, options, env, []);
+  state = new md.inline.State(str, md, env, []);
   max = state.posMax;
 
   for (pos = 1; pos < max; pos++) {
@@ -93,7 +92,7 @@ module.exports = function references(state) {
 
       content = tokens[i].content;
       while (content.length) {
-        pos = parseReference(content, state.inline, state.options, state.env);
+        pos = parseReference(content, state.md, state.env);
         if (pos < 0) { break; }
         content = content.slice(pos).trim();
       }
diff --git a/lib/rules_core/replacements.js b/lib/rules_core/replacements.js
index 1359058..8762c69 100644
--- a/lib/rules_core/replacements.js
+++ b/lib/rules_core/replacements.js
@@ -39,7 +39,7 @@ function replaceScopedAbbr(str) {
 module.exports = function replace(state) {
   var i, token, text, inlineTokens, blkIdx;
 
-  if (!state.options.typographer) { return; }
+  if (!state.md.options.typographer) { return; }
 
   for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
 
diff --git a/lib/rules_core/smartquotes.js b/lib/rules_core/smartquotes.js
index 05a954d..30a7d21 100644
--- a/lib/rules_core/smartquotes.js
+++ b/lib/rules_core/smartquotes.js
@@ -27,7 +27,7 @@ module.exports = function smartquotes(state) {
       canOpen, canClose, j, isSingle, blkIdx, tokens,
       stack;
 
-  if (!state.options.typographer) { return; }
+  if (!state.md.options.typographer) { return; }
 
   stack = [];
 
@@ -85,11 +85,14 @@ module.exports = function smartquotes(state) {
             if (item.single === isSingle && stack[j].level === thisLevel) {
               item = stack[j];
               if (isSingle) {
-                tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[2]);
-                token.content = replaceAt(token.content, t.index, state.options.quotes[3]);
+                tokens[item.token].content = replaceAt(
+                  tokens[item.token].content, item.pos, state.md.options.quotes[2]);
+                token.content = replaceAt(
+                  token.content, t.index, state.md.options.quotes[3]);
               } else {
-                tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[0]);
-                token.content = replaceAt(token.content, t.index, state.options.quotes[1]);
+                tokens[item.token].content = replaceAt(
+                  tokens[item.token].content, item.pos, state.md.options.quotes[0]);
+                token.content = replaceAt(token.content, t.index, state.md.options.quotes[1]);
               }
               stack.length = j;
               continue OUTER;
diff --git a/lib/rules_core/state_core.js b/lib/rules_core/state_core.js
new file mode 100644
index 0000000..86a5231
--- /dev/null
+++ b/lib/rules_core/state_core.js
@@ -0,0 +1,11 @@
+// Core state object
+//
+'use strict';
+
+module.exports = function StateCore(src, md, env) {
+  this.src = src;
+  this.env = env;
+  this.tokens = [];
+  this.inlineMode = false;
+  this.md = md; // link to parser instance
+};
diff --git a/lib/rules_inline/autolink.js b/lib/rules_inline/autolink.js
index 809ea18..dba5d87 100644
--- a/lib/rules_inline/autolink.js
+++ b/lib/rules_inline/autolink.js
@@ -27,7 +27,7 @@ module.exports = function autolink(state, silent) {
 
     url = linkMatch[0].slice(1, -1);
     fullUrl = normalizeLink(url);
-    if (!state.parser.validateLink(url)) { return false; }
+    if (!state.md.inline.validateLink(url)) { return false; }
 
     if (!silent) {
       state.push({
@@ -55,7 +55,7 @@ module.exports = function autolink(state, silent) {
     url = emailMatch[0].slice(1, -1);
 
     fullUrl = normalizeLink('mailto:' + url);
-    if (!state.parser.validateLink(fullUrl)) { return false; }
+    if (!state.md.inline.validateLink(fullUrl)) { return false; }
 
     if (!silent) {
       state.push({
diff --git a/lib/rules_inline/del.js b/lib/rules_inline/del.js
index b91b34c..15b3c9e 100644
--- a/lib/rules_inline/del.js
+++ b/lib/rules_inline/del.js
@@ -51,7 +51,7 @@ module.exports = function(state, silent) {
     return true;
   }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
   stack = Math.floor(startCount / 2);
   if (stack <= 0) { return false; }
   state.pos = start + startCount;
@@ -77,7 +77,7 @@ module.exports = function(state, silent) {
       continue;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found) {
@@ -92,7 +92,7 @@ module.exports = function(state, silent) {
 
   if (!silent) {
     state.push({ type: 'del_open', level: state.level++ });
-    state.parser.tokenize(state);
+    state.md.inline.tokenize(state);
     state.push({ type: 'del_close', level: --state.level });
   }
 
diff --git a/lib/rules_inline/emphasis.js b/lib/rules_inline/emphasis.js
index ad6e53d..3cc08d1 100644
--- a/lib/rules_inline/emphasis.js
+++ b/lib/rules_inline/emphasis.js
@@ -66,7 +66,7 @@ module.exports = function emphasis(state, silent) {
     return true;
   }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   state.pos = start + startCount;
   stack = [ startCount ];
@@ -107,7 +107,7 @@ module.exports = function emphasis(state, silent) {
       continue;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found) {
@@ -128,7 +128,7 @@ module.exports = function emphasis(state, silent) {
     }
     if (count % 2) { state.push({ type: 'em_open', level: state.level++ }); }
 
-    state.parser.tokenize(state);
+    state.md.inline.tokenize(state);
 
     if (count % 2) { state.push({ type: 'em_close', level: --state.level }); }
     for (count = startCount; count > 1; count -= 2) {
diff --git a/lib/rules_inline/footnote_inline.js b/lib/rules_inline/footnote_inline.js
index b8e9c4a..b7e9b98 100644
--- a/lib/rules_inline/footnote_inline.js
+++ b/lib/rules_inline/footnote_inline.js
@@ -16,7 +16,7 @@ module.exports = function footnote_inline(state, silent) {
   if (start + 2 >= max) { return false; }
   if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; }
   if (state.src.charCodeAt(start + 1) !== 0x5B/* [ */) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   labelStart = start + 2;
   labelEnd = parseLinkLabel(state, start + 1);
@@ -41,7 +41,7 @@ module.exports = function footnote_inline(state, silent) {
       level: state.level
     });
     oldLength = state.tokens.length;
-    state.parser.tokenize(state);
+    state.md.inline.tokenize(state);
     state.env.footnotes.list[footnoteId] = { tokens: state.tokens.splice(oldLength) };
   }
 
diff --git a/lib/rules_inline/footnote_ref.js b/lib/rules_inline/footnote_ref.js
index f0ab553..c2df23a 100644
--- a/lib/rules_inline/footnote_ref.js
+++ b/lib/rules_inline/footnote_ref.js
@@ -17,7 +17,7 @@ module.exports = function footnote_ref(state, silent) {
   if (!state.env.footnotes || !state.env.footnotes.refs) { return false; }
   if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; }
   if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   for (pos = start + 2; pos < max; pos++) {
     if (state.src.charCodeAt(pos) === 0x20) { return false; }
diff --git a/lib/rules_inline/htmltag.js b/lib/rules_inline/htmltag.js
index db3dd76..c0db00a 100644
--- a/lib/rules_inline/htmltag.js
+++ b/lib/rules_inline/htmltag.js
@@ -16,7 +16,7 @@ function isLetter(ch) {
 module.exports = function htmltag(state, silent) {
   var ch, match, max, pos = state.pos;
 
-  if (!state.options.html) { return false; }
+  if (!state.md.options.html) { return false; }
 
   // Check start
   max = state.posMax;
diff --git a/lib/rules_inline/ins.js b/lib/rules_inline/ins.js
index 2924ea7..107cf54 100644
--- a/lib/rules_inline/ins.js
+++ b/lib/rules_inline/ins.js
@@ -51,7 +51,7 @@ module.exports = function(state, silent) {
     return true;
   }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
   stack = Math.floor(startCount / 2);
   if (stack <= 0) { return false; }
   state.pos = start + startCount;
@@ -77,7 +77,7 @@ module.exports = function(state, silent) {
       continue;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found) {
@@ -92,7 +92,7 @@ module.exports = function(state, silent) {
 
   if (!silent) {
     state.push({ type: 'ins_open', level: state.level++ });
-    state.parser.tokenize(state);
+    state.md.inline.tokenize(state);
     state.push({ type: 'ins_close', level: --state.level });
   }
 
diff --git a/lib/rules_inline/links.js b/lib/rules_inline/links.js
index 92622fa..f71c833 100644
--- a/lib/rules_inline/links.js
+++ b/lib/rules_inline/links.js
@@ -6,7 +6,6 @@ var parseLinkLabel       = require('../helpers/parse_link_label');
 var parseLinkDestination = require('../helpers/parse_link_destination');
 var parseLinkTitle       = require('../helpers/parse_link_title');
 var normalizeReference   = require('../helpers/normalize_reference');
-var StateInline          = require('../rules_inline/state_inline');
 
 
 module.exports = function links(state, silent) {
@@ -31,7 +30,7 @@ module.exports = function links(state, silent) {
   }
 
   if (marker !== 0x5B/* [ */) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   labelStart = start + 1;
   labelEnd = parseLinkLabel(state, start, !isImage);
@@ -140,14 +139,13 @@ module.exports = function links(state, silent) {
     state.posMax = labelEnd;
 
     if (isImage) {
-      var newState = new StateInline(
+      var newState = new state.md.inline.State(
         state.src.slice(labelStart, labelEnd),
-        state.parser,
-        state.options,
+        state.md,
         state.env,
         tokens = []
       );
-      newState.parser.tokenize(newState);
+      newState.md.inline.tokenize(newState);
 
       state.push({
         type: 'image',
@@ -164,7 +162,7 @@ module.exports = function links(state, silent) {
         title: title,
         level: state.level++
       });
-      state.parser.tokenize(state);
+      state.md.inline.tokenize(state);
       state.push({ type: 'link_close', level: --state.level });
     }
   }
diff --git a/lib/rules_inline/mark.js b/lib/rules_inline/mark.js
index e2c88dd..64d4c90 100644
--- a/lib/rules_inline/mark.js
+++ b/lib/rules_inline/mark.js
@@ -51,7 +51,7 @@ module.exports = function(state, silent) {
     return true;
   }
 
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
   stack = Math.floor(startCount / 2);
   if (stack <= 0) { return false; }
   state.pos = start + startCount;
@@ -77,7 +77,7 @@ module.exports = function(state, silent) {
       continue;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found) {
@@ -92,7 +92,7 @@ module.exports = function(state, silent) {
 
   if (!silent) {
     state.push({ type: 'mark_open', level: state.level++ });
-    state.parser.tokenize(state);
+    state.md.inline.tokenize(state);
     state.push({ type: 'mark_close', level: --state.level });
   }
 
diff --git a/lib/rules_inline/state_inline.js b/lib/rules_inline/state_inline.js
index 954c562..666d5f1 100644
--- a/lib/rules_inline/state_inline.js
+++ b/lib/rules_inline/state_inline.js
@@ -3,12 +3,12 @@
 'use strict';
 
 
-function StateInline(src, parserInline, options, env, outTokens) {
+function StateInline(src, md, env, outTokens) {
   this.src = src;
   this.env = env;
-  this.options = options;
-  this.parser = parserInline;
+  this.md = md;
   this.tokens = outTokens;
+
   this.pos = 0;
   this.posMax = this.src.length;
   this.level = 0;
diff --git a/lib/rules_inline/sub.js b/lib/rules_inline/sub.js
index 667539f..ccaf6d7 100644
--- a/lib/rules_inline/sub.js
+++ b/lib/rules_inline/sub.js
@@ -14,7 +14,7 @@ module.exports = function sub(state, silent) {
   if (state.src.charCodeAt(start) !== 0x7E/* ~ */) { return false; }
   if (silent) { return false; } // don't run any pairs in validation mode
   if (start + 2 >= max) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   state.pos = start + 1;
 
@@ -24,7 +24,7 @@ module.exports = function sub(state, silent) {
       break;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found || start + 1 === state.pos) {
diff --git a/lib/rules_inline/sup.js b/lib/rules_inline/sup.js
index 4189d0a..d5d0ea3 100644
--- a/lib/rules_inline/sup.js
+++ b/lib/rules_inline/sup.js
@@ -14,7 +14,7 @@ module.exports = function sup(state, silent) {
   if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; }
   if (silent) { return false; } // don't run any pairs in validation mode
   if (start + 2 >= max) { return false; }
-  if (state.level >= state.options.maxNesting) { return false; }
+  if (state.level >= state.md.options.maxNesting) { return false; }
 
   state.pos = start + 1;
 
@@ -24,7 +24,7 @@ module.exports = function sup(state, silent) {
       break;
     }
 
-    state.parser.skipToken(state);
+    state.md.inline.skipToken(state);
   }
 
   if (!found || start + 1 === state.pos) {