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