{-# LANGUAGE ScopedTypeVariables, ExistentialQuantification, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}---- Copyright (C) 2007 Don Stewart - http://www.cse.unsw.edu.au/~dons------ | This module defines a common interface for syntax-awareness.moduleYi.Syntax(Highlighter(..),Cache,Scanner(..),ExtHL(..),noHighlighter,mkHighlighter,skipScanner,emptyFileScan,Point(..),Size(..),Length,Stroke,Span(..))whereimportqualifiedData.MapasMimportControl.ArrowimportYi.StyleimportYi.PreludeimportPrelude()importData.List(takeWhile)importYi.Buffer.BasicimportYi.RegiontypeLength=Int-- size in #codepointstypeStroke=SpanStyleNamedataSpana=Span{spanBegin::!Point,spanContents::!a,spanEnd::!Point}derivingShowinstanceTraversableSpanwheretraversef(Spanlar)=(\a'->Spanla'r)<$>fainstanceFoldableSpanwherefoldMap=foldMapDefaultinstanceFunctorSpanwherefmap=fmapDefault-- | The main type of syntax highlighters. This record type combines all-- the required functions, and is parametrized on the type of the internal-- state.-- FIXME: this is actually completetly abstrcted from sytnax HL, so the names are silly.dataHighlightercachesyntax=SynHL{hlStartState::cache-- ^ The start state for the highlighter.,hlRun::ScannerPointChar->Point->cache->cache,hlGetTree::cache->WindowRef->syntax,hlFocus::M.MapWindowRefRegion->cache->cache-- ^ focus at a given point, and return the coresponding node. (hint -- the root can always be returned, at the cost of performance.)}dataExtHLsyntax=forallcache.ExtHL(Highlightercachesyntax)dataScannersta=Scanner{scanInit::st,-- ^ Initial statescanLooked::st->Point,-- ^ How far did the scanner look to produce this intermediate state?-- The state can be reused as long as nothing changes before that point.scanEmpty::a,-- hack :/scanRun::st->[(st,a)]-- ^ Running function returns a list of results and intermediate states.-- Note: the state is the state /before/ producing the result in the second component.}skipScanner::Int->Scannersta->ScannerstaskipScannern(Scanneriler)=Scannerile(other0.r)whereother_[]=[]other_[x]=[x]-- we must return the final result (because if the list is empty mkHighlighter thinks it can reuse the previous result)other0(x:xs)=x:othernxsotherm(_:xs)=other(m-1)xsinstanceFunctor(Scannerst)wherefmapf(Scanneriler)=Scanneril(fe)(\st->fmap(secondf)(rst))dataCachestateresult=Cache[state]resultemptyFileScan::ScannerPointCharemptyFileScan=Scanner{scanInit=0,scanRun=const[],scanLooked=id,scanEmpty=error"emptyFileScan: no scanEmpty"}-- | This takes as input a scanner that returns the "full" result at-- each element in the list; perhaps in a different form for the-- purpose of incremental-lazy eval.mkHighlighter::forallstateresult.Showstate=>(ScannerPointChar->Scannerstateresult)->Highlighter(Cachestateresult)resultmkHighlighterscanner=Yi.Syntax.SynHL{hlStartState=Cache[]emptyResult,hlRun=updateCache,hlGetTree=\(Cache_result)_windowRef->result,hlFocus=\_c->c}wherestartState::statestartState=scanInit(scanneremptyFileScan)emptyResult=scanEmpty(scanneremptyFileScan)updateCache::ScannerPointChar->Point->Cachestateresult->CachestateresultupdateCachenewFileScandirtyOffset(CachecachedStatesoldResult)=CachenewCachedStatesnewResultwherenewScan=scannernewFileScanreused::[state]reused=takeWhile((<dirtyOffset).scanLooked(scannernewFileScan))cachedStatesresumeState::stateresumeState=ifnullreusedthenstartStateelselastreusednewCachedStates=reused++fmapfstrecomputedrecomputed=scanRunnewScanresumeStatenewResult::resultnewResult=ifnullrecomputedthenoldResultelsesnd$head$recomputednoHighlighter::Highlighter()syntaxnoHighlighter=SynHL{hlStartState=(),hlRun=\__a->a,hlFocus=\_c->c,hlGetTree=\_->error"noHighlighter: tried to use syntax"}