mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	This commit was originally automatically generated using `tools/lint --only=eslint --fix`. It was then modified by tabbott to contain only changes to a set of files that are unlikely to result in significant merge conflicts with any open pull request, excluding about 20 files. His plan is to merge the remaining changes with more precise care, potentially involving merging parts of conflicting pull requests before running the `eslint --fix` operation. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
		
			
				
	
	
		
			189 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// Parsing routine that can be dropped in to message parsing
 | 
						|
// and formats code blocks
 | 
						|
//
 | 
						|
// This supports arbitrarily nested code blocks as well as
 | 
						|
// auto-completing code blocks missing a trailing close.
 | 
						|
 | 
						|
// See backend fenced_code.py:71 for associated regexp
 | 
						|
const fencestr = "^(~{3,}|`{3,})"            + // Opening Fence
 | 
						|
               "[ ]*"                      + // Spaces
 | 
						|
               "("                         +
 | 
						|
                   "\\{?\\.?"              +
 | 
						|
                   "([a-zA-Z0-9_+-./#]*)"  + // Language
 | 
						|
                   "\\}?"                  +
 | 
						|
               "[ ]*"                      + // Spaces
 | 
						|
               ")$";
 | 
						|
const fence_re = new RegExp(fencestr);
 | 
						|
 | 
						|
// Default stashing function does nothing
 | 
						|
let stash_func = function (text) {
 | 
						|
    return text;
 | 
						|
};
 | 
						|
 | 
						|
let escape_func = function (text) {
 | 
						|
    return text;
 | 
						|
};
 | 
						|
 | 
						|
function wrap_code(code) {
 | 
						|
    // Trim trailing \n until there's just one left
 | 
						|
    // This mirrors how pygments handles code input
 | 
						|
    code += '\n';
 | 
						|
    while (code.length > 2 && code.substr(code.length - 2) === '\n\n') {
 | 
						|
        code = code.substring(0, code.length - 1);
 | 
						|
    }
 | 
						|
    return '<div class="codehilite"><pre><span></span>' + escape_func(code) + '</pre></div>\n';
 | 
						|
}
 | 
						|
 | 
						|
function wrap_quote(text) {
 | 
						|
    const paragraphs = text.split('\n\n');
 | 
						|
    const quoted_paragraphs = [];
 | 
						|
    // Prefix each quoted paragraph with > at the
 | 
						|
    // beginning of each line
 | 
						|
    _.each(paragraphs, function (paragraph) {
 | 
						|
        const lines = paragraph.split('\n');
 | 
						|
        quoted_paragraphs.push(_.map(
 | 
						|
            _.reject(lines, function (line) { return line === ''; }),
 | 
						|
            function (line) { return '> ' + line; }).join('\n'));
 | 
						|
    });
 | 
						|
    return quoted_paragraphs.join('\n\n');
 | 
						|
}
 | 
						|
 | 
						|
function wrap_tex(tex) {
 | 
						|
    try {
 | 
						|
        return katex.renderToString(tex, {
 | 
						|
            displayMode: true,
 | 
						|
        });
 | 
						|
    } catch (ex) {
 | 
						|
        return '<span class="tex-error">' + escape_func(tex) + '</span>';
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
exports.set_stash_func = function (stash_handler) {
 | 
						|
    stash_func = stash_handler;
 | 
						|
};
 | 
						|
 | 
						|
exports.set_escape_func = function (escape) {
 | 
						|
    escape_func = escape;
 | 
						|
};
 | 
						|
 | 
						|
exports.process_fenced_code = function (content) {
 | 
						|
    const input = content.split('\n');
 | 
						|
    const output = [];
 | 
						|
    const handler_stack = [];
 | 
						|
    let consume_line;
 | 
						|
 | 
						|
    function handler_for_fence(output_lines, fence, lang) {
 | 
						|
        // lang is ignored except for 'quote', as we
 | 
						|
        // don't do syntax highlighting yet
 | 
						|
        return (function () {
 | 
						|
            const lines = [];
 | 
						|
            if (lang === 'quote') {
 | 
						|
                return {
 | 
						|
                    handle_line: function (line) {
 | 
						|
                        if (line === fence) {
 | 
						|
                            this.done();
 | 
						|
                        } else {
 | 
						|
                            consume_line(lines, line);
 | 
						|
                        }
 | 
						|
                    },
 | 
						|
 | 
						|
                    done: function () {
 | 
						|
                        const text = wrap_quote(lines.join('\n'));
 | 
						|
                        output_lines.push('');
 | 
						|
                        output_lines.push(text);
 | 
						|
                        output_lines.push('');
 | 
						|
                        handler_stack.pop();
 | 
						|
                    },
 | 
						|
                };
 | 
						|
            }
 | 
						|
 | 
						|
            if (lang === 'math' || lang === 'tex' || lang === 'latex') {
 | 
						|
                return {
 | 
						|
                    handle_line: function (line) {
 | 
						|
                        if (line === fence) {
 | 
						|
                            this.done();
 | 
						|
                        } else {
 | 
						|
                            lines.push(line);
 | 
						|
                        }
 | 
						|
                    },
 | 
						|
 | 
						|
                    done: function () {
 | 
						|
                        const text = wrap_tex(lines.join('\n'));
 | 
						|
                        const placeholder = stash_func(text, true);
 | 
						|
                        output_lines.push('');
 | 
						|
                        output_lines.push(placeholder);
 | 
						|
                        output_lines.push('');
 | 
						|
                        handler_stack.pop();
 | 
						|
                    },
 | 
						|
                };
 | 
						|
            }
 | 
						|
 | 
						|
            return {
 | 
						|
                handle_line: function (line) {
 | 
						|
                    if (line === fence) {
 | 
						|
                        this.done();
 | 
						|
                    } else {
 | 
						|
                        lines.push(util.rtrim(line));
 | 
						|
                    }
 | 
						|
                },
 | 
						|
 | 
						|
                done: function () {
 | 
						|
                    const text = wrap_code(lines.join('\n'));
 | 
						|
                    // insert safe HTML that is passed through the parsing
 | 
						|
                    const placeholder = stash_func(text, true);
 | 
						|
                    output_lines.push('');
 | 
						|
                    output_lines.push(placeholder);
 | 
						|
                    output_lines.push('');
 | 
						|
                    handler_stack.pop();
 | 
						|
                },
 | 
						|
            };
 | 
						|
        }());
 | 
						|
    }
 | 
						|
 | 
						|
    function default_hander() {
 | 
						|
        return {
 | 
						|
            handle_line: function (line) {
 | 
						|
                consume_line(output, line);
 | 
						|
            },
 | 
						|
            done: function () {
 | 
						|
                handler_stack.pop();
 | 
						|
            },
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    consume_line = function consume_line(output_lines, line) {
 | 
						|
        const match = fence_re.exec(line);
 | 
						|
        if (match) {
 | 
						|
            const fence = match[1];
 | 
						|
            const lang = match[3];
 | 
						|
            const handler = handler_for_fence(output_lines, fence, lang);
 | 
						|
            handler_stack.push(handler);
 | 
						|
        } else {
 | 
						|
            output_lines.push(line);
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    const current_handler = default_hander();
 | 
						|
    handler_stack.push(current_handler);
 | 
						|
 | 
						|
    _.each(input, function (line) {
 | 
						|
        const handler = handler_stack[handler_stack.length - 1];
 | 
						|
        handler.handle_line(line);
 | 
						|
    });
 | 
						|
 | 
						|
    // Clean up all trailing blocks by letting them
 | 
						|
    // insert closing fences
 | 
						|
    while (handler_stack.length !== 0) {
 | 
						|
        const handler = handler_stack[handler_stack.length - 1];
 | 
						|
        handler.done();
 | 
						|
    }
 | 
						|
 | 
						|
    if (output.length > 2 && output[output.length - 2] !== '') {
 | 
						|
        output.push('');
 | 
						|
    }
 | 
						|
 | 
						|
    return output.join('\n');
 | 
						|
};
 | 
						|
 | 
						|
window.fenced_code = exports;
 |