diff --git a/fhem/CHANGED b/fhem/CHANGED index cdb38e5a3..8ebcba9b5 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: fhem_codemirror: Added DOIF autocomplete-keywords. Added feature + to autocomplete on any keypress (on by default). - change: ATTENTION: Removed deprecated module 75_MSG.pm. Users will need to manually change their device definitions to MSGFile or MSGMail respectively. diff --git a/fhem/www/codemirror/fhem.js b/fhem/www/codemirror/fhem.js index 6a1a263c9..01faa7cd6 100644 --- a/fhem/www/codemirror/fhem.js +++ b/fhem/www/codemirror/fhem.js @@ -1,3 +1,5 @@ +/* $Id$ */ + CodeMirror.defineMode("fhem",function(){function d(a,c,d,f,b){c.chain=null;c.style=null;c.tail=null;c.tokenize=function(a,c){for(var h=!1,l,k=0;l=a.next();){if(l===d[k]&&!h){void 0!==d[++k]?(c.chain=d[k],c.style=f,c.tail=b):b&&a.eatWhile(b);c.tokenize=n;break}h=!h&&"\\"==l}return f};return c.tokenize(a,c)}function h(a,c,d){c.tokenize=function(a,b){a.string==d&&(b.tokenize=n);a.skipToEnd();return"string"};return c.tokenize(a,c)}function n(a,c){if(a.eatSpace())return null;if(c.chain)return d(a,c,c.chain, c.style,c.tail);if(a.match(/^\-?[\d\.]/,!1)&&a.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))return"number";if(a.match(/^<<(?=\w)/))return a.eatWhile(/\w/),h(a,c,a.current().substr(2));if(a.sol()&&a.match(/^\=item(?!\w)/))return h(a,c,"=cut");var g=a.next();if('"'==g||"'"==g){if(a.prefix(3)=="<<"+g){var m=a.pos;a.eatWhile(/\w/);var b=a.current().substr(1);if(b&&a.eat(g))return h(a,c,b);a.pos=m}return d(a,c,[g],"string")}if("q"==g&&(b=a.look(-2),!b||!/\w/.test(b)))if(b= a.look(0),"x"==b){b=a.look(1);if("("==b)return a.eatSuffix(2),d(a,c,[")"],"string-2",f);if("["==b)return a.eatSuffix(2),d(a,c,["]"],"string-2",f);if("{"==b)return a.eatSuffix(2),d(a,c,["}"],"string-2",f);if("<"==b)return a.eatSuffix(2),d(a,c,[">"],"string-2",f);if(/[\^'"!~\/]/.test(b))return a.eatSuffix(1),d(a,c,[a.eat(b)],"string-2",f)}else if("q"==b){b=a.look(1);if("("==b)return a.eatSuffix(2),d(a,c,[")"],"string");if("["==b)return a.eatSuffix(2),d(a,c,["]"],"string");if("{"==b)return a.eatSuffix(2), @@ -16,13 +18,13 @@ $RS:5,"$/":5,$OUTPUT_RECORD_SEPARATOR:5,$ORS:5,"$\\":5,$OUTPUT_AUTOFLUSH:5,"$|": endprotoent:1,endpwent:1,endservent:1,eof:1,eval:1,exec:1,exists:1,exit:1,exp:1,fcntl:1,fileno:1,flock:1,fork:1,format:1,formline:1,getc:1,getgrent:1,getgrgid:1,getgrnam:1,gethostbyaddr:1,gethostbyname:1,gethostent:1,getlogin:1,getnetbyaddr:1,getnetbyname:1,getnetent:1,getpeername:1,getpgrp:1,getppid:1,getpriority:1,getprotobyname:1,getprotobynumber:1,getprotoent:1,getpwent:1,getpwnam:1,getpwuid:1,getservbyname:1,getservbyport:1,getservent:1,getsockname:1,getsockopt:1,given:1,glob:1,gmtime:1,"goto":1, grep:1,hex:1,"import":1,index:1,"int":1,ioctl:1,join:1,keys:1,kill:1,last:1,lc:1,lcfirst:1,length:1,link:1,listen:1,local:2,localtime:1,lock:1,log:1,lstat:1,m:null,map:1,mkdir:1,msgctl:1,msgget:1,msgrcv:1,msgsnd:1,my:2,"new":1,next:1,no:1,oct:1,open:1,opendir:1,ord:1,our:2,pack:1,"package":1,pipe:1,pop:1,pos:1,print:1,printf:1,prototype:1,push:1,q:null,qq:null,qr:null,quotemeta:null,qw:null,qx:null,rand:1,read:1,readdir:1,readline:1,readlink:1,readpipe:1,recv:1,redo:1,ref:1,rename:1,require:1,reset:1, "return":1,reverse:1,rewinddir:1,rindex:1,rmdir:1,s:null,say:1,scalar:1,seek:1,seekdir:1,select:1,semctl:1,semget:1,semop:1,send:1,setgrent:1,sethostent:1,setnetent:1,setpgrp:1,setpriority:1,setprotoent:1,setpwent:1,setservent:1,setsockopt:1,shift:1,shmctl:1,shmget:1,shmread:1,shmwrite:1,shutdown:1,sin:1,sleep:1,socket:1,socketpair:1,sort:1,splice:1,split:1,sprintf:1,sqrt:1,srand:1,stat:1,state:1,study:1,sub:1,substr:1,symlink:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,tell:1,telldir:1, -tie:1,tied:1,time:1,times:1,tr:null,truncate:1,uc:1,ucfirst:1,umask:1,undef:1,unlink:1,unpack:1,unshift:1,untie:1,use:1,utime:1,values:1,vec:1,wait:1,waitpid:1,wantarray:1,warn:1,when:1,write:1,define:2,attr:2,at:2,notify:2,set:2,ReadingsVal:1,Value:1,fhem:1,y:null};keywords.foreach(function(a,d){p[d]=2});var f=/[goseximacplud]/;return{startState:function(){return{tokenize:n,chain:null,style:null,tail:null}},token:function(a,d){return(d.tokenize||n)(a,d)},electricChars:"{}"}}); +tie:1,tied:1,time:1,times:1,tr:null,truncate:1,uc:1,ucfirst:1,umask:1,undef:1,unlink:1,unpack:1,unshift:1,untie:1,use:1,utime:1,values:1,vec:1,wait:1,waitpid:1,wantarray:1,warn:1,when:1,write:1,define:2,attr:2,at:2,notify:2,set:2,ReadingsVal:1,Value:1,fhem:1,IF:2,DOIF:2,DOELSE:2,DOELSEIF:2,y:null};keywords.foreach(function(a,c){p[c]=2});var f=/[goseximacplud]/;return{startState:function(){return{tokenize:n,chain:null,style:null,tail:null}},token:function(a,c){return(c.tokenize||n)(a,c)},electricChars:"{}"}}); CodeMirror.defineMIME("text/x-fhem","fhem");CodeMirror.StringStream.prototype.look=function(d){return this.string.charAt(this.pos+(d||0))};CodeMirror.StringStream.prototype.prefix=function(d){if(d){var h=this.pos-d;return this.string.substr(0<=h?h:0,d)}return this.string.substr(0,this.pos-1)};CodeMirror.StringStream.prototype.suffix=function(d){var h=this.string.length,n=h-this.pos+1;return this.string.substr(this.pos,d&&d=d?this.pos=0:d>=(h=this.string.length-1)?this.pos=h:this.pos=d};Array.prototype.foreach=function(d){for(var h=0;hg&&(c=f+1),f=Math.floor((e+c)/2);return g!=b?null:a[f]}function m(a,b,c,f){var e=[];a.foreach(function(a,b){0==b.lastIndexOf(f,0)&&e.push({text:b,className:"hintkeyword"})});b.foreach(function(a,b){0==b.Name.lastIndexOf(f,0)&&(b.Attributes&&null!=b.Attributes.alias?e.push({text:b.Name, -displayText:b.Name+" # "+b.Attributes.alias}):e.push(b.Name))});c.foreach(function(a,b){0==b.lastIndexOf(f,0)&&e.push({text:b,className:"hintvariable"})});n({list:e,from:CodeMirror.Pos(t.line,u),to:CodeMirror.Pos(t.line,r)})}if(0==devices.length)$.getJSON("/fhem?cmd=jsonlist2&XHR=1",function(a){a.Results.foreach(function(a,b){devices.push(b)});devices.sort(function(a,b){return a.Name.toLowerCase().localeCompare(b.Name.toLowerCase())});hintfhem(h,n,p)});else{var b=keywords,e=variables,q=devices,t= -h.getCursor(),l=h.getTokenAt(t),k=l.string,u=l.start,r=l.end;/[^\w$_-]/.test(k)&&(k="",u=r=t.ch);l=h.getLine(t.line).substr(0,r);/^[ \t]*(attr|set|get|delete|deleteattr|deletereading|displayattr|getstate|list|modify|setdefaultattr|setreading|setstate|trigger)[ \t]+([\w]*)$/.test(l)?b=e=[]:/^[ \t]*(attr|deleteattr|displayattr)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=f(e)):/^[ \t]*(deletereading|setreading)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e= -RegExp.$2,k=RegExp.$3,e=g(devices,e),e=c(e)):/^[ \t]*(set|get)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=a(e)):/.*(AttrVal)[ \t]*\([ \t]*\"(\w+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,u=r-k.length,e=g(devices,e),e=f(e)):/.*(ReadingsVal|ReadingsTimestamp)[ \t]*\([ \t]*\"(\w+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,u=r-k.length,e=g(devices,e),e=c(e)):/.*(OldTimestamp|OldValue|Value|ReadingsVal|ReadingsTimestamp|AttrVal)[ \t]*\([ \t]*\"(\w*)$/.test(l)&& -(b=e=[],k=RegExp.$2,u=r-k.length);m(b,q,e,k)}}); \ No newline at end of file +b.sort(function(a,b){return a.toLowerCase().localeCompare(b.toLowerCase())})}return b}function g(a,b){var c=0,e=a.length-1,f=Math.floor((e+c)/2),g=null;for(b=b.toLowerCase();(g=a[f].Name.toLowerCase())!=b&&cg&&(c=f+1),f=Math.floor((e+c)/2);return g!=b?null:a[f]}function m(a,b,c,e){var f=[];a.foreach(function(a,b){0==b.lastIndexOf(e,0)&&f.push({text:b,className:"hintkeyword"})});b.foreach(function(a,b){0==b.Name.lastIndexOf(e,0)&&(b.Attributes&&null!=b.Attributes.alias?f.push({text:b.Name, +displayText:b.Name+" # "+b.Attributes.alias}):f.push(b.Name))});c.foreach(function(a,b){0==b.lastIndexOf(e,0)&&f.push({text:b,className:"hintvariable"})});n({list:f,from:CodeMirror.Pos(t.line,u),to:CodeMirror.Pos(t.line,r)})}if(0==devices.length)$.getJSON("/fhem?cmd=jsonlist2&XHR=1",function(a){0==devices.length&&(a.Results.foreach(function(a,b){devices.push(b)}),devices.sort(function(a,b){return a.Name.toLowerCase().localeCompare(b.Name.toLowerCase())}),hintfhem(h,n,p))});else{var b=keywords,e=variables, +q=devices,t=h.getCursor(),l=h.getTokenAt(t),k=l.string,u=l.start,r=l.end;/[^\w$_-]/.test(k)&&(k="",u=r=t.ch);l=h.getLine(t.line).substr(0,r);/^[ \t]*(attr|set|get|delete|deleteattr|deletereading|displayattr|getstate|list|modify|setdefaultattr|setreading|setstate|trigger)[ \t]+([\w]*)$/.test(l)?b=e=[]:/^[ \t]*(attr|deleteattr|displayattr)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=f(e)):/^[ \t]*(DOIF|DOELSE|DOELSEIF).*\[+\??(\w+):\??([\w-]*)$/.test(l)?(b= +q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=c(e)):/^[ \t]*(deletereading|setreading)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=c(e)):/^[ \t]*(set|get)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,e=g(devices,e),e=a(e)):/.*(AttrVal)[ \t]*\([ \t]*\"(\w+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(l)?(b=q=e=[],e=RegExp.$2,k=RegExp.$3,u=r-k.length,e=g(devices,e),e=f(e)):/.*(ReadingsVal|ReadingsTimestamp)[ \t]*\([ \t]*\"(\w+)\"[ \t]*,[ \t]*\"([\w-]*)$/.test(l)? +(b=q=e=[],e=RegExp.$2,k=RegExp.$3,u=r-k.length,e=g(devices,e),e=c(e)):/.*(OldTimestamp|OldValue|Value|ReadingsVal|ReadingsTimestamp|AttrVal)[ \t]*\([ \t]*\"(\w*)$/.test(l)&&(b=e=[],k=RegExp.$2,u=r-k.length);m(b,q,e,k)}}); \ No newline at end of file diff --git a/fhem/www/codemirror/fhem.js.unoptimized b/fhem/www/codemirror/fhem.js.unoptimized index 242f3dfa5..c39444c73 100644 --- a/fhem/www/codemirror/fhem.js.unoptimized +++ b/fhem/www/codemirror/fhem.js.unoptimized @@ -1,4 +1,5 @@ -// $Id: fhem.js 5485 2014-04-08 10:10:56Z betateilchen $ +/* $Id$ */ + // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08) // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com) CodeMirror.defineMode("fhem",function(){ @@ -462,15 +463,19 @@ CodeMirror.defineMode("fhem",function(){ warn :1, // - print debugging info when :1, // write :1, // - print a picture record - - define :2, - attr :2, - at :2, - notify :2, - set :2, - ReadingsVal :1, + // FHEM Keywords //////////////////////// + define :2, + attr :2, + at :2, + notify :2, + set :2, + ReadingsVal :1, Value :1, - fhem :1, + fhem :1, + IF :2, + DOIF :2, + DOELSE :2, + DOELSEIF :2, y :null}; // - transliterate a string keywords.foreach( function( k, v ) { @@ -839,7 +844,7 @@ CodeMirror.commands.autocomplete = function(cm) { CodeMirror.showHint(cm, CodeMirror.hint.fhem, {async:true}); } -var keywords = ["at","attr","define","delete","deleteattr","deletereading","displayattr","fhem","get","getstate", +var keywords = ["at","attr","define","delete","deleteattr","deletereading","IF","DOIF","DOELSEIF","DOELSE","displayattr","fhem","get","getstate", "list","modify","notify","set","setdefaultattr","setreading","setstate","trigger", "AttrVal","OldTimestamp","OldValue","ReadingsVal","ReadingsTimestamp","Value"]; var variables = ["$defs","$hms","$hour","$isdst","$mday","$min","$month","$sec","$wday","$we","$yday","$year"]; @@ -849,13 +854,15 @@ CodeMirror.registerHelper("hint", "fhem", function hintfhem(cm, callback, option if( devices.length == 0 ) { $.getJSON( '/fhem?cmd=jsonlist2&XHR=1', function ( data ) { - data.Results.foreach( function(k,v) { - devices.push(v); - }); - devices.sort(function (a, b) { - return a.Name.toLowerCase().localeCompare(b.Name.toLowerCase()); - }); - hintfhem(cm,callback,options); + if( devices.length == 0 ) { + data.Results.foreach( function(k,v) { + devices.push(v); + }); + devices.sort(function (a, b) { + return a.Name.toLowerCase().localeCompare(b.Name.toLowerCase()); + }); + hintfhem(cm,callback,options); + } }); return; } @@ -883,6 +890,14 @@ CodeMirror.registerHelper("hint", "fhem", function hintfhem(cm, callback, option _var = getDeviceAttributes(d); } // only device reading names + else if( /^[ \t]*(DOIF|DOELSE|DOELSEIF).*\[+\??(\w+):\??([\w-]*)$/.test(line) ) { + _key = _dev = _var = []; + var device = RegExp.$2; + word = RegExp.$3; + var d = searchDevice(devices,device); + _var = getDeviceReadings(d); + } + // only device reading names else if( /^[ \t]*(deletereading|setreading)[ \t]+(\w+)[ \t]+([\w-]*)$/.test(line) ) { _key = _dev = _var = []; var device = RegExp.$2; diff --git a/fhem/www/codemirror/fhem_codemirror.js b/fhem/www/codemirror/fhem_codemirror.js index 5cde195ab..43f2f48a1 100644 --- a/fhem/www/codemirror/fhem_codemirror.js +++ b/fhem/www/codemirror/fhem_codemirror.js @@ -3,19 +3,20 @@ var cm_loaded = 0; var cm_active = 0; var cm_attr = { - matchBrackets: true, - autoRefresh: true, - search: true, - comment: true, - autocomplete: true, - autoCloseBrackets:true, - indentUnit: 4, - type: "fhem", - theme: "blackboard", - indentWithTabs: true, - autofocus: true, - lineNumbers: true, - smartIndent: false, + matchBrackets: true, + autoRefresh: true, + search: true, + comment: true, + autocomplete: true, + autocompleteAlways: true, + autoCloseBrackets: true, + indentUnit: 4, + type: "fhem", + theme: "blackboard", + indentWithTabs: true, + autofocus: true, + lineNumbers: true, + smartIndent: false, extraKeys: { 'Tab': function(cm) { if (cm.somethingSelected()) { @@ -148,6 +149,15 @@ function cm_wait(cm_editor, callback, recursions) { } var cm = CodeMirror.fromTextArea(cm_editor, cm_attr); + + if (cm_attr.autocomplete && cm_attr.autocompleteAlways) { + cm.on("keyup", function (cm, event) { + if ( !cm.state.completionActive && String.fromCharCode(event.keyCode).match(/\w/) ) { + CodeMirror.commands.autocomplete(cm, null, {completeSingle: false}); + } + }); + } + if(callback) callback(cm); }