org.unlaxer.tinyexpression.model.CalculatorEditableLineModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tinyExpression Show documentation
Show all versions of tinyExpression Show documentation
TinyExpression implemented with Unlaxer
package org.unlaxer.tinyexpression.model;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;
import org.unlaxer.EnclosureDirection;
import org.unlaxer.Range;
import org.unlaxer.Token;
import org.unlaxer.TokenEnclosureUtil;
import org.unlaxer.parser.ParsersSpecifier;
import org.unlaxer.tinyexpression.CalculateResult;
import org.unlaxer.tinyexpression.CalculationContext;
import org.unlaxer.tinyexpression.Calculator;
import org.unlaxer.tinyexpression.parser.ExpressionTypes;
import org.unlaxer.tinyexpression.parser.NumberExpressionParser;
import org.unlaxer.tinyexpression.parser.NumberFactorParser;
import org.unlaxer.tinyexpression.parser.NumberTermParser;
import org.unlaxer.util.StringUtil;
public class CalculatorEditableLineModel implements EditableLineModel{
public static final ParsersSpecifier enclosureMatchers=
new ParsersSpecifier(
NumberExpressionParser.class,
NumberTermParser.class,
NumberFactorParser.class
);
final Calculator calculator;
CalculationContext calculateContext;
public final Deque calculations = new ArrayDeque();
public final Deque edits = new ArrayDeque();
public CalculatorEditableLineModel(Calculator calculator , CalculationContext calculateContext) {
this(calculator , calculateContext , "");
}
public CalculatorEditableLineModel(Calculator calculator , CalculationContext calculateContext , String formula) {
super();
this.calculateContext = calculateContext;
this.calculator = calculator;
CalculateResult calculateResult = calculator.calculate(calculateContext,formula,ExpressionTypes._float);
EditHistory editHistory =
new EditHistory(EditAction.of(ActionType.initialized), 0 , calculateContext, calculateResult);
edits.add(editHistory);
editHistory =
new EditHistory(new EditAction(formula) ,
formula.length(), calculateContext, calculateResult);
edits.add(editHistory);
}
//
// modify formula
//
@Override
public DeleteBehavior backSpace() {
// first implementation -> delete force
// TODO second implementation -> if ast was broken when delete token then suggests operation(change function , delete , etc)
boolean success = backspace(getPosition());
DeleteBehavior deleteBehavior = new DeleteBehavior();
deleteBehavior.deleted = success;
return deleteBehavior;
}
@Override
public DeleteBehavior delete() {
// first implementation -> delete force
// TODO second implementation -> if ast was broken when delete token then suggests operation(change function , delete , etc)
boolean success = delete(getPosition());
DeleteBehavior deleteBehavior = new DeleteBehavior();
deleteBehavior.deleted = success;
return deleteBehavior;
}
@Override
public boolean insert(String part) {
//first implementation -> do simple !
String formulaString = getFormulaString();
int position = getPosition();
Optional selection = getSelection();
Range tokenRange = selection.isPresent() ?
selection.get().tokenRange :
new Range(position , position+1);
String deleted = StringUtil.deleteAndInsert(formulaString, tokenRange , part);
EditHistory createInsertEditHistory = createInsertEditHistory(deleted , tokenRange, position, part);
edits.add(createInsertEditHistory);
return true;
}
boolean backspace(int position){
return delete(ActionType.backSpace , position-1);
}
boolean delete(int position){
return delete(ActionType.delete, position);
}
boolean delete(ActionType actionType , int position){
String formulaString = getFormulaString();
Optional selection = getSelection();
if(selection.isPresent()){
Range tokenRange = selection.get().tokenRange;
String deleted = StringUtil.delete(formulaString, tokenRange);
return addDeleteAction(actionType, position, formulaString , deleted , Optional.of(tokenRange));
}else{
String deleted = StringUtil.delete(formulaString , position);
return addDeleteAction(actionType, position, formulaString, deleted , Optional.empty());
}
}
private boolean addDeleteAction(
ActionType actionType, int position, String formulaString, String deleted ,Optional effectedRange) {
boolean success = deleted.length() != formulaString.length();
if(success){
Range range = effectedRange.orElse(new Range(position , position +1));
EditHistory createEditHistory = createEditHistory(actionType , deleted, range , position);
edits.add(createEditHistory);
}
return success;
}
EditHistory createEditHistory(ActionType actionType , String formula ,Range range ,int position){
CalculateResult calculateResult = calculator.calculate(calculateContext,formula , ExpressionTypes._float);
EditHistory editHistory =
new EditHistory(new EditAction(actionType , range), position , calculateContext, calculateResult);
return editHistory;
}
EditHistory createInsertEditHistory(String formula ,Range range ,int position , String insertion){
CalculateResult calculateResult = calculator.calculate(calculateContext,formula , ExpressionTypes._float);
EditHistory editHistory =
new EditHistory(new EditAction(insertion,range), position , calculateContext, calculateResult);
return editHistory;
}
//
// position
//
@Override
public boolean cursorRight() {
Optional currentSelection = getSelection();
if(currentSelection.isPresent()){
updatePosition(ActionType.cursorRight , currentSelection.get().tokenRange.endIndexExclusive);
return true;
}
String formulaString = getFormulaString();
int position = getPosition();
boolean movable = formulaString.length() > position;
position = movable ? ++position : position;
updatePosition(ActionType.cursorRight , position);
return movable;
}
@Override
public boolean cursorLeft() {
Optional currentSelection = getSelection();
if(currentSelection.isPresent()){
int position = Math.max(0, currentSelection.get().tokenRange.startIndexInclusive-1);
updatePosition(ActionType.cursorLeft , position);
return true;
}
int position = getPosition();
boolean movable = 0 < position;
position = movable ? --position : position;
updatePosition(ActionType.cursorLeft, position);
return movable;
}
@Override
public boolean home() {
int position = getPosition();
boolean movable = 0 < position;
position = 0;
updatePosition(ActionType.home , position);
return movable;
}
@Override
public boolean end() {
String formulaString = getFormulaString();
int position = getPosition();
boolean movable = formulaString.length() > position;
position = formulaString.length();
updatePosition(ActionType.end, position);
return movable;
}
void updatePosition(ActionType actionType , int position){
EditHistory updated = getCurrent().clone(EditAction.of(actionType));
updated.caretPosition = position;
edits.push(updated);
}
//
// select
//
@Override
public Optional selectEnclosure(EnclosureDirection enclosureDirection) {
Optional rootToken = getCurrent().calculateResult.tokenAst;
if(false == rootToken.isPresent()){
return Optional.empty();
}
int position = getPosition();
Optional selected =
TokenEnclosureUtil.getEnclosureWithToken(rootToken.get(),
enclosureDirection, position, getSelection(), enclosureMatchers);
if(selected.isPresent()){
EditHistory clone = getCurrent().clone(EditAction.of(ActionType.of(enclosureDirection)));
clone.select = selected;
edits.add(clone);
return selected;
}
return Optional.empty();
}
@Override
public Optional getSelection() {
return getCurrent().select;
}
//
// history
//
@Override
public boolean addCalculateHistory() {
EditHistory current = getCurrent();
if(current.calculateResult.success){
calculations.add(current);
}
return false;
}
EditHistory getCurrent(){
return edits.peekFirst();
}
String getFormulaString(){
return getCurrent().calculateResult.parseContext.source.toString();
}
int getPosition(){
return getCurrent().caretPosition;
}
}