Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gfm] Prevent markdown mode from parsing formatting within vanilla links (closes #4079) #4106

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 10 additions & 3 deletions addon/mode/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// can override the style of text.
// If state.overlay.freezeBaseState is true,
// only the overlay mode will parse the text
// until state.overlay.freezeBaseState is set to false.
// Otherwise, both modes get to parse all of the text,
// but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are
// combined.
Expand Down Expand Up @@ -47,7 +51,7 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
state.basePos = state.overlayPos = stream.start;
}

if (stream.start == state.basePos) {
if (stream.start == state.basePos && !state.overlay.freezeBaseState) {
state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos;
}
Expand All @@ -56,6 +60,9 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos;
}
if (state.overlay.freezeBaseState) {
state.basePos = state.overlayPos;
}
stream.pos = Math.min(state.basePos, state.overlayPos);

// state.overlay.combineTokens always takes precedence over combine,
Expand Down
13 changes: 5 additions & 8 deletions mode/gfm/gfm.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,13 @@ CodeMirror.defineMode("gfm", function(config, modeConfig) {
return {
code: false,
codeBlock: false,
ateSpace: false
};
},
copyState: function(s) {
return {
code: s.code,
codeBlock: s.codeBlock,
ateSpace: s.ateSpace
ateSpace: false,
freezeBaseState: false
};
},
token: function(stream, state) {
state.combineTokens = null;
state.freezeBaseState = false;

// Hack to prevent formatting override inside code blocks (block and inline)
if (state.codeBlock) {
Expand Down Expand Up @@ -104,6 +99,8 @@ CodeMirror.defineMode("gfm", function(config, modeConfig) {
// And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
// And then limited url schemes to the CommonMark list, so foo:bar isn't matched as a URL
state.combineTokens = true;
// #4079: Freeze base state until after URL to avoid parsing formatting within link
state.freezeBaseState = true;
return "link";
}
stream.next();
Expand Down
9 changes: 9 additions & 0 deletions mode/gfm/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@
MT("vanillaLinkEmphasis",
"foo [em *][em&link http://www.example.com/index.html][em *] bar");

MT("vanillaLinkUnderscoreInParam",
"foo [link http://www.example.com/?bar_baz] hello");

MT("vanillaLinkUnderscoreStartsParam",
"foo [link http://www.example.com/?_bar] hello");

MT("vanillaLinkUnderscoreStartsParamNoSlash",
"foo [link http://www.example.com?_bar] hello");

MT("notALink",
"foo asfd:asdf bar");

Expand Down