blob: 75369e83a5249e038d7d65152a5522e44707c5bc [file] [log] [blame]
// Parser MathBlock
var latexMathParser = (function() {
function commandToBlock(cmd) { // can also take in a Fragment
var block = MathBlock();
cmd.adopt(block, 0, 0);
return block;
}
function joinBlocks(blocks) {
var firstBlock = blocks[0] || MathBlock();
for (var i = 1; i < blocks.length; i += 1) {
blocks[i].children().adopt(firstBlock, firstBlock.ends[R], 0);
}
return firstBlock;
}
var string = Parser.string;
var regex = Parser.regex;
var letter = Parser.letter;
var any = Parser.any;
var optWhitespace = Parser.optWhitespace;
var succeed = Parser.succeed;
var fail = Parser.fail;
// Parsers yielding either MathCommands, or Fragments of MathCommands
// (either way, something that can be adopted by a MathBlock)
var variable = letter.map(function(c) { return Letter(c); });
var symbol = regex(/^[^${}\\_^]/).map(function(c) { return VanillaSymbol(c); });
var controlSequence =
regex(/^[^\\a-eg-zA-Z]/) // hotfix #164; match MathBlock::write
.or(string('\\').then(
regex(/^[a-z]+/i)
.or(regex(/^\s+/).result(' '))
.or(any)
)).then(function(ctrlSeq) {
var cmdKlass = LatexCmds[ctrlSeq];
if (cmdKlass) {
return cmdKlass(ctrlSeq).parser();
}
else {
return fail('unknown command: \\'+ctrlSeq);
}
})
;
var command =
controlSequence
.or(variable)
.or(symbol)
;
// Parsers yielding MathBlocks
var mathGroup = string('{').then(function() { return mathSequence; }).skip(string('}'));
var mathBlock = optWhitespace.then(mathGroup.or(command.map(commandToBlock)));
var mathSequence = mathBlock.many().map(joinBlocks).skip(optWhitespace);
var optMathBlock =
string('[').then(
mathBlock.then(function(block) {
return block.join('latex') !== ']' ? succeed(block) : fail();
})
.many().map(joinBlocks).skip(optWhitespace)
).skip(string(']'))
;
var latexMath = mathSequence;
latexMath.block = mathBlock;
latexMath.optBlock = optMathBlock;
return latexMath;
})();
Controller.open(function(_, super_) {
_.exportLatex = function() {
return this.root.latex().replace(/(\\[a-z]+) (?![a-z])/ig,'$1');
};
_.writeLatex = function(latex) {
var cursor = this.notify('edit').cursor;
var all = Parser.all;
var eof = Parser.eof;
var block = latexMathParser.skip(eof).or(all.result(false)).parse(latex);
if (block && !block.isEmpty()) {
block.children().adopt(cursor.parent, cursor[L], cursor[R]);
var jQ = block.jQize();
jQ.insertBefore(cursor.jQ);
cursor[L] = block.ends[R];
block.finalizeInsert(cursor.options, cursor);
if (block.ends[R][R].siblingCreated) block.ends[R][R].siblingCreated(cursor.options, L);
if (block.ends[L][L].siblingCreated) block.ends[L][L].siblingCreated(cursor.options, R);
cursor.parent.bubble('reflow');
}
return this;
};
_.renderLatexMath = function(latex) {
var root = this.root, cursor = this.cursor;
var all = Parser.all;
var eof = Parser.eof;
var block = latexMathParser.skip(eof).or(all.result(false)).parse(latex);
root.eachChild('postOrder', 'dispose');
root.ends[L] = root.ends[R] = 0;
if (block) {
block.children().adopt(root, 0, 0);
}
var jQ = root.jQ;
if (block) {
var html = block.join('html');
jQ.html(html);
root.jQize(jQ.children());
root.finalizeInsert(cursor.options);
}
else {
jQ.empty();
}
delete cursor.selection;
cursor.insAtRightEnd(root);
};
_.renderLatexText = function(latex) {
var root = this.root, cursor = this.cursor;
root.jQ.children().slice(1).remove();
root.eachChild('postOrder', 'dispose');
root.ends[L] = root.ends[R] = 0;
delete cursor.selection;
cursor.show().insAtRightEnd(root);
var regex = Parser.regex;
var string = Parser.string;
var eof = Parser.eof;
var all = Parser.all;
// Parser RootMathCommand
var mathMode = string('$').then(latexMathParser)
// because TeX is insane, math mode doesn't necessarily
// have to end. So we allow for the case that math mode
// continues to the end of the stream.
.skip(string('$').or(eof))
.map(function(block) {
// HACK FIXME: this shouldn't have to have access to cursor
var rootMathCommand = RootMathCommand(cursor);
rootMathCommand.createBlocks();
var rootMathBlock = rootMathCommand.ends[L];
block.children().adopt(rootMathBlock, 0, 0);
return rootMathCommand;
})
;
var escapedDollar = string('\\$').result('$');
var textChar = escapedDollar.or(regex(/^[^$]/)).map(VanillaSymbol);
var latexText = mathMode.or(textChar).many();
var commands = latexText.skip(eof).or(all.result(false)).parse(latex);
if (commands) {
for (var i = 0; i < commands.length; i += 1) {
commands[i].adopt(root, root.ends[R], 0);
}
root.jQize().appendTo(root.jQ);
root.finalizeInsert(cursor.options);
}
};
});