import * as CodeMirror from "codemirror" ; CodeMirror . defineMode < ModeState > ( "filter-mode" , function ( config , modeOptions ? ) { function getNextFieldState ( fieldState ) { if ( fieldState == FieldStates . category ) return FieldStates . operator ; if ( fieldState == FieldStates . operator ) return FieldStates . value ; if ( fieldState == FieldStates . value ) return FieldStates . category ; } function setNextFieldState ( state ) { var nextFieldState = getNextFieldState ( state . fieldState ) ; var currentFieldState = state . fieldState ; state . fieldState = nextFieldState ; return currentFieldState . toString ( ) ; } function isEmpty ( char ) { return char == " " || char == "\r" || char == "\n" || char == "\t" ; } return { startState : function ( ) : ModeState { return { inString : false , fieldState : FieldStates . category } ; } , token : function ( stream , state ) : string { if ( isEmpty ( stream . peek ( ) ) ) { stream . eatSpace ( ) ; return null ; } if ( stream . peek ( ) == "(" || stream . peek ( ) == ")" ) { stream . next ( ) ; return "bracket" ; } if ( stream . match ( "AND" , true , true ) || stream . match ( "OR" , true , true ) ) { return "condition" ; } if ( ! state . inString && stream . peek ( ) == '"' ) { stream . next ( ) ; state . inString = true ; } if ( state . inString ) { if ( stream . skipTo ( '"' ) ) { stream . next ( ) ; state . inString = false ; } else { stream . skipToEnd ( ) ; } return setNextFieldState ( state ) ; } stream . eatWhile ( /[^\r\n\t\s\(\)]+/ ) ; return setNextFieldState ( state ) ; } } ; } ) ; class FieldStates { static none = "none" ; static category = "category" ; static operator = "operator" ; static value = "value" ; } interface ModeState { inString : boolean ; fieldState : FieldStates ; }