fhem.js.unoptimized 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. /* $Id: fhem.js.unoptimized 11288 2016-04-20 08:25:19Z rapster $ */
  2. // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
  3. // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
  4. CodeMirror.defineMode("fhem",function(){
  5. // http://perldoc.perl.org
  6. var PERL={ // null - magic touch
  7. // 1 - keyword
  8. // 2 - def
  9. // 3 - atom
  10. // 4 - operator
  11. // 5 - variable-2 (predefined)
  12. // [x,y] - x=1,2,3; y=must be defined if x{...}
  13. // PERL operators
  14. '->' : 4,
  15. '++' : 4,
  16. '--' : 4,
  17. '**' : 4,
  18. // ! ~ \ and unary + and -
  19. '=~' : 4,
  20. '!~' : 4,
  21. '*' : 4,
  22. '/' : 4,
  23. '%' : 4,
  24. 'x' : 4,
  25. '+' : 4,
  26. '-' : 4,
  27. '.' : 4,
  28. '<<' : 4,
  29. '>>' : 4,
  30. // named unary operators
  31. '<' : 4,
  32. '>' : 4,
  33. '<=' : 4,
  34. '>=' : 4,
  35. 'lt' : 4,
  36. 'gt' : 4,
  37. 'le' : 4,
  38. 'ge' : 4,
  39. '==' : 4,
  40. '!=' : 4,
  41. '<=>' : 4,
  42. 'eq' : 4,
  43. 'ne' : 4,
  44. 'cmp' : 4,
  45. '~~' : 4,
  46. '&' : 4,
  47. '|' : 4,
  48. '^' : 4,
  49. '&&' : 4,
  50. '||' : 4,
  51. '//' : 4,
  52. '..' : 4,
  53. '...' : 4,
  54. '?' : 4,
  55. ':' : 4,
  56. '=' : 4,
  57. '+=' : 4,
  58. '-=' : 4,
  59. '*=' : 4, // etc. ???
  60. ',' : 4,
  61. '=>' : 4,
  62. '::' : 4,
  63. // list operators (rightward)
  64. 'not' : 4,
  65. 'and' : 4,
  66. 'or' : 4,
  67. 'xor' : 4,
  68. // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
  69. 'BEGIN' : [5,1],
  70. 'END' : [5,1],
  71. 'PRINT' : [5,1],
  72. 'PRINTF' : [5,1],
  73. 'GETC' : [5,1],
  74. 'READ' : [5,1],
  75. 'READLINE' : [5,1],
  76. 'DESTROY' : [5,1],
  77. 'TIE' : [5,1],
  78. 'TIEHANDLE' : [5,1],
  79. 'UNTIE' : [5,1],
  80. 'STDIN' : 5,
  81. 'STDIN_TOP' : 5,
  82. 'STDOUT' : 5,
  83. 'STDOUT_TOP' : 5,
  84. 'STDERR' : 5,
  85. 'STDERR_TOP' : 5,
  86. '$ARG' : 5,
  87. '$_' : 5,
  88. '@ARG' : 5,
  89. '@_' : 5,
  90. '$LIST_SEPARATOR' : 5,
  91. '$"' : 5,
  92. '$PROCESS_ID' : 5,
  93. '$PID' : 5,
  94. '$$' : 5,
  95. '$REAL_GROUP_ID' : 5,
  96. '$GID' : 5,
  97. '$(' : 5,
  98. '$EFFECTIVE_GROUP_ID' : 5,
  99. '$EGID' : 5,
  100. '$)' : 5,
  101. '$PROGRAM_NAME' : 5,
  102. '$0' : 5,
  103. '$SUBSCRIPT_SEPARATOR' : 5,
  104. '$SUBSEP' : 5,
  105. '$;' : 5,
  106. '$REAL_USER_ID' : 5,
  107. '$UID' : 5,
  108. '$<' : 5,
  109. '$EFFECTIVE_USER_ID' : 5,
  110. '$EUID' : 5,
  111. '$>' : 5,
  112. '$a' : 5,
  113. '$b' : 5,
  114. '$COMPILING' : 5,
  115. '$^C' : 5,
  116. '$DEBUGGING' : 5,
  117. '$^D' : 5,
  118. '${^ENCODING}' : 5,
  119. '$ENV' : 5,
  120. '%ENV' : 5,
  121. '$SYSTEM_FD_MAX' : 5,
  122. '$^F' : 5,
  123. '@F' : 5,
  124. '${^GLOBAL_PHASE}' : 5,
  125. '$^H' : 5,
  126. '%^H' : 5,
  127. '@INC' : 5,
  128. '%INC' : 5,
  129. '$INPLACE_EDIT' : 5,
  130. '$^I' : 5,
  131. '$^M' : 5,
  132. '$OSNAME' : 5,
  133. '$^O' : 5,
  134. '${^OPEN}' : 5,
  135. '$PERLDB' : 5,
  136. '$^P' : 5,
  137. '$SIG' : 5,
  138. '%SIG' : 5,
  139. '$BASETIME' : 5,
  140. '$^T' : 5,
  141. '${^TAINT}' : 5,
  142. '${^UNICODE}' : 5,
  143. '${^UTF8CACHE}' : 5,
  144. '${^UTF8LOCALE}' : 5,
  145. '$PERL_VERSION' : 5,
  146. '$^V' : 5,
  147. '${^WIN32_SLOPPY_STAT}' : 5,
  148. '$EXECUTABLE_NAME' : 5,
  149. '$^X' : 5,
  150. '$1' : 5, // - regexp $1, $2...
  151. '$MATCH' : 5,
  152. '$&' : 5,
  153. '${^MATCH}' : 5,
  154. '$PREMATCH' : 5,
  155. '$`' : 5,
  156. '${^PREMATCH}' : 5,
  157. '$POSTMATCH' : 5,
  158. "$'" : 5,
  159. '${^POSTMATCH}' : 5,
  160. '$LAST_PAREN_MATCH' : 5,
  161. '$+' : 5,
  162. '$LAST_SUBMATCH_RESULT' : 5,
  163. '$^N' : 5,
  164. '@LAST_MATCH_END' : 5,
  165. '@+' : 5,
  166. '%LAST_PAREN_MATCH' : 5,
  167. '%+' : 5,
  168. '@LAST_MATCH_START' : 5,
  169. '@-' : 5,
  170. '%LAST_MATCH_START' : 5,
  171. '%-' : 5,
  172. '$LAST_REGEXP_CODE_RESULT' : 5,
  173. '$^R' : 5,
  174. '${^RE_DEBUG_FLAGS}' : 5,
  175. '${^RE_TRIE_MAXBUF}' : 5,
  176. '$ARGV' : 5,
  177. '@ARGV' : 5,
  178. 'ARGV' : 5,
  179. 'ARGVOUT' : 5,
  180. '$OUTPUT_FIELD_SEPARATOR' : 5,
  181. '$OFS' : 5,
  182. '$,' : 5,
  183. '$INPUT_LINE_NUMBER' : 5,
  184. '$NR' : 5,
  185. '$.' : 5,
  186. '$INPUT_RECORD_SEPARATOR' : 5,
  187. '$RS' : 5,
  188. '$/' : 5,
  189. '$OUTPUT_RECORD_SEPARATOR' : 5,
  190. '$ORS' : 5,
  191. '$\\' : 5,
  192. '$OUTPUT_AUTOFLUSH' : 5,
  193. '$|' : 5,
  194. '$ACCUMULATOR' : 5,
  195. '$^A' : 5,
  196. '$FORMAT_FORMFEED' : 5,
  197. '$^L' : 5,
  198. '$FORMAT_PAGE_NUMBER' : 5,
  199. '$%' : 5,
  200. '$FORMAT_LINES_LEFT' : 5,
  201. '$-' : 5,
  202. '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
  203. '$:' : 5,
  204. '$FORMAT_LINES_PER_PAGE' : 5,
  205. '$=' : 5,
  206. '$FORMAT_TOP_NAME' : 5,
  207. '$^' : 5,
  208. '$FORMAT_NAME' : 5,
  209. '$~' : 5,
  210. '${^CHILD_ERROR_NATIVE}' : 5,
  211. '$EXTENDED_OS_ERROR' : 5,
  212. '$^E' : 5,
  213. '$EXCEPTIONS_BEING_CAUGHT' : 5,
  214. '$^S' : 5,
  215. '$WARNING' : 5,
  216. '$^W' : 5,
  217. '${^WARNING_BITS}' : 5,
  218. '$OS_ERROR' : 5,
  219. '$ERRNO' : 5,
  220. '$!' : 5,
  221. '%OS_ERROR' : 5,
  222. '%ERRNO' : 5,
  223. '%!' : 5,
  224. '$CHILD_ERROR' : 5,
  225. '$?' : 5,
  226. '$EVAL_ERROR' : 5,
  227. '$@' : 5,
  228. '$OFMT' : 5,
  229. '$#' : 5,
  230. '$*' : 5,
  231. '$ARRAY_BASE' : 5,
  232. '$[' : 5,
  233. '$OLD_PERL_VERSION' : 5,
  234. '$]' : 5,
  235. // PERL blocks
  236. 'if' :[1,1],
  237. elsif :[1,1],
  238. 'else' :[1,1],
  239. 'while' :[1,1],
  240. unless :[1,1],
  241. 'for' :[1,1],
  242. foreach :[1,1],
  243. // PERL functions
  244. 'abs' :1, // - absolute value function
  245. accept :1, // - accept an incoming socket connect
  246. alarm :1, // - schedule a SIGALRM
  247. 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
  248. bind :1, // - binds an address to a socket
  249. binmode :1, // - prepare binary files for I/O
  250. bless :1, // - create an object
  251. bootstrap :1, //
  252. 'break' :1, // - break out of a "given" block
  253. caller :1, // - get context of the current subroutine call
  254. chdir :1, // - change your current working directory
  255. chmod :1, // - changes the permissions on a list of files
  256. chomp :1, // - remove a trailing record separator from a string
  257. chop :1, // - remove the last character from a string
  258. chown :1, // - change the owership on a list of files
  259. chr :1, // - get character this number represents
  260. chroot :1, // - make directory new root for path lookups
  261. close :1, // - close file (or pipe or socket) handle
  262. closedir :1, // - close directory handle
  263. connect :1, // - connect to a remote socket
  264. 'continue' :[1,1], // - optional trailing block in a while or foreach
  265. 'cos' :1, // - cosine function
  266. crypt :1, // - one-way passwd-style encryption
  267. dbmclose :1, // - breaks binding on a tied dbm file
  268. dbmopen :1, // - create binding on a tied dbm file
  269. 'default' :1, //
  270. defined :1, // - test whether a value, variable, or function is defined
  271. 'delete' :1, // - deletes a value from a hash
  272. die :1, // - raise an exception or bail out
  273. 'do' :1, // - turn a BLOCK into a TERM
  274. dump :1, // - create an immediate core dump
  275. each :1, // - retrieve the next key/value pair from a hash
  276. endgrent :1, // - be done using group file
  277. endhostent :1, // - be done using hosts file
  278. endnetent :1, // - be done using networks file
  279. endprotoent :1, // - be done using protocols file
  280. endpwent :1, // - be done using passwd file
  281. endservent :1, // - be done using services file
  282. eof :1, // - test a filehandle for its end
  283. 'eval' :1, // - catch exceptions or compile and run code
  284. 'exec' :1, // - abandon this program to run another
  285. exists :1, // - test whether a hash key is present
  286. exit :1, // - terminate this program
  287. 'exp' :1, // - raise I to a power
  288. fcntl :1, // - file control system call
  289. fileno :1, // - return file descriptor from filehandle
  290. flock :1, // - lock an entire file with an advisory lock
  291. fork :1, // - create a new process just like this one
  292. format :1, // - declare a picture format with use by the write() function
  293. formline :1, // - internal function used for formats
  294. getc :1, // - get the next character from the filehandle
  295. getgrent :1, // - get next group record
  296. getgrgid :1, // - get group record given group user ID
  297. getgrnam :1, // - get group record given group name
  298. gethostbyaddr :1, // - get host record given its address
  299. gethostbyname :1, // - get host record given name
  300. gethostent :1, // - get next hosts record
  301. getlogin :1, // - return who logged in at this tty
  302. getnetbyaddr :1, // - get network record given its address
  303. getnetbyname :1, // - get networks record given name
  304. getnetent :1, // - get next networks record
  305. getpeername :1, // - find the other end of a socket connection
  306. getpgrp :1, // - get process group
  307. getppid :1, // - get parent process ID
  308. getpriority :1, // - get current nice value
  309. getprotobyname :1, // - get protocol record given name
  310. getprotobynumber :1, // - get protocol record numeric protocol
  311. getprotoent :1, // - get next protocols record
  312. getpwent :1, // - get next passwd record
  313. getpwnam :1, // - get passwd record given user login name
  314. getpwuid :1, // - get passwd record given user ID
  315. getservbyname :1, // - get services record given its name
  316. getservbyport :1, // - get services record given numeric port
  317. getservent :1, // - get next services record
  318. getsockname :1, // - retrieve the sockaddr for a given socket
  319. getsockopt :1, // - get socket options on a given socket
  320. given :1, //
  321. glob :1, // - expand filenames using wildcards
  322. gmtime :1, // - convert UNIX time into record or string using Greenwich time
  323. 'goto' :1, // - create spaghetti code
  324. grep :1, // - locate elements in a list test true against a given criterion
  325. hex :1, // - convert a string to a hexadecimal number
  326. 'import' :1, // - patch a module's namespace into your own
  327. index :1, // - find a substring within a string
  328. 'int' :1, // - get the integer portion of a number
  329. ioctl :1, // - system-dependent device control system call
  330. 'join' :1, // - join a list into a string using a separator
  331. keys :1, // - retrieve list of indices from a hash
  332. kill :1, // - send a signal to a process or process group
  333. last :1, // - exit a block prematurely
  334. lc :1, // - return lower-case version of a string
  335. lcfirst :1, // - return a string with just the next letter in lower case
  336. length :1, // - return the number of bytes in a string
  337. 'link' :1, // - create a hard link in the filesytem
  338. listen :1, // - register your socket as a server
  339. local : 2, // - create a temporary value for a global variable (dynamic scoping)
  340. localtime :1, // - convert UNIX time into record or string using local time
  341. lock :1, // - get a thread lock on a variable, subroutine, or method
  342. 'log' :1, // - retrieve the natural logarithm for a number
  343. lstat :1, // - stat a symbolic link
  344. m :null, // - match a string with a regular expression pattern
  345. map :1, // - apply a change to a list to get back a new list with the changes
  346. mkdir :1, // - create a directory
  347. msgctl :1, // - SysV IPC message control operations
  348. msgget :1, // - get SysV IPC message queue
  349. msgrcv :1, // - receive a SysV IPC message from a message queue
  350. msgsnd :1, // - send a SysV IPC message to a message queue
  351. my : 2, // - declare and assign a local variable (lexical scoping)
  352. 'new' :1, //
  353. next :1, // - iterate a block prematurely
  354. no :1, // - unimport some module symbols or semantics at compile time
  355. oct :1, // - convert a string to an octal number
  356. open :1, // - open a file, pipe, or descriptor
  357. opendir :1, // - open a directory
  358. ord :1, // - find a character's numeric representation
  359. our : 2, // - declare and assign a package variable (lexical scoping)
  360. pack :1, // - convert a list into a binary representation
  361. 'package' :1, // - declare a separate global namespace
  362. pipe :1, // - open a pair of connected filehandles
  363. pop :1, // - remove the last element from an array and return it
  364. pos :1, // - find or set the offset for the last/next m//g search
  365. print :1, // - output a list to a filehandle
  366. printf :1, // - output a formatted list to a filehandle
  367. prototype :1, // - get the prototype (if any) of a subroutine
  368. push :1, // - append one or more elements to an array
  369. q :null, // - singly quote a string
  370. qq :null, // - doubly quote a string
  371. qr :null, // - Compile pattern
  372. quotemeta :null, // - quote regular expression magic characters
  373. qw :null, // - quote a list of words
  374. qx :null, // - backquote quote a string
  375. rand :1, // - retrieve the next pseudorandom number
  376. read :1, // - fixed-length buffered input from a filehandle
  377. readdir :1, // - get a directory from a directory handle
  378. readline :1, // - fetch a record from a file
  379. readlink :1, // - determine where a symbolic link is pointing
  380. readpipe :1, // - execute a system command and collect standard output
  381. recv :1, // - receive a message over a Socket
  382. redo :1, // - start this loop iteration over again
  383. ref :1, // - find out the type of thing being referenced
  384. rename :1, // - change a filename
  385. require :1, // - load in external functions from a library at runtime
  386. reset :1, // - clear all variables of a given name
  387. 'return' :1, // - get out of a function early
  388. reverse :1, // - flip a string or a list
  389. rewinddir :1, // - reset directory handle
  390. rindex :1, // - right-to-left substring search
  391. rmdir :1, // - remove a directory
  392. s :null, // - replace a pattern with a string
  393. say :1, // - print with newline
  394. scalar :1, // - force a scalar context
  395. seek :1, // - reposition file pointer for random-access I/O
  396. seekdir :1, // - reposition directory pointer
  397. select :1, // - reset default output or do I/O multiplexing
  398. semctl :1, // - SysV semaphore control operations
  399. semget :1, // - get set of SysV semaphores
  400. semop :1, // - SysV semaphore operations
  401. send :1, // - send a message over a socket
  402. setgrent :1, // - prepare group file for use
  403. sethostent :1, // - prepare hosts file for use
  404. setnetent :1, // - prepare networks file for use
  405. setpgrp :1, // - set the process group of a process
  406. setpriority :1, // - set a process's nice value
  407. setprotoent :1, // - prepare protocols file for use
  408. setpwent :1, // - prepare passwd file for use
  409. setservent :1, // - prepare services file for use
  410. setsockopt :1, // - set some socket options
  411. shift :1, // - remove the first element of an array, and return it
  412. shmctl :1, // - SysV shared memory operations
  413. shmget :1, // - get SysV shared memory segment identifier
  414. shmread :1, // - read SysV shared memory
  415. shmwrite :1, // - write SysV shared memory
  416. shutdown :1, // - close down just half of a socket connection
  417. 'sin' :1, // - return the sine of a number
  418. sleep :1, // - block for some number of seconds
  419. socket :1, // - create a socket
  420. socketpair :1, // - create a pair of sockets
  421. 'sort' :1, // - sort a list of values
  422. splice :1, // - add or remove elements anywhere in an array
  423. 'split' :1, // - split up a string using a regexp delimiter
  424. sprintf :1, // - formatted print into a string
  425. 'sqrt' :1, // - square root function
  426. srand :1, // - seed the random number generator
  427. stat :1, // - get a file's status information
  428. state :1, // - declare and assign a state variable (persistent lexical scoping)
  429. study :1, // - optimize input data for repeated searches
  430. 'sub' :1, // - declare a subroutine, possibly anonymously
  431. 'substr' :1, // - get or alter a portion of a stirng
  432. symlink :1, // - create a symbolic link to a file
  433. syscall :1, // - execute an arbitrary system call
  434. sysopen :1, // - open a file, pipe, or descriptor
  435. sysread :1, // - fixed-length unbuffered input from a filehandle
  436. sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
  437. system :1, // - run a separate program
  438. syswrite :1, // - fixed-length unbuffered output to a filehandle
  439. tell :1, // - get current seekpointer on a filehandle
  440. telldir :1, // - get current seekpointer on a directory handle
  441. tie :1, // - bind a variable to an object class
  442. tied :1, // - get a reference to the object underlying a tied variable
  443. time :1, // - return number of seconds since 1970
  444. times :1, // - return elapsed time for self and child processes
  445. tr :null, // - transliterate a string
  446. truncate :1, // - shorten a file
  447. uc :1, // - return upper-case version of a string
  448. ucfirst :1, // - return a string with just the next letter in upper case
  449. umask :1, // - set file creation mode mask
  450. undef :1, // - remove a variable or function definition
  451. unlink :1, // - remove one link to a file
  452. unpack :1, // - convert binary structure into normal perl variables
  453. unshift :1, // - prepend more elements to the beginning of a list
  454. untie :1, // - break a tie binding to a variable
  455. use :1, // - load in a module at compile time
  456. utime :1, // - set a file's last access and modify times
  457. values :1, // - return a list of the values in a hash
  458. vec :1, // - test or set particular bits in a string
  459. wait :1, // - wait for any child process to die
  460. waitpid :1, // - wait for a particular child process to die
  461. wantarray :1, // - get void vs scalar vs list context of current subroutine call
  462. warn :1, // - print debugging info
  463. when :1, //
  464. write :1, // - print a picture record
  465. // FHEM Keywords ////////////////////////
  466. define :2,
  467. defmod :2,
  468. attr :2,
  469. at :2,
  470. notify :2,
  471. set :2,
  472. ReadingsVal :1,
  473. Value :1,
  474. fhem :1,
  475. IF :2,
  476. DOIF :2,
  477. DOELSE :2,
  478. DOELSEIF :2,
  479. y :null}; // - transliterate a string
  480. keywords.foreach( function( k, v ) {
  481. PERL[v] = 2;
  482. });
  483. var RXstyle="string-2";
  484. var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
  485. function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
  486. state.chain=null; // 12 3tail
  487. state.style=null;
  488. state.tail=null;
  489. state.tokenize=function(stream,state){
  490. var e=false,c,i=0;
  491. while(c=stream.next()){
  492. if(c===chain[i]&&!e){
  493. if(chain[++i]!==undefined){
  494. state.chain=chain[i];
  495. state.style=style;
  496. state.tail=tail;}
  497. else if(tail)
  498. stream.eatWhile(tail);
  499. state.tokenize=tokenPerl;
  500. return style;}
  501. e=!e&&c=="\\";}
  502. return style;};
  503. return state.tokenize(stream,state);}
  504. function tokenSOMETHING(stream,state,string){
  505. state.tokenize=function(stream,state){
  506. if(stream.string==string)
  507. state.tokenize=tokenPerl;
  508. stream.skipToEnd();
  509. return "string";};
  510. return state.tokenize(stream,state);}
  511. function tokenPerl(stream,state){
  512. if(stream.eatSpace())
  513. return null;
  514. if(state.chain)
  515. return tokenChain(stream,state,state.chain,state.style,state.tail);
  516. if(stream.match(/^\-?[\d\.]/,false))
  517. if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
  518. return 'number';
  519. if(stream.match(/^<<(?=\w)/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n
  520. stream.eatWhile(/\w/);
  521. return tokenSOMETHING(stream,state,stream.current().substr(2));}
  522. if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n
  523. return tokenSOMETHING(stream,state,'=cut');}
  524. var ch=stream.next();
  525. if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
  526. if(stream.prefix(3)=="<<"+ch){
  527. var p=stream.pos;
  528. stream.eatWhile(/\w/);
  529. var n=stream.current().substr(1);
  530. if(n&&stream.eat(ch))
  531. return tokenSOMETHING(stream,state,n);
  532. stream.pos=p;}
  533. return tokenChain(stream,state,[ch],"string");}
  534. if(ch=="q"){
  535. var c=stream.look(-2);
  536. if(!(c&&/\w/.test(c))){
  537. c=stream.look(0);
  538. if(c=="x"){
  539. c=stream.look(1);
  540. if(c=="("){
  541. stream.eatSuffix(2);
  542. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  543. if(c=="["){
  544. stream.eatSuffix(2);
  545. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  546. if(c=="{"){
  547. stream.eatSuffix(2);
  548. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  549. if(c=="<"){
  550. stream.eatSuffix(2);
  551. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
  552. if(/[\^'"!~\/]/.test(c)){
  553. stream.eatSuffix(1);
  554. return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
  555. else if(c=="q"){
  556. c=stream.look(1);
  557. if(c=="("){
  558. stream.eatSuffix(2);
  559. return tokenChain(stream,state,[")"],"string");}
  560. if(c=="["){
  561. stream.eatSuffix(2);
  562. return tokenChain(stream,state,["]"],"string");}
  563. if(c=="{"){
  564. stream.eatSuffix(2);
  565. return tokenChain(stream,state,["}"],"string");}
  566. if(c=="<"){
  567. stream.eatSuffix(2);
  568. return tokenChain(stream,state,[">"],"string");}
  569. if(/[\^'"!~\/]/.test(c)){
  570. stream.eatSuffix(1);
  571. return tokenChain(stream,state,[stream.eat(c)],"string");}}
  572. else if(c=="w"){
  573. c=stream.look(1);
  574. if(c=="("){
  575. stream.eatSuffix(2);
  576. return tokenChain(stream,state,[")"],"bracket");}
  577. if(c=="["){
  578. stream.eatSuffix(2);
  579. return tokenChain(stream,state,["]"],"bracket");}
  580. if(c=="{"){
  581. stream.eatSuffix(2);
  582. return tokenChain(stream,state,["}"],"bracket");}
  583. if(c=="<"){
  584. stream.eatSuffix(2);
  585. return tokenChain(stream,state,[">"],"bracket");}
  586. if(/[\^'"!~\/]/.test(c)){
  587. stream.eatSuffix(1);
  588. return tokenChain(stream,state,[stream.eat(c)],"bracket");}}
  589. else if(c=="r"){
  590. c=stream.look(1);
  591. if(c=="("){
  592. stream.eatSuffix(2);
  593. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  594. if(c=="["){
  595. stream.eatSuffix(2);
  596. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  597. if(c=="{"){
  598. stream.eatSuffix(2);
  599. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  600. if(c=="<"){
  601. stream.eatSuffix(2);
  602. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
  603. if(/[\^'"!~\/]/.test(c)){
  604. stream.eatSuffix(1);
  605. return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
  606. else if(/[\^'"!~\/(\[{<]/.test(c)){
  607. if(c=="("){
  608. stream.eatSuffix(1);
  609. return tokenChain(stream,state,[")"],"string");}
  610. if(c=="["){
  611. stream.eatSuffix(1);
  612. return tokenChain(stream,state,["]"],"string");}
  613. if(c=="{"){
  614. stream.eatSuffix(1);
  615. return tokenChain(stream,state,["}"],"string");}
  616. if(c=="<"){
  617. stream.eatSuffix(1);
  618. return tokenChain(stream,state,[">"],"string");}
  619. if(/[\^'"!~\/]/.test(c)){
  620. return tokenChain(stream,state,[stream.eat(c)],"string");}}}}
  621. if(ch=="m"){
  622. var c=stream.look(-2);
  623. if(!(c&&/\w/.test(c))){
  624. c=stream.eat(/[(\[{<\^'"!~\/]/);
  625. if(c){
  626. if(/[\^'"!~\/]/.test(c)){
  627. return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}
  628. if(c=="("){
  629. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  630. if(c=="["){
  631. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  632. if(c=="{"){
  633. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  634. if(c=="<"){
  635. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}}
  636. if(ch=="s"){
  637. var c=/[\/>\]})\w]/.test(stream.look(-2));
  638. if(!c){
  639. c=stream.eat(/[(\[{<\^'"!~\/]/);
  640. if(c){
  641. if(c=="[")
  642. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  643. if(c=="{")
  644. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  645. if(c=="<")
  646. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  647. if(c=="(")
  648. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  649. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
  650. if(ch=="y"){
  651. var c=/[\/>\]})\w]/.test(stream.look(-2));
  652. if(!c){
  653. c=stream.eat(/[(\[{<\^'"!~\/]/);
  654. if(c){
  655. if(c=="[")
  656. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  657. if(c=="{")
  658. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  659. if(c=="<")
  660. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  661. if(c=="(")
  662. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  663. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
  664. if(ch=="t"){
  665. var c=/[\/>\]})\w]/.test(stream.look(-2));
  666. if(!c){
  667. c=stream.eat("r");if(c){
  668. c=stream.eat(/[(\[{<\^'"!~\/]/);
  669. if(c){
  670. if(c=="[")
  671. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  672. if(c=="{")
  673. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  674. if(c=="<")
  675. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  676. if(c=="(")
  677. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  678. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}
  679. if(ch=="`"){
  680. return tokenChain(stream,state,[ch],"variable-2");}
  681. if(ch=="/"){
  682. if(!/~\s*$/.test(stream.prefix()))
  683. return "operator";
  684. else
  685. return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}
  686. if(ch=="$"){
  687. var p=stream.pos;
  688. if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
  689. return "variable-2";
  690. else
  691. stream.pos=p;}
  692. if(/[$@%]/.test(ch)){
  693. var p=stream.pos;
  694. if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
  695. var c=stream.current();
  696. if(PERL[c])
  697. return "variable-2";}
  698. stream.pos=p;}
  699. if(/[$@%&]/.test(ch)){
  700. if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
  701. var c=stream.current();
  702. if(PERL[c])
  703. return "variable-2";
  704. else
  705. return "variable";}}
  706. if(ch=="#"){
  707. if(stream.look(-2)!="$"){
  708. stream.skipToEnd();
  709. return "comment";}}
  710. if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
  711. var p=stream.pos;
  712. stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
  713. if(PERL[stream.current()])
  714. return "operator";
  715. else
  716. stream.pos=p;}
  717. if(ch=="_"){
  718. if(stream.pos==1){
  719. if(stream.suffix(6)=="_END__"){
  720. return tokenChain(stream,state,['\0'],"comment");}
  721. else if(stream.suffix(7)=="_DATA__"){
  722. return tokenChain(stream,state,['\0'],"variable-2");}
  723. else if(stream.suffix(7)=="_C__"){
  724. return tokenChain(stream,state,['\0'],"string");}}}
  725. if(/\w/.test(ch)){
  726. var p=stream.pos;
  727. if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
  728. return "string";
  729. else
  730. stream.pos=p;}
  731. if(/[A-Z]/.test(ch)){
  732. var l=stream.look(-2);
  733. var p=stream.pos;
  734. stream.eatWhile(/[A-Z_]/);
  735. if(/[\da-z]/.test(stream.look(0))){
  736. stream.pos=p;}
  737. else{
  738. var c=PERL[stream.current()];
  739. if(!c)
  740. return "meta";
  741. if(c[1])
  742. c=c[0];
  743. if(l!=":"){
  744. if(c==1)
  745. return "keyword";
  746. else if(c==2)
  747. return "def";
  748. else if(c==3)
  749. return "atom";
  750. else if(c==4)
  751. return "operator";
  752. else if(c==5)
  753. return "variable-2";
  754. else
  755. return "meta";}
  756. else
  757. return "meta";}}
  758. if(/[a-zA-Z_]/.test(ch)){
  759. var l=stream.look(-2);
  760. stream.eatWhile(/\w/);
  761. var c=PERL[stream.current()];
  762. if(!c)
  763. return "meta";
  764. if(c[1])
  765. c=c[0];
  766. if(l!=":"){
  767. if(c==1)
  768. return "keyword";
  769. else if(c==2)
  770. return "def";
  771. else if(c==3)
  772. return "atom";
  773. else if(c==4)
  774. return "operator";
  775. else if(c==5)
  776. return "variable-2";
  777. else
  778. return "meta";}
  779. else
  780. return "meta";}
  781. return null;}
  782. return{
  783. startState:function(){
  784. return{
  785. tokenize:tokenPerl,
  786. chain:null,
  787. style:null,
  788. tail:null};},
  789. token:function(stream,state){
  790. return (state.tokenize||tokenPerl)(stream,state);},
  791. electricChars:"{}"};});
  792. CodeMirror.defineMIME("text/x-fhem", "fhem");
  793. // it's like "peek", but need for look-ahead or look-behind if index < 0
  794. CodeMirror.StringStream.prototype.look=function(c){
  795. return this.string.charAt(this.pos+(c||0));};
  796. // return a part of prefix of current stream from current position
  797. CodeMirror.StringStream.prototype.prefix=function(c){
  798. if(c){
  799. var x=this.pos-c;
  800. return this.string.substr((x>=0?x:0),c);}
  801. else{
  802. return this.string.substr(0,this.pos-1);}};
  803. // return a part of suffix of current stream from current position
  804. CodeMirror.StringStream.prototype.suffix=function(c){
  805. var y=this.string.length;
  806. var x=y-this.pos+1;
  807. return this.string.substr(this.pos,(c&&c<y?c:x));};
  808. // return a part of suffix of current stream from current position and change current position
  809. CodeMirror.StringStream.prototype.nsuffix=function(c){
  810. var p=this.pos;
  811. var l=c||(this.string.length-this.pos+1);
  812. this.pos+=l;
  813. return this.string.substr(p,l);};
  814. // eating and vomiting a part of stream from current position
  815. CodeMirror.StringStream.prototype.eatSuffix=function(c){
  816. var x=this.pos+c;
  817. var y;
  818. if(x<=0)
  819. this.pos=0;
  820. else if(x>=(y=this.string.length-1))
  821. this.pos=y;
  822. else
  823. this.pos=x;};
  824. Array.prototype.foreach = function( callback ) {
  825. for( var k=0; k<this .length; k++ ) {
  826. callback( k, this[ k ] );
  827. }
  828. }
  829. CodeMirror.commands.autocomplete = function(cm) {
  830. CodeMirror.showHint(cm, CodeMirror.hint.fhem, {async:true});
  831. }
  832. var keywords = ["at","attr","define","defmod","delete","deleteattr","deletereading","IF","DOIF","DOELSEIF","DOELSE","displayattr","fhem","get","getstate",
  833. "list","modify","notify","set","setdefaultattr","setreading","setstate","trigger",
  834. "AttrVal","OldTimestamp","OldValue","ReadingsVal","ReadingsTimestamp","Value"];
  835. var variables = ["$defs","$hms","$hour","$isdst","$mday","$min","$month","$sec","$wday","$we","$yday","$year"];
  836. var devices = [];
  837. CodeMirror.registerHelper("hint", "fhem", function hintfhem(cm, callback, options) {
  838. if( devices.length == 0 ) {
  839. $.getJSON( '/fhem?cmd=jsonlist2&XHR=1', function ( data ) {
  840. if( devices.length == 0 ) {
  841. data.Results.foreach( function(k,v) {
  842. devices.push(v);
  843. });
  844. devices.sort(function (a, b) {
  845. return a.Name.toLowerCase().localeCompare(b.Name.toLowerCase());
  846. });
  847. hintfhem(cm,callback,options);
  848. }
  849. });
  850. return;
  851. }
  852. var _key = keywords;
  853. var _var = variables;
  854. var _dev = devices;
  855. var cur = cm.getCursor(), token = cm.getTokenAt(cur);
  856. var word = token.string, start = token.start, end = token.end;
  857. if (/[^\w$_-]/.test(word)) {
  858. word = ""; start = end = cur.ch;
  859. }
  860. var line = cm.getLine(cur.line).substr(0,end);
  861. if( /([\w_\.]+)$/.test(line) ) {
  862. word = RegExp.$1;
  863. start = end - word.length;
  864. }
  865. // only device names
  866. if( /^[ \t]*(attr|set|get|defmod|delete|deleteattr|deletereading|displayattr|getstate|list|modify|setdefaultattr|setreading|setstate|trigger)[ \t]+([\w_\.]+)$/.test(line) ) {
  867. _key = _var = [];
  868. }
  869. // only device attribute names
  870. else if( /^[ \t]*(attr|deleteattr|displayattr)[ \t]+([\w_\.]+)[ \t]+([\w-]*)$/.test(line) ) {
  871. _key = _dev = _var = [];
  872. var device = RegExp.$2;
  873. word = RegExp.$3;
  874. var d = searchDevice(devices,device);
  875. _var = getDeviceAttributes(d);
  876. }
  877. // only device reading names
  878. else if( /^[ \t]*(DOIF|DOELSE|DOELSEIF).*\[+\??([\w_\.]+):\??([\w-]*)$/.test(line) ) {
  879. _key = _dev = _var = [];
  880. var device = RegExp.$2;
  881. word = RegExp.$3;
  882. var d = searchDevice(devices,device);
  883. _var = getDeviceReadings(d);
  884. }
  885. // only device reading names
  886. else if( /^[ \t]*(deletereading|setreading)[ \t]+([\w_\.]+)[ \t]+([\w-]*)$/.test(line) ) {
  887. _key = _dev = _var = [];
  888. var device = RegExp.$2;
  889. word = RegExp.$3;
  890. var d = searchDevice(devices,device);
  891. _var = getDeviceReadings(d);
  892. }
  893. // only device sets names
  894. else if( /^[ \t]*(set|get)[ \t]+([\w_\.]+)[ \t]+([\w-]*)$/.test(line) ) {
  895. _key = _dev = _var = [];
  896. var device = RegExp.$2;
  897. word = RegExp.$3;
  898. var d = searchDevice(devices,device);
  899. _var = getDeviceSets(d);
  900. }
  901. // only device attribute names
  902. else if( /.*(AttrVal)[ \t]*\([ \t]*\"([\w_\.]+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(line) ) {
  903. _key = _dev = _var = [];
  904. var device = RegExp.$2;
  905. word = RegExp.$3;
  906. start = end - word.length;
  907. var d = searchDevice(devices,device);
  908. _var = getDeviceAttributes(d);
  909. }
  910. // only device readings names
  911. else if( /.*(ReadingsVal|ReadingsTimestamp)[ \t]*\([ \t]*\"([\w_\.]+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(line) ) {
  912. _key = _dev = _var = [];
  913. var device = RegExp.$2;
  914. word = RegExp.$3;
  915. start = end - word.length;
  916. var d = searchDevice(devices,device);
  917. _var = getDeviceReadings(d);
  918. }
  919. // only device names
  920. else if( /.*(OldTimestamp|OldValue|Value|ReadingsVal|ReadingsTimestamp|AttrVal)[ \t]*\([ \t]*\"([\w_\.]+)$/.test(line) ) {
  921. _key = _var = [];
  922. word = RegExp.$2;
  923. start = end - word.length;
  924. }
  925. finish(_key,_dev,_var,word);
  926. function getDeviceAttributes(device) {
  927. var attrs = [];
  928. if( device != null ) {
  929. device.PossibleAttrs.split(' ').foreach(function(k,v) {
  930. attrs.push(v.split(':')[0]);
  931. });
  932. attrs.sort(function (a, b) {
  933. return a.toLowerCase().localeCompare(b.toLowerCase());
  934. });
  935. }
  936. return attrs;
  937. }
  938. function getDeviceSets(device) {
  939. var attrs = [];
  940. if( device != null ) {
  941. device.PossibleSets.split(' ').foreach(function(k,v) {
  942. attrs.push(v.split(':')[0]);
  943. });
  944. attrs.sort(function (a, b) {
  945. return a.toLowerCase().localeCompare(b.toLowerCase());
  946. });
  947. }
  948. return attrs;
  949. }
  950. function getDeviceReadings(device) {
  951. var readings = [];
  952. if( device != null ) {
  953. for( var key in device.Readings ) {
  954. readings.push(key);
  955. }
  956. readings.sort(function (a, b) {
  957. return a.toLowerCase().localeCompare(b.toLowerCase());
  958. });
  959. }
  960. return readings;
  961. }
  962. function searchDevice(items, name){
  963. var startIndex = 0,
  964. stopIndex = items.length - 1,
  965. middle = Math.floor((stopIndex + startIndex)/2);
  966. var iname = null;
  967. name = name.toLowerCase();
  968. while( (iname = items[middle].Name.toLowerCase()) != name && startIndex < stopIndex){
  969. //adjust search area
  970. if (name < iname){
  971. stopIndex = middle - 1;
  972. } else if (name > iname){
  973. startIndex = middle + 1;
  974. }
  975. //recalculate middle
  976. middle = Math.floor((stopIndex + startIndex)/2);
  977. }
  978. //make sure it's the right value
  979. return (iname != name) ? null : items[middle];
  980. }
  981. function finish(keys,devs,vars,word) {
  982. var res = [];
  983. keys.foreach( function( k, v ) {
  984. if( v.lastIndexOf(word,0)==0)
  985. res.push({text:v,className:"hintkeyword"});
  986. });
  987. devs.foreach( function( k, v ) {
  988. if( v.Name.lastIndexOf(word,0)==0) {
  989. if( v.Attributes && v.Attributes.alias != null) {
  990. res.push({ text:v.Name, displayText: v.Name + " # " + v.Attributes.alias});
  991. }
  992. else {
  993. res.push(v.Name);
  994. }
  995. }
  996. });
  997. vars.foreach( function( k, v ) {
  998. if( v.lastIndexOf(word,0)==0)
  999. res.push({text:v,className:"hintvariable"});
  1000. });
  1001. callback( {
  1002. list: res,
  1003. from: CodeMirror.Pos(cur.line, start),
  1004. to: CodeMirror.Pos(cur.line, end)
  1005. });
  1006. }
  1007. });