Commit 78aa8c16 authored by Sean McGivern's avatar Sean McGivern

Escape autocomplete results for Markdown

A label name can contain a `_`, `~~`, or other Markdown-significant
characters. But label references are processed _after_ Markdown processing has
run, so we can't easily fix this on the backend.

We can make it more convenient, though, by changing the frontend to escape these
characters so they aren't processed as Markdown, when we insert them from
autocomplete.
parent d7a9df68
...@@ -54,6 +54,7 @@ class GfmAutoComplete { ...@@ -54,6 +54,7 @@ class GfmAutoComplete {
alias: 'commands', alias: 'commands',
searchKey: 'search', searchKey: 'search',
skipSpecialCharacterTest: true, skipSpecialCharacterTest: true,
skipMarkdownCharacterTest: true,
data: GfmAutoComplete.defaultLoadingData, data: GfmAutoComplete.defaultLoadingData,
displayTpl(value) { displayTpl(value) {
if (GfmAutoComplete.isLoading(value)) return GfmAutoComplete.Loading.template; if (GfmAutoComplete.isLoading(value)) return GfmAutoComplete.Loading.template;
...@@ -376,15 +377,23 @@ class GfmAutoComplete { ...@@ -376,15 +377,23 @@ class GfmAutoComplete {
return $.fn.atwho.default.callbacks.filter(query, data, searchKey); return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
}, },
beforeInsert(value) { beforeInsert(value) {
let resultantValue = value; let withoutAt = value.substring(1);
const at = value.charAt();
if (value && !this.setting.skipSpecialCharacterTest) { if (value && !this.setting.skipSpecialCharacterTest) {
const withoutAt = value.substring(1); const regex = at === '~' ? /\W|^\d+$/ : /\W/;
const regex = value.charAt() === '~' ? /\W|^\d+$/ : /\W/;
if (withoutAt && regex.test(withoutAt)) { if (withoutAt && regex.test(withoutAt)) {
resultantValue = `${value.charAt()}"${withoutAt}"`; withoutAt = `"${withoutAt}"`;
} }
} }
return resultantValue;
// We can ignore this for quick actions because they are processed
// before Markdown.
if (!this.setting.skipMarkdownCharacterTest) {
withoutAt = withoutAt.replace(/([~\-_*`])/g, '\\$&');
}
return `${at}${withoutAt}`;
}, },
matcher(flag, subtext) { matcher(flag, subtext) {
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers); const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
......
---
title: Escape Markdown characters properly when using autocomplete
merge_request:
author:
type: fixed
...@@ -81,13 +81,21 @@ describe('GfmAutoComplete', function () { ...@@ -81,13 +81,21 @@ describe('GfmAutoComplete', function () {
}); });
it('should quote if value contains any non-alphanumeric characters', () => { it('should quote if value contains any non-alphanumeric characters', () => {
expect(beforeInsert(atwhoInstance, '~label-20')).toBe('~"label-20"'); expect(beforeInsert(atwhoInstance, '~label-20')).toBe('~"label\\-20"');
expect(beforeInsert(atwhoInstance, '~label 20')).toBe('~"label 20"'); expect(beforeInsert(atwhoInstance, '~label 20')).toBe('~"label 20"');
}); });
it('should quote integer labels', () => { it('should quote integer labels', () => {
expect(beforeInsert(atwhoInstance, '~1234')).toBe('~"1234"'); expect(beforeInsert(atwhoInstance, '~1234')).toBe('~"1234"');
}); });
it('should escape Markdown emphasis characters, except in the first character', () => {
expect(beforeInsert(atwhoInstance, '@_group')).toEqual('@\\_group');
expect(beforeInsert(atwhoInstance, '~_bug')).toEqual('~\\_bug');
expect(beforeInsert(atwhoInstance, '~a `bug`')).toEqual('~"a \\`bug\\`"');
expect(beforeInsert(atwhoInstance, '~a ~bug')).toEqual('~"a \\~bug"');
expect(beforeInsert(atwhoInstance, '~a **bug')).toEqual('~"a \\*\\*bug"');
});
}); });
describe('DefaultOptions.matcher', function () { describe('DefaultOptions.matcher', function () {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment