@@ -40,8 +40,10 @@ const path = require('path');
4040// OTHER changes
4141// draw has been changed to draw_ on the righthand side
4242// Gobal functions currently have _ at end, which they didn't in the original file: keyPressed, keyReleased, keyTyped, mouseClicked, mouseDragged, mouseMoved, mousePressed, mouseReleased, mouseWheel, settings, setup
43- // pixelHeight was listed as a function with _ at the right end. I removed it.
43+ // pixelHeight was there twice. I removed it from the generated code
4444// PVector was listed twice as FUNCTION1 in base and KEYWORD5 in generated output. I keps the latter.
45+ // PShader.set was `PShader FUNCTION2 PShader_set_`. Changed to `set FUNCTION2 PShader_set_`
46+ // PFont.list was listed as FUNCTION1. I changed it to be FUNCTION2 like the other class methods.
4547
4648const folder = path . join (
4749 __dirname ,
@@ -59,81 +61,99 @@ const folder = path.join(
5961**/
6062const ignore = [ 'width' , 'height' , 'x' , 'y' , 'z' , 'Object' ] ;
6163
64+ /**
65+ A list of global functions that need to have special handling
66+ **/
67+ const globalFuncs = [
68+ 'keyPressed()' ,
69+ 'keyReleased()' ,
70+ 'keyTyped()' ,
71+ 'mouseClicked()' ,
72+ 'mouseDragged()' ,
73+ 'mouseMoved()' ,
74+ 'mousePressed()' ,
75+ 'mouseReleased()' ,
76+ 'mouseWheel()' ,
77+ 'settings()' ,
78+ 'setup()' ,
79+ 'draw()'
80+ ] ;
81+
6282/**
6383 This script creates the keywords.txt file that is used to do syntax highligting
6484 in the Processing IDE.
6585**/
6686const createKeywords = ( ) => {
67- // TEMPORARY: To be used for diffing
68- const currentKeywords = parseKeywordsFile ( 'current_keywords.txt' ) ;
69- const absIndex = currentKeywords . findIndex ( ( k ) => k [ 0 ] === 'abs' ) ;
70- const needToGenerate = currentKeywords . slice ( absIndex ) ;
71-
7287 // Load the base keywords
73- const baseKeywords = parseKeywordsFile ( 'keywords_base.txt' ) ;
88+ const [ baseKeywords , baseContents ] = parseKeywordsFile ( 'keywords_base.txt' ) ;
7489
7590 // Load all json files
7691 const entries = fs . readdirSync ( folder ) . map ( ( file ) => {
77- const entry = require ( path . join ( folder , file ) ) ;
78- return Object . assign (
92+ let entry = require ( path . join ( folder , file ) ) ;
93+ entry = Object . assign (
7994 {
8095 filename : file ,
81- basename : path . basename ( file , '.json' ) ,
82- clean : cleanName ( entry )
96+ basename : path . basename ( file , '.json' )
8397 } ,
8498 entry
8599 ) ;
100+ entry . leftName = leftName ( entry ) ;
101+ entry . rightName = rightName ( entry ) ;
102+ entry . token = getToken ( entry ) ;
103+ return entry ;
86104 } ) ;
87105
88106 // Sort by listing in original keywords.txt
89107 entries . sort ( sortByClassAndGlobal ) ;
90108
91109 // Run through and add if not already in base
92- const newKeywords = [ ] ;
110+ const keywords = [ ] ;
93111 for ( let i = 0 ; i < entries . length ; i ++ ) {
94112 const entry = entries [ i ] ;
95- if ( entry . name === 'PVector' ) {
96- console . log ( 'here' , shouldInclude ( baseKeywords , entry ) ) ;
97- }
98113 if ( shouldInclude ( baseKeywords , entry ) ) {
99- newKeywords . push ( [ entry . clean , 'CATEGORY' , entry . basename ] ) ;
114+ keywords . push ( [ entry . leftName , entry . token , entry . rightName ] ) ;
100115 }
101116 }
102117
103- // Log to compare objects
104- for ( let i = 0 ; i < needToGenerate . length ; i ++ ) {
105- const a = needToGenerate [ i ] [ 2 ] ;
106- const b = newKeywords [ i ] ? newKeywords [ i ] [ 2 ] : null ;
107- console . log ( a == b , `| ${ a } | ${ b } |` ) ;
108- }
118+ const pad = ( str , size ) => ( str ? str . padEnd ( size , ' ' ) : str ) ;
119+
120+ // COMPARE TO OLD VERSION
121+ /*
122+ const [currentKeywords] = parseKeywordsFile('keywords_old.txt');
123+ const absIndex = currentKeywords.findIndex((k) => k[0] === 'abs');
124+ const needToGenerate = currentKeywords.slice(absIndex);
125+ console.log('Old', needToGenerate.length, 'New', keywords.length);
109126
110- console . log (
111- 'Old length' ,
112- needToGenerate . length ,
113- 'New Length' ,
114- newKeywords . length
115- ) ;
116-
117- // output rest of stuff from newKeywords
118- if ( newKeywords . length > needToGenerate . length ) {
119- for ( let i = needToGenerate . length ; i < newKeywords . length ; i ++ ) {
120- console . log ( 'EXTRA' , needToGenerate [ i ] ) ;
127+ for (let i = 0; i < needToGenerate.length; i++) {
128+ const a = needToGenerate[i];
129+ const b = keywords[i];
130+ const match = a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
131+
132+ if (!match) {
133+ console.log(
134+ pad(match.toString(), 7),
135+ pad(a[0], 25),
136+ pad(b[0], 25),
137+ pad(a[1], 10),
138+ pad(b[1], 10),
139+ pad(a[2], 25),
140+ pad(b[2], 25)
141+ );
121142 }
122143 }
123- } ;
144+ */
124145
125- const sortByClassAndGlobal = ( a , b ) => {
126- // If a is not a class, but b is, a comes first
127- // if (!a.classanchor && b.classanchor) {
128- // return -1;
129- // }
146+ // Save to keywords.txt file
147+ const combined = baseContents + '\n\n' + generateKeywordsFile ( keywords ) ;
130148
131- // If a is a class, but b is not, a comes last
132- // else if (a.classanchor && !b.classanchor) {
133- // return 1;
134- // }
149+ fs . writeFileSync ( path . join ( __dirname , 'keywords.txt' ) , combined ) ;
150+ console . log ( 'keywords.txt file written to scripts folder' ) ;
151+ } ;
135152
136- // Otherwise, compare apples to apples
153+ /**
154+ Sorts the entries based on the basename
155+ **/
156+ const sortByClassAndGlobal = ( a , b ) => {
137157 const strippedA = a . basename . replace ( / _ $ / , '' ) . toLowerCase ( ) ;
138158 const strippedB = b . basename . replace ( / _ $ / , '' ) . toLowerCase ( ) ;
139159
@@ -149,7 +169,7 @@ const sortByClassAndGlobal = (a, b) => {
149169} ;
150170
151171/**
152- Looks to see if the entry is in the keywords base.
172+ Looks to see if the entry is in the base keywords .
153173**/
154174const shouldInclude = ( keywords , entry ) => {
155175 // Don't include ignored names
@@ -159,7 +179,7 @@ const shouldInclude = (keywords, entry) => {
159179
160180 // See if entry is in the keywords base
161181 for ( let i = 0 ; i < keywords . length ; i ++ ) {
162- if ( keywords [ i ] [ 0 ] == entry . clean && keywords [ i ] [ 2 ] == entry . basename ) {
182+ if ( keywords [ i ] [ 0 ] == entry . leftName && keywords [ i ] [ 2 ] == entry . basename ) {
163183 return false ;
164184 }
165185 }
@@ -168,9 +188,12 @@ const shouldInclude = (keywords, entry) => {
168188 return true ;
169189} ;
170190
191+ /**
192+ Parse a keywords file into an array of arrays
193+ **/
171194const parseKeywordsFile = ( filename ) => {
172- const txt = fs . readFileSync ( path . join ( __dirname , filename ) ) . toString ( ) ;
173- const lines = txt . split ( '\n' ) ;
195+ const content = fs . readFileSync ( path . join ( __dirname , filename ) ) . toString ( ) ;
196+ const lines = content . split ( '\n' ) ;
174197 const keywords = [ ] ;
175198
176199 for ( let i = 0 ; i < lines . length ; i ++ ) {
@@ -180,7 +203,15 @@ const parseKeywordsFile = (filename) => {
180203 }
181204 }
182205
183- return keywords ;
206+ return [ keywords , content ] ;
207+ } ;
208+
209+ const generateKeywordsFile = ( keywords ) => {
210+ let str = '' ;
211+ for ( let i = 0 ; i < keywords . length ; i ++ ) {
212+ str += `${ keywords [ i ] [ 0 ] } \t${ keywords [ i ] [ 1 ] } \t${ keywords [ i ] [ 2 ] } \n` ;
213+ }
214+ return str ;
184215} ;
185216
186217/**
@@ -195,36 +226,61 @@ const specialCases = {
195226/**
196227 Makes the clean version of the name for the left-hand side of the file
197228**/
198- const cleanName = ( entry ) => {
199- // Constants, classes and primitives are just using the name
200- if (
201- entry . type === 'class' ||
202- entry . category === 'constants' ||
203- ( entry . category === 'Data' && entry . subcategory === 'Primitive' )
204- ) {
205- return entry . name ;
206- }
207-
229+ const operatorRegex = / \s \( [ a - z A - Z \s ] + \) $ / ;
230+ const leftName = ( entry ) => {
208231 // Special handling
209232 if ( specialCases [ entry . name ] ) {
210233 return specialCases [ entry . name ] ;
211234 }
212235
213236 // Operators are renamed: += (add assign) => +=
214- if (
215- entry . subcategory === 'Operators' ||
216- entry . subcategory == 'Bitwise Operators' ||
217- entry . subcategory == 'Relational Operators' ||
218- entry . subcategory == 'Logical Operators' ||
219- ( entry . category === 'structure' && entry . subcategory === '' )
220- ) {
221- return entry . name . replace ( / \( [ a - z A - Z \s ] + \) $ / , '' ) . trim ( ) ;
237+ if ( entry . name . match ( operatorRegex ) ) {
238+ return entry . name . replace ( operatorRegex , '' ) ;
222239 }
223240
224241 // Functions and class methods are renamed: float() => float
225242 if ( entry . type === 'function' || entry . type === 'method' ) {
226243 return entry . name . replace ( / \( \) $ / , '' ) ;
227244 }
245+
246+ // Variables are renamed: pixels[] => pixels
247+ if ( entry . type === 'field' || entry . type === 'other' ) {
248+ return entry . name . replace ( / \[ \] $ / , '' ) ;
249+ }
250+
251+ // Just use name (Constants, classes, primitives, etc)
252+ return entry . name ;
253+ } ;
254+
255+ /**
256+ Make a name suitable for the right hand side
257+ **/
258+ const rightName = ( entry ) => {
259+ // global functions appear as just the name in the right
260+ if ( globalFuncs . includes ( entry . name ) ) {
261+ return entry . name . replace ( / \( \) $ / , '' ) ;
262+ }
263+
264+ // Everything else uses the basename (fill_, PVector_add_, etc)
265+ return entry . basename ;
266+ } ;
267+
268+ /**
269+ Gets the syntax category. Based on the old pearl script.
270+ **/
271+ const getToken = ( entry ) => {
272+ if ( globalFuncs . includes ( entry . name ) ) {
273+ return 'FUNCTION4' ;
274+ } else if ( entry . type === 'class' ) {
275+ return 'KEYWORD5' ;
276+ } else if ( entry . type === 'method' ) {
277+ return 'FUNCTION2' ;
278+ } else if ( entry . type === 'other' ) {
279+ return 'KEYWORD4' ;
280+ } else if ( entry . type === 'field' ) {
281+ return 'KEYWORD2' ;
282+ }
283+ return 'FUNCTION1' ;
228284} ;
229285
230286createKeywords ( ) ;
0 commit comments