Merge branch 'master' of http://git.roojs.com/roobuilder
[roobuilder] / src / Palete / LanguageClientJavascript.vala
1
2 namespace Palete {
3         public class LanguageClientJavascript : LanguageClient {
4         
5                 Gee.HashMap<string,string> file_contents;
6         
7                 public LanguageClientJavascript(Project.Project project)
8                 {
9                         // extend versions will proably call initialize to start and connect to server.
10                         base(project);
11                         this.file_contents =  new Gee.HashMap<string,string>();
12                         GLib.debug(" START JAVASCRIPT LANG SERVER");
13                 
14                 }
15                 public override   void  initialize_server()   {
16                         GLib.debug("initialize javascript server");                     
17                 }
18                  
19                  
20                 public override void document_open (JsRender.JsRender file)  
21                 {
22                         this.file_contents.set(file.path, file.toSourceCode());
23                         Javascript.singleton().validate(file.toSourceCode(), file );
24                         BuilderApplication.updateCompileResults();
25                 
26                 }
27                 public override async void document_save (JsRender.JsRender file)  
28                 {
29                         
30                         this.file_contents.set(file.path, file.toSourceCode());
31                         GLib.debug("set file %s : %d  chars", file.path, this.file_contents.get(file.path).length);
32                         Javascript.singleton().validate(file.toSourceCode(), file );
33                         BuilderApplication.updateCompileResults();
34                 }
35                 public override async void document_change_force (JsRender.JsRender file, string contents )   {
36                         this.file_contents.set(file.path, contents);
37                         GLib.debug("set file %s : %d chars", file.path, this.file_contents.get(file.path).length);
38                         Javascript.singleton().validate(contents, file );
39                         BuilderApplication.updateCompileResults();
40                 }
41                 public override  void document_change (JsRender.JsRender file )    
42                 {
43                         this.document_change_force.begin( file, file.toSourceCode(), (obj, res) => {
44                                 this.document_change_force.end(res);
45                         });;
46                 }
47                 public override void document_close (JsRender.JsRender file) {}
48                 public override void exit () throws GLib.Error { }
49                 public override async void shutdown () throws GLib.Error { }
50                 public override async Lsp.CompletionList?  completion(JsRender.JsRender file, int line, int offset , int triggerType = 1) throws GLib.Error 
51                 {
52                 
53                         var ret = new Lsp.CompletionList();     
54                         if (this.file_contents.get(file.path) == null) {
55                                 GLib.debug("got file %s : MISSING ", file.path);                                
56                                 return ret;
57                         }
58                         //GLib.debug("got file %s : %s ", file.path, this.file_contents.get(file.path));
59                         
60                         var ar = this.file_contents.get(file.path).split("\n");
61                         var ln = line >= ar.length || line < 1 ? "" :  ar[line-1];
62                         if (offset-1 >= ln.length) {
63                                 GLib.debug("request for complete on line %d  @ pos %d > line length %d", line, offset, (int) ln.length);
64                                 return ret;
65                         } 
66                         GLib.debug("got Line %d:%d '%s' ", line, offset,  ln);
67                         
68                         var start = -1;
69                         for (var i = offset - 1; i > 0; i--) {
70                                 GLib.debug("check char %d '%c'", i, ln[i]); 
71                                 if (ln[i].isalpha() || ln[i] == '.' || ln[i] == '_') { // any other allowed chars?
72                                         start = i;
73                                         continue;
74                                 }
75                                 break;
76                         }
77                         
78                         
79                         var complete_string = ln.substring(start, offset - start);
80                         GLib.debug("complete string = %s", complete_string);
81                         
82                         
83                  
84                         // completion rules??
85                         
86                         // Roo......
87                         
88                         // this. (based on the node type)
89                         // this.xxx // Node and any determination.
90                         
91                         // keywords... // text does not contains "."
92                         
93                         if (!complete_string.contains(".")) {
94                                 // string does not have a '.'
95                                 // offer up this / Roo / javascript keywords... / look for var string = .. in the code..
96                                 for(var i = 0; i <  JsRender.Lang.match_strings.size ; i++) {
97                                         var str = JsRender.Lang.match_strings.get(i);
98                                         var sci = new  Lsp.CompletionItem.keyword(str, str, "keywords : %s".printf(str));
99                                         ret.items.add(sci);
100                                                  
101                                         
102                                         
103                                         
104                                 }
105                                 if (complete_string != "Roo" && "Roo".has_prefix(complete_string)  ) { 
106                                         // should we ignore exact matches... ???
107                                         var sci =  new Lsp.CompletionItem.keyword("Roo", "Roo", "Roo - A Roo class" );
108                                         ret.items.add(sci);
109
110                                          
111                                 }
112                                 if (complete_string != "_this" && "_this".has_prefix(  complete_string) ) { 
113                                         // should we ignore exact matches... ???
114                                         
115                                         var sci =  new Lsp.CompletionItem.keyword("_this", "_this",   "Reference to the global pointer to the files main class instance");
116                                         ret.items.add(sci);
117                                          
118                                          
119                                 }
120                                 return ret;
121                         }
122                         // got at least one ".".
123                         var parts = complete_string.split(".");
124                         var curtype = "";
125                         var cur_instance = false;
126                         if (parts[0] == "_this") {
127                                 if (file.tree == null) {
128
129                                         GLib.debug("file has no tree");
130                                         return ret; // no idea..
131                                 }
132                                 curtype = file.tree.fqn();
133                                 cur_instance = true;                            
134                                 // work out from the node, what the type is...
135                                 // fetch node from element.
136
137                                 //curtype = node.fqn();
138                                 cur_instance = true;
139                         }
140                         
141                         
142                         if (parts[0] == "this") {
143                                 // work out from the node, what the type is...
144                                 // fetch node from element.
145                                 var node = file.lineToNode(line -1); // hopefuly
146                                 if (node == null) {
147                                         GLib.debug("could nt find scope for 'this'");
148                                         return ret; // no idea..
149                                 }
150                                 curtype = node.fqn();
151                                 cur_instance = true;
152                         }
153                         if (parts[0] == "Roo") {        
154                                 curtype = "Roo";
155                                 cur_instance = false;
156                         }
157                                         
158                         var prevbits = parts[0] + ".";
159                         for(var i =1; i < parts.length; i++) {
160                                 GLib.debug("matching %d/%d\n", i, parts.length);
161
162                                 var is_last = i == parts.length -1;     
163                                 // look up all the properties of the type...
164                                 var cls = this.project.palete.getClass(curtype);
165                                 if (cls == null) {
166                                         GLib.debug("could not get class of curtype '%s'\n", curtype);
167                                         return ret;
168                                 }
169
170                                 if (!is_last) {
171                                 
172                                         // only exact matches from here on...
173                                         if (cur_instance) {
174                                                 if (cls.props.has_key(parts[i])) {
175                                                         var prop = cls.props.get(parts[i]);
176                                                         if (prop.type.index_of(".",0) > -1) {
177                                                                 // type is another roo object..
178                                                                 curtype = prop.type;
179                                                                 prevbits += parts[i] + ".";
180                                                                 continue;
181                                                         }
182                                                         return ret;
183                                                 }
184                                                 
185                                                 
186                                                 
187                                                 // check methods?? - we do not export that at present..
188                                                 return ret;      //no idea...
189                                         }
190                                 
191                                         // not a instance..
192                                         //look for child classes.
193                                         var citer = this.project.palete.classes.map_iterator();
194                                         var foundit = false;
195                                         while (citer.next()) {
196                                                 var scls = citer.get_key();
197                                                 var look = prevbits + parts[i];
198                                                 if (scls.index_of(look,0) != 0) {
199                                                         continue;
200                                                 }
201                                                 // got a starting match..
202                                                 curtype = look;
203                                                 cur_instance = false;
204                                                 foundit =true;
205                                                 break;
206                                         }
207                                         if (!foundit) {
208                                                 return ret;
209                                         }
210                                         prevbits += parts[i] + ".";
211                                         continue;
212                                 }
213                                 // got to the last element..
214                                 GLib.debug("Got last element\n");
215                                 if (curtype == "") { // should not happen.. we would have returned already..
216                                         return ret;
217                                 }
218                                 GLib.debug("Got last element type %s\n",curtype);
219                                 if (!cur_instance) {
220                                         GLib.debug("matching instance");
221                                         // it's a static reference..
222                                         var citer = this.project.palete.classes.map_iterator();
223                                         while (citer.next()) {
224                                                 var scls = citer.get_key();
225                                                 var look = prevbits + parts[i];
226                                                 if (parts[i].length > 0 && scls.index_of(look,0) != 0) {
227                                                         continue;
228                                                 }
229                                                 var sci =  new Lsp.CompletionItem.keyword(scls,scls, "doc??" );
230                                                 ret.items.add(sci);
231
232                                                  
233                                         }
234                                         return ret;
235                                 }
236                                 GLib.debug("matching property");
237                                 
238                                 
239                                 
240                                 var citer = cls.methods.map_iterator();
241                                 while (citer.next()) {
242                                         var prop = citer.get_value();
243                                         // does the name start with ...
244                                         if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
245                                                 continue;
246                                         }
247                                         // got a matching property...
248                                         // return type?
249                                         
250                                         var sci =  new Lsp.CompletionItem.keyword( prop.name + "(", prop.name + "(" , prop.doctxt );
251                                         ret.items.add(sci);
252
253                                  
254                                          
255                                 }
256                                 
257                                 // get the properties / methods and subclasses.. of cls..
258                                 // we have cls.. - see if the string matches any of the properties..
259                                 citer = cls.props.map_iterator();
260                                 while (citer.next()) {
261                                         var prop = citer.get_value();
262                                         // does the name start with ...
263                                         //if (parts[i].length > 0 && prop.name.index_of(parts[i],0) != 0) {
264                                         //      continue;
265                                         //}
266                                         
267                                         var sci =  new Lsp.CompletionItem.keyword( prop.name, prop.name , prop.doctxt );
268                                         ret.items.add(sci);
269  
270                                 
271                                 }
272                                          
273                                         
274                                 return ret;     
275                                         
276                                         
277                                 
278                                         
279                                 
280                         }
281                          
282                         
283                         
284                         return ret;
285                 
286                 }
287                  
288                 public override async  Lsp.Hover hover (JsRender.JsRender file, int line, int offset) throws GLib.Error {
289                         return new Lsp.Hover();
290                 }
291                 public override void queueDocumentSymbols (JsRender.JsRender file) { }
292                 public override async Gee.ArrayList<Lsp.DocumentSymbol> documentSymbols (JsRender.JsRender file) throws GLib.Error {
293                         var ret = new Gee.ArrayList<Lsp.DocumentSymbol>();      
294                         return ret;
295                 }
296                 public override async Gee.ArrayList<Lsp.SignatureInformation> signatureHelp (JsRender.JsRender file, int line, int offset) throws GLib.Error
297                 {
298                         return new Gee.ArrayList<Lsp.SignatureInformation>();   
299                 }
300                 public override async Gee.ArrayList<Lsp.SymbolInformation> symbol (string sym) throws GLib.Error 
301                 {
302                         return new Gee.ArrayList<Lsp.SymbolInformation>();
303                 }
304                 
305         }
306         
307 }