/* * MathJaxUtil.java * * Copyright (C) 2009-16 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.common.mathjax; import java.util.ArrayList; import java.util.List; import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay; import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Position; import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Range; import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Token; import org.rstudio.studio.client.workbench.views.source.editors.text.ace.TokenIterator; public class MathJaxUtil { public static Range getLatexRange(DocDisplay docDisplay) { return getLatexRange(docDisplay, docDisplay.getCursorPosition()); } public static Range getLatexRange(DocDisplay docDisplay, Position pos) { if (pos == null) pos = docDisplay.getCursorPosition(); // find start of latex block TokenIterator startIt = docDisplay.createTokenIterator(); // avoid case where token iterator moves back across lines // to discover a latex block Token startToken = startIt.moveToPosition(pos); if (startToken != null && startToken.hasAllTypes("latex", "end") && startIt.getCurrentTokenRow() != pos.getRow()) { return null; } for (Token token = startIt.moveToPosition(pos); token != null; token = startIt.stepBackward()) { if (!token.hasType("latex")) return null; if (token.hasType("begin")) break; } // find end of latex block TokenIterator endIt = docDisplay.createTokenIterator(); for (Token token = endIt.moveToPosition(pos); token != null; token = endIt.stepForward()) { if (!token.hasType("latex")) return null; if (token.hasType("end")) break; } Token lhsToken = startIt.getCurrentToken(); if (lhsToken == null || !lhsToken.hasAllTypes("latex", "begin")) return null; Token rhsToken = endIt.getCurrentToken(); if (rhsToken == null || !rhsToken.hasAllTypes("latex", "end")) return null; Position startPos = startIt.getCurrentTokenPosition(); Position endPos = endIt.getCurrentTokenPosition(); endPos.setColumn(endPos.getColumn() + endIt.getCurrentToken().getValue().length()); return Range.fromPoints(startPos, endPos); } public static boolean isSelectionWithinLatexChunk(DocDisplay docDisplay) { Range range = getLatexRange(docDisplay); if (range == null) return false; Token startToken = docDisplay.getTokenAt(range.getStart().getRow(), 0); if (startToken == null || !startToken.getValue().equals("$$")) return false; Token endToken = docDisplay.getTokenAt(range.getEnd().getRow(), 0); if (endToken == null || !endToken.getValue().equals("$$")) return false; return true; } public static List<Range> findLatexChunks(DocDisplay docDisplay) { docDisplay.tokenizeDocument(); List<Range> ranges = new ArrayList<Range>(); Position startPos = null; for (int i = 0, n = docDisplay.getRowCount(); i < n; i++) { Position pos = Position.create(i, 0); Token token = docDisplay.getTokenAt(Position.create(i, 0)); if (token == null) continue; if (token.hasAllTypes("latex", "begin") && token.getValue().equals("$$")) { startPos = pos; // get the length of this line to see if it could be an inline // LaTeX chunk (e.g. $$ x = y $$) int length = docDisplay.getLength(i); if (length < 5) continue; // get the last token on the row; if it's a LaTeX end token then // consider the row to be an inline LaTeX chunk Token endLineToken = docDisplay.getTokenAt( Position.create(i, docDisplay.getLength(i))); if (endLineToken != null && endLineToken.hasAllTypes("latex", "end")) { ranges.add(Range.fromPoints(startPos, Position.create(i, length))); } continue; } if (token.hasAllTypes("latex", "end") && token.getValue().equals("$$")) { ranges.add(Range.fromPoints(startPos, Position.create(i, 2))); continue; } } return ranges; } }