@@ -699,9 +699,12 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
699
699
const includeset = new Set ( ) ;
700
700
let errorCount = 0 ;
701
701
702
+ const ifendifSet = new Set ( ) ;
703
+ let ifendifSetChanged = false ;
704
+
702
705
const extractMarkerDetails = ( doc , lineHandle ) => {
703
706
if ( astParser . isUnsupported ( ) ) {
704
- return { value : 'error' , msg : 'Unsupported filter syntax' } ;
707
+ return { lint : 'error' , msg : 'Unsupported filter syntax' } ;
705
708
}
706
709
if ( astParser . hasError ( ) ) {
707
710
let msg = 'Invalid filter' ;
@@ -739,23 +742,31 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
739
742
}
740
743
break ;
741
744
}
742
- return { value : 'error' , msg } ;
745
+ return { lint : 'error' , msg } ;
743
746
}
744
747
if ( astParser . astType !== sfp . AST_TYPE_COMMENT ) { return ; }
745
748
if ( astParser . astTypeFlavor !== sfp . AST_TYPE_COMMENT_PREPARSER ) {
746
749
if ( astParser . raw . startsWith ( '! <<<<<<<< ' ) === false ) { return ; }
747
750
for ( const include of includeset ) {
748
751
if ( astParser . raw . endsWith ( include ) === false ) { continue ; }
749
752
includeset . delete ( include ) ;
750
- return { value : 'include-end' } ;
753
+ return { lint : 'include-end' } ;
751
754
}
752
755
return ;
753
756
}
754
757
if ( / ^ \s * ! # i f \S + / . test ( astParser . raw ) ) {
755
- return { value : 'if-start' } ;
758
+ return {
759
+ lint : 'if-start' ,
760
+ data : {
761
+ state : sfp . utils . preparser . evaluateExpr (
762
+ astParser . getTypeString ( sfp . NODE_TYPE_PREPARSE_DIRECTIVE_IF_VALUE ) ,
763
+ preparseDirectiveEnv
764
+ ) ? 'y' : 'n'
765
+ }
766
+ } ;
756
767
}
757
768
if ( / ^ \s * ! # e n d i f \b / . test ( astParser . raw ) ) {
758
- return { value : 'if-end' } ;
769
+ return { lint : 'if-end' } ;
759
770
}
760
771
const match = / ^ \s * ! # i n c l u d e \s * ( \S + ) / . exec ( astParser . raw ) ;
761
772
if ( match === null ) { return ; }
@@ -765,7 +776,7 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
765
776
const includeToken = `/${ match [ 1 ] } ` ;
766
777
if ( nextLineHandle . text . endsWith ( includeToken ) === false ) { return ; }
767
778
includeset . add ( includeToken ) ;
768
- return { value : 'include-start' } ;
779
+ return { lint : 'include-start' } ;
769
780
} ;
770
781
771
782
const extractMarker = lineHandle => {
@@ -779,18 +790,19 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
779
790
'error' : {
780
791
node : null ,
781
792
html : [
782
- '<div class="CodeMirror-lintmarker" data-lint="error"> ' ,
793
+ '<div class="CodeMirror-lintmarker" data-lint="error" data-error="y" > ' ,
783
794
'<span class="msg"></span>' ,
784
795
'</div>' ,
785
796
] ,
786
797
} ,
787
798
'if-start' : {
788
799
node : null ,
789
800
html : [
790
- '<div class="CodeMirror-lintmarker" data-lint="if" data-fold="start"> ' ,
801
+ '<div class="CodeMirror-lintmarker" data-lint="if" data-fold="start" data-state="" > ' ,
791
802
'<svg viewBox="0 0 100 100">' ,
792
803
'<polygon points="0,0 100,0 50,100" />' ,
793
804
'</svg>' ,
805
+ '<span class="msg">Mismatched if-endif directive</span>' ,
794
806
'</div>' ,
795
807
] ,
796
808
} ,
@@ -801,6 +813,7 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
801
813
'<svg viewBox="0 0 100 100">' ,
802
814
'<polygon points="50,0 100,100 0,100" />' ,
803
815
'</svg>' ,
816
+ '<span class="msg">Mismatched if-endif directive</span>' ,
804
817
'</div>' ,
805
818
] ,
806
819
} ,
@@ -826,52 +839,111 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
826
839
} ,
827
840
} ;
828
841
829
- const markerFromTemplate = which => {
830
- const template = markerTemplates [ which ] ;
842
+ const markerFromTemplate = details => {
843
+ const template = markerTemplates [ details . lint ] ;
831
844
if ( template . node === null ) {
832
845
const domParser = new DOMParser ( ) ;
833
846
const doc = domParser . parseFromString ( template . html . join ( '' ) , 'text/html' ) ;
834
847
template . node = document . adoptNode ( qs$ ( doc , '.CodeMirror-lintmarker' ) ) ;
835
848
}
836
- return template . node . cloneNode ( true ) ;
849
+ const node = template . node . cloneNode ( true ) ;
850
+ if ( details . data instanceof Object ) {
851
+ for ( const [ k , v ] of Object . entries ( details . data ) ) {
852
+ node . dataset [ k ] = `${ v } ` ;
853
+ }
854
+ }
855
+ return node ;
837
856
} ;
838
857
839
858
const addMarker = ( doc , lineHandle , marker , details ) => {
840
- if ( marker !== null && marker . dataset . lint !== details . value ) {
859
+ if ( marker && marker . dataset . lint !== details . lint ) {
841
860
doc . setGutterMarker ( lineHandle , 'CodeMirror-lintgutter' , null ) ;
842
- if ( marker . dataset . lint === 'error ' ) {
861
+ if ( marker . dataset . error === 'y ' ) {
843
862
errorCount -= 1 ;
844
863
}
864
+ if ( marker . dataset . lint === 'if' ) {
865
+ ifendifSet . delete ( lineHandle ) ;
866
+ ifendifSetChanged = true ;
867
+ }
845
868
marker = null ;
846
869
}
847
870
if ( marker === null ) {
848
- marker = markerFromTemplate ( details . value ) ;
871
+ marker = markerFromTemplate ( details ) ;
849
872
doc . setGutterMarker ( lineHandle , 'CodeMirror-lintgutter' , marker ) ;
850
- if ( details . value === 'error ' ) {
873
+ if ( marker . dataset . error === 'y ' ) {
851
874
errorCount += 1 ;
852
875
}
876
+ if ( marker . dataset . lint === 'if' ) {
877
+ ifendifSet . add ( lineHandle ) ;
878
+ ifendifSetChanged = true ;
879
+ }
853
880
}
881
+ if ( typeof details . msg !== 'string' || details . msg === '' ) { return ; }
854
882
const msgElem = qs$ ( marker , '.msg' ) ;
855
883
if ( msgElem === null ) { return ; }
856
- msgElem . textContent = details . msg || '' ;
884
+ msgElem . textContent = details . msg ;
857
885
} ;
858
886
859
887
const removeMarker = ( doc , lineHandle , marker ) => {
860
888
doc . setGutterMarker ( lineHandle , 'CodeMirror-lintgutter' , null ) ;
861
- if ( marker . dataset . lint === 'error ' ) {
889
+ if ( marker . dataset . error === 'y ' ) {
862
890
errorCount -= 1 ;
863
891
}
892
+ if ( marker . dataset . lint === 'if' ) {
893
+ ifendifSet . delete ( lineHandle ) ;
894
+ ifendifSetChanged = true ;
895
+ }
896
+ } ;
897
+
898
+ // Analyze whether all if-endif are properly paired
899
+ const processIfendifs = ( ) => {
900
+ if ( ifendifSet . size === 0 ) { return ; }
901
+ if ( ifendifSetChanged !== true ) { return ; }
902
+ const sortFn = ( a , b ) => a . lineNo ( ) - b . lineNo ( ) ;
903
+ const sorted = Array . from ( ifendifSet ) . sort ( sortFn ) ;
904
+ const bad = [ ] ;
905
+ const stack = [ ] ;
906
+ for ( const line of sorted ) {
907
+ const marker = extractMarker ( line ) ;
908
+ const fold = marker . dataset . fold ;
909
+ if ( fold === 'start' ) {
910
+ stack . push ( line ) ;
911
+ } else if ( fold === 'end' ) {
912
+ if ( stack . length !== 0 ) {
913
+ if ( marker . dataset . error === 'y' ) {
914
+ marker . dataset . error = '' ;
915
+ errorCount -= 1 ;
916
+ }
917
+ const ifstart = extractMarker ( stack . pop ( ) ) ;
918
+ if ( ifstart . dataset . error === 'y' ) {
919
+ ifstart . dataset . error = '' ;
920
+ errorCount -= 1 ;
921
+ }
922
+ } else {
923
+ bad . push ( line ) ;
924
+ }
925
+ }
926
+ }
927
+ bad . push ( ...stack ) ;
928
+ for ( const line of bad ) {
929
+ const marker = extractMarker ( line ) ;
930
+ marker . dataset . error = 'y' ;
931
+ errorCount += 1 ;
932
+ }
933
+ ifendifSetChanged = false ;
864
934
} ;
865
935
866
936
const processDeletion = ( doc , change ) => {
867
937
let { from, to } = change ;
868
938
doc . eachLine ( from . line , to . line , lineHandle => {
869
939
const marker = extractMarker ( lineHandle ) ;
870
940
if ( marker === null ) { return ; }
871
- if ( marker . dataset . lint === 'error' ) {
941
+ if ( marker . dataset . error === 'y' ) {
942
+ marker . dataset . error = '' ;
872
943
errorCount -= 1 ;
873
- marker . dataset . lint = 'void' ;
874
944
}
945
+ ifendifSet . delete ( lineHandle ) ;
946
+ ifendifSetChanged = true ;
875
947
} ) ;
876
948
} ;
877
949
@@ -881,10 +953,10 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
881
953
astParser . parse ( lineHandle . text ) ;
882
954
const markerDetails = extractMarkerDetails ( doc , lineHandle ) ;
883
955
const marker = extractMarker ( lineHandle ) ;
884
- if ( markerDetails === undefined && marker !== null ) {
885
- removeMarker ( doc , lineHandle , marker ) ;
886
- } else if ( markerDetails !== undefined ) {
956
+ if ( markerDetails !== undefined ) {
887
957
addMarker ( doc , lineHandle , marker , markerDetails ) ;
958
+ } else if ( marker !== null ) {
959
+ removeMarker ( doc , lineHandle , marker ) ;
888
960
}
889
961
from += 1 ;
890
962
if ( ( from & 0x0F ) !== 0 ) { return ; }
@@ -910,6 +982,7 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
910
982
return processChangesetAsync ( doc ) ;
911
983
}
912
984
includeset . clear ( ) ;
985
+ processIfendifs ( doc ) ;
913
986
CodeMirror . signal ( doc . getEditor ( ) , 'linterDone' , { errorCount } ) ;
914
987
} ;
915
988
@@ -922,13 +995,14 @@ CodeMirror.registerHelper('fold', 'ubo-static-filtering', (( ) => {
922
995
} ;
923
996
924
997
const onChanges = ( cm , changes ) => {
998
+ if ( changes . length === 0 ) { return ; }
925
999
const doc = cm . getDoc ( ) ;
926
1000
for ( const change of changes ) {
927
1001
const from = change . from . line ;
928
1002
const to = from + change . text . length ;
929
1003
changeset . push ( { from, to } ) ;
930
- processChangesetAsync ( doc ) ;
931
1004
}
1005
+ processChangesetAsync ( doc ) ;
932
1006
} ;
933
1007
934
1008
const onBeforeChanges = ( cm , change ) => {
0 commit comments