1 
2 /*
3  * glspi_sci.c - This file is part of the Lua scripting plugin for the Geany IDE
4  * See the file "geanylua.c" for copyright information.
5  */
6 
7 #define NEED_FAIL_ARG_TYPE
8 #define NEED_FAIL_ELEM_TYPE
9 
10 #include "glspi.h"
11 #include "glspi_sci.h"
12 
13 
14 /* Get or Set the entire text of the currently active Geany document */
glspi_text(lua_State * L)15 static gint glspi_text(lua_State* L)
16 {
17 
18 	GeanyDocument *doc = document_get_current();
19 
20 	if (!doc) { return 0; }
21 	if (0 == lua_gettop(L)) { /* Called with no args, GET the current text */
22 		gchar *txt = sci_get_contents(doc->editor->sci, -1);
23 		lua_pushstring(L, txt ? txt : "");
24 		g_free(txt);
25 		return 1;
26 	} else { /* Called with one arg, SET the current text */
27 		const gchar*txt;
28 		if (!lua_isstring(L, 1)) {
29 			return FAIL_STRING_ARG(1);
30 		}
31 		txt = lua_tostring(L, 1);
32 		sci_set_text(doc->editor->sci, txt);
33 		return 0;
34 	}
35 }
36 
37 
38 /* Get or Set the selection text of the currently active Geany document */
glspi_selection(lua_State * L)39 static gint glspi_selection(lua_State* L)
40 {
41 
42 	DOC_REQUIRED
43 	if (0 == lua_gettop(L)) { /* Called with no args, GET the selection */
44 		gchar *txt = sci_get_selection_contents(doc->editor->sci);
45 		lua_pushstring(L, txt ? txt : "");
46 		g_free(txt);
47 		return 1;
48 	} else { /* Called with one arg, SET the selection */
49 		const gchar*txt=NULL;
50 		if (!lua_isstring(L, 1)) { return FAIL_STRING_ARG(1); }
51 		txt = lua_tostring(L, 1);
52 		sci_replace_sel(doc->editor->sci, txt);
53 		return 0;
54 	}
55 }
56 
57 
58 
59 /* Set or get the endpoints of the scintilla selection */
glspi_select(lua_State * L)60 static gint glspi_select(lua_State* L)
61 {
62 	gint argc=lua_gettop(L);
63 	gint sel_start, sel_end;
64 	gboolean rectsel=FALSE;
65 	DOC_REQUIRED
66 	if (0==argc) {
67 		rectsel=scintilla_send_message(doc->editor->sci, SCI_SELECTIONISRECTANGLE, 0, 0);
68 	}
69 
70 	lua_getglobal(L, LUA_MODULE_NAME);
71 	if ( lua_istable(L, -1) ) {
72 		lua_pushstring(L,tokenRectSel);
73 		lua_gettable(L, -2);
74 		if ( (argc>0) && lua_isboolean(L, -1) ) {
75 			rectsel=lua_toboolean(L, -1);
76 		} else {
77 			lua_getglobal(L, LUA_MODULE_NAME);
78 			lua_pushstring(L, tokenRectSel);
79 			lua_pushboolean(L, rectsel);
80 			lua_settable(L, -3);
81 		}
82 	}
83 	if (0==argc) {
84 		sel_end=sci_get_current_position(doc->editor->sci);
85 		sel_start=scintilla_send_message(doc->editor->sci, SCI_GETANCHOR, 0, 0);
86 		push_number(L, sel_start);
87 		push_number(L, sel_end);
88 		return 2;
89 	} else {
90 		if (!lua_isnumber(L, 1)) { return FAIL_NUMERIC_ARG(1);	}
91 		sel_start=lua_tonumber(L,1);
92 		if (1==argc) {
93 			sel_end=sel_start;
94 		} else {
95 			if (!lua_isnumber(L, 2)) { return FAIL_NUMERIC_ARG(2); }
96 			sel_end=lua_tonumber(L,2);
97 		}
98 		scintilla_send_message(doc->editor->sci,
99 			SCI_SETSELECTIONMODE, rectsel?SC_SEL_RECTANGLE:SC_SEL_STREAM, 0);
100 		sci_set_current_position(doc->editor->sci, sel_end, FALSE);
101 		scintilla_send_message(doc->editor->sci, SCI_SETANCHOR, sel_start, 0);
102 		sci_ensure_line_is_visible(doc->editor->sci,
103 			sci_get_line_from_position(doc->editor->sci, sel_end));
104 		sci_scroll_caret(doc->editor->sci);
105 		scintilla_send_message(doc->editor->sci,
106 			SCI_SETSELECTIONMODE, rectsel?SC_SEL_RECTANGLE:SC_SEL_STREAM, 0);
107 		return 0;
108 	}
109 }
110 
111 
112 /* Returns the total number of lines in the current document */
glspi_height(lua_State * L)113 static gint glspi_height(lua_State* L)
114 {
115 	DOC_REQUIRED
116 	push_number(L, sci_get_line_count(doc->editor->sci));
117 	return 1;
118 }
119 
120 
121 /* Returns the total number of characters in the current document */
glspi_length(lua_State * L)122 static gint glspi_length(lua_State* L)
123 {
124 	DOC_REQUIRED
125 	push_number(L, sci_get_length(doc->editor->sci));
126 	return 1;
127 }
128 
129 
130 
131 /* Get or set the caret position */
glspi_caret(lua_State * L)132 static gint glspi_caret(lua_State* L)
133 {
134 	DOC_REQUIRED
135 	if (lua_gettop(L)==0) {
136 		push_number(L,sci_get_current_position(doc->editor->sci));
137 		return 1;
138 	} else {
139 		if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
140 		sci_set_current_position(doc->editor->sci,(gint)lua_tonumber(L,1),TRUE);
141 		return 0;
142 	}
143 }
144 
145 
146 /*
147 	Translate between rectangular (line/column) and linear (position) locations.
148 */
glspi_rowcol(lua_State * L)149 static gint glspi_rowcol(lua_State* L)
150 {
151 	gint argc=lua_gettop(L);
152 	gint line,col,pos,len,cnt;
153 	DOC_REQUIRED
154 	switch (argc) {
155 		case 0:
156 		case 1:
157 			if (argc==0) {
158 				pos=sci_get_current_position(doc->editor->sci);
159 			} else {
160 				if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
161 				pos=lua_tonumber(L,1);
162 				if ( pos < 0 ) {
163 					pos=0;
164 				} else {
165 					len=sci_get_length(doc->editor->sci);
166 					if ( pos >= len ) { pos=len-1; }
167 				}
168 			}
169 			line=sci_get_line_from_position(doc->editor->sci,pos);
170 			col=sci_get_col_from_position(doc->editor->sci,pos);
171 			push_number(L,line+1);
172 			push_number(L,col);
173 			return 2;
174 		default:
175 			if (!lua_isnumber(L,2)) { return FAIL_NUMERIC_ARG(2); }
176 			if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
177 			line=lua_tonumber(L,1);
178 			if ( line < 1 ) {
179 				line=1;
180 			} else {
181 				cnt=sci_get_line_count(doc->editor->sci);
182 				if ( line > cnt ) { line=cnt; }
183 			}
184 			col=lua_tonumber(L,2);
185 			if ( col < 0 ) {
186 				col=0;
187 			} else {
188 				len=sci_get_line_length(doc->editor->sci,line);
189 				if (col>=len) {col=len-1;}
190 			}
191 			pos=sci_get_position_from_line(doc->editor->sci,line-1)+col;
192 			push_number(L,pos);
193 			return 1;
194 	}
195 }
196 
197 
198 /* Set or unset the undo marker */
glspi_batch(lua_State * L)199 static gint glspi_batch(lua_State* L)
200 {
201 	DOC_REQUIRED
202 	if ( (lua_gettop(L)==0) || (!lua_isboolean(L,1)) ) {
203 		return FAIL_BOOL_ARG(1);
204 	}
205 	if (lua_toboolean(L,1)) {
206 		sci_start_undo_action(doc->editor->sci);
207 	} else {
208 		sci_end_undo_action(doc->editor->sci);
209 	}
210 	return 0;
211 }
212 
213 
214 
215 /* Return the "word" at the given position */
glspi_word(lua_State * L)216 static gint glspi_word(lua_State* L)
217 {
218 	const gchar* word_chars = GEANY_WORDCHARS;
219 	gint pos,linenum, bol, bow, eow;
220 	gchar *text=NULL;
221 	DOC_REQUIRED
222 	if (lua_gettop(L)>0) {
223 		if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
224 		pos=lua_tonumber(L,1);
225 	} else {
226 		pos = sci_get_current_position(doc->editor->sci);
227 	}
228 	linenum = sci_get_line_from_position(doc->editor->sci, pos);
229 	bol = sci_get_position_from_line(doc->editor->sci, linenum);
230 	bow = pos - bol;
231 	eow = pos - bol;
232 	text=sci_get_line(doc->editor->sci, linenum);
233 	lua_getglobal(L, LUA_MODULE_NAME);
234 	if ( lua_istable(L, -1) ) {
235 		lua_pushstring(L,tokenWordChars);
236 		lua_gettable(L, -2);
237 		if (lua_isstring(L, -1)) {
238 			word_chars=lua_tostring(L, -1);
239 		} else {
240 			lua_getglobal(L, LUA_MODULE_NAME);
241 			lua_pushstring(L,tokenWordChars);
242 			lua_pushstring(L,word_chars);
243 			lua_settable(L, -3);
244 		}
245 	}
246 	while ( (bow>0) && (strchr(word_chars,text[bow-1])!=NULL) ) {bow--;}
247 	while (text[eow] && (strchr(word_chars, text[eow])!=NULL) ) {eow++;}
248 	text[eow]='\0';
249 	lua_pushstring(L, text+bow);
250 	g_free(text);
251 	return 1;
252 }
253 
254 
255 
256 /*
257 	Pushes the line of text onto the Lua stack from the specified
258 	line number. Return FALSE only if the index is out of bounds.
259 */
get_line_text(GeanyDocument * doc,gint linenum)260 static gchar* get_line_text(GeanyDocument*doc,gint linenum)
261 {
262 	gint count=sci_get_line_count(doc->editor->sci);
263 	if ((linenum>0)&&(linenum<=count)) {
264 		gchar *text=sci_get_line(doc->editor->sci, linenum-1);
265 		return text?text:g_strdup("");
266 	} else {
267 		return FALSE;
268 	}
269 }
270 
271 
272 
273 /*
274 	Lua "closure" function to iterate through each line in the current document
275 */
lines_closure(lua_State * L)276 static gint lines_closure(lua_State *L)
277 {
278 	gint idx=lua_tonumber(L, lua_upvalueindex(1))+1;
279 	GeanyDocument *doc=lua_touserdata(L,lua_upvalueindex(2));
280 	gchar *text=get_line_text(doc,idx);
281 	if ( text ) {
282 		push_number(L, idx);
283 		lua_pushvalue(L, -1);
284 		lua_replace(L, lua_upvalueindex(1));
285 		lua_pushstring(L,text);
286 		g_free(text);
287 		return 2;
288 	} else {
289 		return 0;
290 	}
291 }
292 
293 
294 
295 /* Access the individual lines in the current document */
glspi_lines(lua_State * L)296 static gint glspi_lines(lua_State* L)
297 {
298 	DOC_REQUIRED
299 	if (lua_gettop(L)==0) {
300 		push_number(L,0);
301 		lua_pushlightuserdata(L,doc); /* Pass the doc pointer to our iterator */
302 		lua_pushcclosure(L, &lines_closure, 2);
303 		return 1;
304 	} else {
305 		int idx;
306 		gchar *text;
307 		if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
308 		idx=lua_tonumber(L,1);
309 		text=get_line_text(doc,idx);
310 		if (text) {
311 			lua_pushstring(L,text);
312 			g_free(text);
313 			return 1;
314 		} else {
315 			return 0;
316 		}
317 	}
318 }
319 
320 
321 
322 
get_sci_nav_cmd(const gchar * str,gboolean fwd,gboolean sel,gboolean rect)323 static gint get_sci_nav_cmd(const gchar*str, gboolean fwd, gboolean sel, gboolean rect)
324 {
325 	if (g_ascii_strncasecmp(str, "char", 4) == 0) {
326 		if (fwd) {
327 			return sel?(rect?SCI_CHARRIGHTRECTEXTEND:SCI_CHARRIGHTEXTEND):SCI_CHARRIGHT;
328 		} else {
329 			return sel?(rect?SCI_CHARLEFTRECTEXTEND:SCI_CHARLEFTEXTEND):SCI_CHARLEFT;
330 		}
331 	} else if (g_ascii_strncasecmp(str, "word", 4) == 0) {
332 		if (fwd) {
333 			return sel?SCI_WORDRIGHTEXTEND:SCI_WORDRIGHT;
334 		} else {
335 			return sel?SCI_WORDLEFTEXTEND:SCI_WORDLEFT;
336 		}
337 	} else if (g_ascii_strncasecmp(str, "part", 4) == 0) {
338 		if (fwd) {
339 			return sel?SCI_WORDPARTRIGHTEXTEND:SCI_WORDPARTRIGHT;
340 		} else {
341 			return sel?SCI_WORDPARTLEFTEXTEND:SCI_WORDPARTLEFT;
342 		}
343 	} else if (g_ascii_strncasecmp(str, "edge", 4) == 0) {
344 		if (fwd) {
345 			return sel?(rect?SCI_LINEENDRECTEXTEND:SCI_LINEENDEXTEND):SCI_LINEEND;
346 		} else {
347 			return sel?(rect?SCI_HOMERECTEXTEND:SCI_HOMEEXTEND):SCI_HOME;
348 		}
349 	} else if (g_ascii_strncasecmp(str, "line", 4) == 0) {
350 		if (fwd) {
351 			return sel?(rect?SCI_LINEDOWNRECTEXTEND:SCI_LINEDOWNEXTEND):SCI_LINEDOWN;
352 		} else {
353 			return sel?(rect?SCI_LINEUPRECTEXTEND:SCI_LINEUPEXTEND):SCI_LINEUP;
354 		}
355 	} else if (g_ascii_strncasecmp(str, "para", 4) == 0) {
356 		if (fwd) {
357 			return sel?SCI_PARADOWNEXTEND:SCI_PARADOWN;
358 		} else {
359 			return sel?SCI_PARAUPEXTEND:SCI_PARAUP;
360 		}
361 	} else if (g_ascii_strncasecmp(str, "page", 4) == 0) {
362 		if (fwd) {
363 			return sel?(rect?SCI_PAGEDOWNRECTEXTEND:SCI_PAGEDOWNEXTEND):SCI_PAGEDOWN;
364 		} else {
365 			return sel?(rect?SCI_PAGEUPRECTEXTEND:SCI_PAGEUPEXTEND):SCI_PAGEUP;
366 		}
367 	} else if (g_ascii_strncasecmp(str, "body", 4) == 0) {
368 		if (fwd) {
369 			return sel?SCI_DOCUMENTENDEXTEND:SCI_DOCUMENTEND;
370 		} else {
371 			return sel?SCI_DOCUMENTSTARTEXTEND:SCI_DOCUMENTSTART;
372 		}
373 	} else return SCI_NULL;
374 }
375 
376 
377 
378 
379 
380 
glspi_navigate(lua_State * L)381 static gint glspi_navigate(lua_State* L)
382 {
383 	gint scicmd;
384 	const gchar *strcmd="char";
385 	gboolean sel=FALSE;
386 	gboolean fwd=TRUE;
387 	gboolean rect=FALSE;
388 	gint count=1;
389 	DOC_REQUIRED
390 	switch (lua_gettop(L)){
391 		case 0: break;
392 		case 4:
393 			if (!lua_isboolean(L,4)) { return FAIL_BOOL_ARG(4); }
394 			rect=lua_toboolean(L,4);
395 		case 3:
396 			if (!lua_isboolean(L,3)) { return FAIL_BOOL_ARG(3); }
397 			sel=lua_toboolean(L,3);
398 		case 2:
399 			if (!lua_isnumber(L,2)) { return FAIL_NUMERIC_ARG(2); }
400 			count=lua_tonumber(L,2);
401 			if (count<0) {
402 				fwd=FALSE;
403 				count=0-count;
404 			}
405 		case 1:
406 			if (!lua_isstring(L,1)) { return FAIL_STRING_ARG(1); }
407 			strcmd=lua_tostring(L,1);
408 	}
409 	scicmd=get_sci_nav_cmd(strcmd,fwd,sel, rect);
410 	if ( SCI_NULL == scicmd ) {
411 		lua_pushfstring(
412 			L, _( "Error in module \"%s\" at function navigate():\n"
413 						"unknown navigation mode \"%s\" for argument #1.\n"),
414 						LUA_MODULE_NAME, strcmd);
415 		lua_error(L);
416 	} else {
417 		gint n;
418 		for (n=0; n<count; n++) {
419 			sci_send_command(doc->editor->sci,scicmd);
420 		}
421 	}
422 	return 0;
423 }
424 
425 
426 
swap(gint * a,gint * b)427 static void swap(gint*a,gint*b)
428 {
429 	gint tmp=*a;
430 	*a=*b;
431 	*b=tmp;
432 }
433 
434 
glspi_copy(lua_State * L)435 static gint glspi_copy(lua_State* L)
436 {
437 	const gchar *content=NULL;
438 	gint start=-1, stop=-1;
439 	gint len=0;
440 	DOC_REQUIRED
441 
442 
443 	switch (lua_gettop(L)) {
444 		case 0:
445 			start=sci_get_selection_start(doc->editor->sci);
446 			stop=sci_get_selection_end(doc->editor->sci);
447 			if (start>stop) { swap(&start,&stop); }
448 			if (start!=stop) sci_send_command(doc->editor->sci, SCI_COPY);
449 			push_number(L, stop-start);
450 			return 1;
451 		case 1:
452 			if (!lua_isstring(L,1)) {return FAIL_STRING_ARG(1);}
453 			content=lua_tostring(L,1);
454 			len=strlen(content);
455 			if (len) { scintilla_send_message(doc->editor->sci,SCI_COPYTEXT,len,(sptr_t)content); }
456 			push_number(L, len);
457 			return 1;
458 		default:
459 			if (!lua_isnumber(L,2)) { return FAIL_NUMERIC_ARG(2); }
460 			if (!lua_isnumber(L,1)) { return FAIL_NUMERIC_ARG(1); }
461 			start=lua_tonumber(L,1);
462 			stop=lua_tonumber(L,2);
463 			if (start<0) { return FAIL_UNSIGNED_ARG(1); }
464 			if (stop <0) { return FAIL_UNSIGNED_ARG(2); }
465 			if (start>stop) { swap(&start,&stop); }
466 			if (start!=stop) scintilla_send_message(doc->editor->sci,SCI_COPYRANGE,start,stop);
467 			push_number(L, stop-start);
468 			return 1;
469 	}
470 }
471 
472 
473 
glspi_cut(lua_State * L)474 static gint glspi_cut(lua_State* L)
475 {
476 	gint start,stop,len;
477 	DOC_REQUIRED
478 	start=sci_get_selection_start(doc->editor->sci);
479 	stop=sci_get_selection_end(doc->editor->sci);
480 	len=sci_get_length(doc->editor->sci);
481 	if (start>stop) {swap(&start,&stop); }
482 	if (start!=stop) {sci_send_command(doc->editor->sci, SCI_CUT); }
483 	push_number(L,len-sci_get_length(doc->editor->sci));
484 	return 1;
485 }
486 
487 
488 
489 
490 
glspi_paste(lua_State * L)491 static gint glspi_paste(lua_State* L)
492 {
493 	DOC_REQUIRED
494 	if (scintilla_send_message(doc->editor->sci,SCI_CANPASTE,0,0)) {
495 		gint len=sci_get_length(doc->editor->sci);
496 		sci_send_command(doc->editor->sci,SCI_PASTE);
497 		push_number(L,sci_get_length(doc->editor->sci)-len);
498 	} else {
499 		lua_pushnil(L);
500 	}
501 	return 1;
502 }
503 
504 
505 
glspi_match(lua_State * L)506 static gint glspi_match(lua_State* L)
507 {
508 	gint pos;
509 	DOC_REQUIRED
510 	if (lua_gettop(L)==0) {
511 		pos=sci_get_current_position(doc->editor->sci);
512 	} else {
513 		if ( !lua_isnumber(L,1) ) {return FAIL_NUMERIC_ARG(1);}
514 		pos=lua_tonumber(L,1);
515 	}
516 	push_number(L,sci_find_matching_brace(doc->editor->sci,pos));
517 	return 1;
518 }
519 
520 
521 
522 
glspi_byte(lua_State * L)523 static gint glspi_byte(lua_State* L)
524 {
525 	gint pos;
526 	DOC_REQUIRED
527 	if (lua_gettop(L)==0) {
528 		pos=sci_get_current_position(doc->editor->sci);
529 	} else {
530 		if ( !lua_isnumber(L,1) ) {return FAIL_NUMERIC_ARG(1);}
531 		pos=lua_tonumber(L,1);
532 	}
533 	push_number(L,sci_get_char_at(doc->editor->sci,pos));
534 	return 1;
535 }
536 
537 
538 
539 
540 
541 static GHashTable*sci_cmd_hash=NULL;
542 
glspi_init_sci_cmd_hash(void)543 static void glspi_init_sci_cmd_hash(void)
544 {
545 	gint i;
546 	sci_cmd_hash=g_hash_table_new(g_str_hash,g_str_equal);
547 	for (i=0; sci_cmd_hash_entries[i].name; i++) {
548 		g_hash_table_insert(
549 			sci_cmd_hash,
550 			(gpointer) sci_cmd_hash_entries[i].name,&sci_cmd_hash_entries[i]);
551 	}
552 }
553 
554 
glspi_free_sci_cmd_hash(void)555 static void glspi_free_sci_cmd_hash(void) {
556 	if (sci_cmd_hash) {
557 		g_hash_table_destroy(sci_cmd_hash);
558 		sci_cmd_hash=NULL;
559 	}
560 }
561 
glspi_set_sci_cmd_hash(gboolean create)562 void glspi_set_sci_cmd_hash(gboolean create) {
563 	if (create) {
564 		glspi_init_sci_cmd_hash ();
565 	} else {
566 		glspi_free_sci_cmd_hash();
567 	}
568 }
569 
570 
lookup_cmd_id(gint cmd)571 static SciCmdHashEntry* lookup_cmd_id(gint cmd)
572 {
573 	gint i;
574 	for (i=0;sci_cmd_hash_entries[i].name; i++) {
575 		if (sci_cmd_hash_entries[i].msgid==cmd) { return &sci_cmd_hash_entries[i];}
576 	}
577 	return NULL;
578 }
579 
580 
581 #define lookup_cmd_str(cmd) g_hash_table_lookup(sci_cmd_hash,cmd);
582 
583 
584 
glspi_fail_not_implemented(lua_State * L,const gchar * funcname,const gchar * cmdname)585 static gint glspi_fail_not_implemented(lua_State* L, const gchar*funcname, const gchar*cmdname)
586 {
587 	lua_pushfstring(
588 		L, _( "Error in module \"%s\" at function %s():\n"
589 			"API command \"%s\" not implemented.\n"),
590 		LUA_MODULE_NAME, &funcname[6], cmdname);
591 	lua_error(L);
592 	return 0;
593 }
594 
595 
glspi_fail_arg_count(lua_State * L,const gchar * funcname,const gchar * cmdname)596 static gint glspi_fail_arg_count(lua_State* L, const gchar*funcname, const gchar*cmdname)
597 {
598 	lua_pushfstring(
599 		L, _( "Error in module \"%s\" at function %s():\n"
600 			"not enough arguments for command \"%s\".\n"),
601 		LUA_MODULE_NAME, &funcname[6], cmdname);
602 	lua_error(L);
603 	return 0;
604 }
605 
606 
607 
608 #define FAIL_API glspi_fail_not_implemented(L,__FUNCTION__,he->name)
609 
610 #define FAIL_ARGC glspi_fail_arg_count(L,__FUNCTION__,he->name)
611 
glspi_scintilla(lua_State * L)612 static gint glspi_scintilla(lua_State* L)
613 {
614 	uptr_t wparam=0;
615 	sptr_t lparam=0;
616 	SciCmdHashEntry*he=NULL;
617 	gint argc=lua_gettop(L);
618 	gchar*resultbuf=NULL;
619 	gint bufsize=0;
620 	DOC_REQUIRED
621 	if (argc==0) { return FAIL_STRING_ARG(1); }
622 
623 	if (lua_isnumber(L,1)) {
624 		he=lookup_cmd_id((gint)lua_tonumber(L,1));
625 	} else {
626 		if (lua_isstring(L,1)) {
627 			gchar cmdbuf[64];
628 			gint i;
629 			memset(cmdbuf,'\0', sizeof(cmdbuf));
630 			strncpy(cmdbuf,lua_tostring(L,1),sizeof(cmdbuf)-1);
631 			for (i=0;cmdbuf[i];i++) {cmdbuf[i]=g_ascii_toupper(cmdbuf[i]);}
632 			he=lookup_cmd_str((strncmp(cmdbuf,"SCI_",4)==0)?&cmdbuf[4]:cmdbuf);
633 		} else { return FAIL_STRING_ARG(1); }
634 	}
635 	if ( !he ) {
636 		lua_pushfstring(
637 			L, _( "Error in module \"%s\" at function %s():\n"
638 				"unknown command \"%s\" given for argument #1.\n"),
639 			LUA_MODULE_NAME, &__FUNCTION__[6], lua_tostring(L,1));
640 		lua_error(L);
641 		return 0;
642 	}
643 
644 	if (((he->wparam==SLT_INT)&&(he->lparam==SLT_STRINGRESULT))) {
645 		/* We can allow missing wparam (length) for some string result types */
646 	} else {
647 		if ((he->lparam!=SLT_VOID)&&(argc<3)) { return FAIL_ARGC; }
648 		if (((he->wparam!=SLT_VOID)&&(argc<2))) { return FAIL_ARGC; }
649 	}
650 	switch (he->wparam) {
651 		case SLT_VOID:
652 		break;
653 		case SLT_INT:
654 			if (argc>=2) {
655 				if (!lua_isnumber(L,2)) {return FAIL_NUMERIC_ARG(2); };
656 				wparam=lua_tonumber(L,2);
657 			}
658 			break;
659 		case SLT_STRING:
660 			if (!lua_isstring(L,2)) {return FAIL_STRING_ARG(2); };
661 			wparam=(uptr_t)lua_tostring(L,2);
662 		break;
663 		case SLT_CELLS: return FAIL_API;
664 		case SLT_BOOL:
665 			if (!lua_isboolean(L,2)) {return FAIL_BOOL_ARG(2); };
666 			wparam=lua_toboolean(L,2);
667 		break;
668 		case SLT_TEXTRANGE: return FAIL_API;
669 		case SLT_STRINGRESULT: return FAIL_API;
670 		case SLT_FINDTEXT: return FAIL_API;
671 		case SLT_FORMATRANGE: return FAIL_API;
672 		default:return FAIL_API;
673 	}
674 
675 	switch (he->lparam) {
676 		case SLT_VOID:
677 		break;
678 		case SLT_INT:
679 			if (!lua_isnumber(L,3)) { return FAIL_NUMERIC_ARG(2); };
680 			lparam=lua_tonumber(L,3);
681 		break;
682 		case SLT_STRING:
683 			if (!lua_isstring(L,3)) {return FAIL_STRING_ARG(2); };
684 			lparam=(sptr_t)lua_tostring(L,3);
685 		break;
686 		case SLT_CELLS: return FAIL_API;
687 		case SLT_BOOL:
688 			if (!lua_isboolean(L,3)) {return FAIL_BOOL_ARG(3); };
689 			lparam=lua_toboolean(L,3);
690 			break;
691 		case SLT_TEXTRANGE: return FAIL_API;
692 		case SLT_STRINGRESULT:
693 			if ((he->msgid==SCI_GETTEXT)&&(wparam==0)) {
694 				wparam=scintilla_send_message(doc->editor->sci, SCI_GETLENGTH, 0,0);
695 			}
696 			switch (he->msgid) {
697 				case SCI_GETTEXT:
698 					if (wparam==0){
699 						wparam=scintilla_send_message(doc->editor->sci, SCI_GETLENGTH, 0,0);
700 					} else { wparam++; }
701 					break;
702 				case SCI_GETCURLINE:
703 					if (wparam>0) { wparam++; }
704 					break;
705 			}
706 			bufsize=scintilla_send_message(doc->editor->sci, he->msgid, wparam, 0);
707 			if (bufsize) {
708 				resultbuf=g_malloc0((guint)(bufsize+1));
709 				lparam=(sptr_t)resultbuf;
710 			} else {
711 				lua_pushnil(L);
712 				return 1;
713 			}
714 			break;
715 		case SLT_FINDTEXT: return FAIL_API;
716 		case SLT_FORMATRANGE: return FAIL_API;
717 		default:return FAIL_API;
718 	}
719 	switch (he->result) {
720 		case SLT_VOID:
721 			scintilla_send_message(doc->editor->sci, he->msgid, wparam, lparam);
722 			lua_pushnil(L);
723 			return 1;
724 		case SLT_INT:
725 			if (he->lparam==SLT_STRINGRESULT) {
726 				scintilla_send_message(doc->editor->sci, he->msgid, wparam, lparam);
727 				lua_pushstring(L,resultbuf);
728 				g_free(resultbuf);
729 			} else {
730 				push_number(L, scintilla_send_message(doc->editor->sci, he->msgid, wparam, lparam));
731 			}
732 			return 1;
733 		case SLT_BOOL:
734 			lua_pushboolean(L, scintilla_send_message(doc->editor->sci, he->msgid, wparam, lparam));
735 			return 1;
736 		default:return FAIL_API;
737 	}
738 }
739 
glspi_find(lua_State * L)740 static gint glspi_find(lua_State* L)
741 {
742 	struct Sci_TextToFind ttf;
743 
744 	gint flags=0;
745 	gint i,n;
746 	gchar *text;
747 	DOC_REQUIRED
748 	switch (lua_gettop(L)) {
749 		case 0:return FAIL_STRING_ARG(1);
750 		case 1:return FAIL_NUMERIC_ARG(2);
751 		case 2:return FAIL_NUMERIC_ARG(3);
752 		case 3:return FAIL_TABLE_ARG(4);
753 	}
754 
755 	if (!lua_isstring(L,1)) { return FAIL_STRING_ARG(1); }
756 	if (!lua_isnumber(L,2)) { return FAIL_NUMERIC_ARG(2); }
757 	if (!lua_isnumber(L,3)) { return FAIL_NUMERIC_ARG(3); }
758 	if (!lua_istable(L,4)) { return FAIL_TABLE_ARG(4); }
759 
760 	text=g_strdup(lua_tostring(L,1));
761 	ttf.lpstrText=text;
762 	ttf.chrg.cpMin=lua_tonumber(L,2);
763 	ttf.chrg.cpMax=lua_tonumber(L,3);
764 
765 	n=lua_objlen(L,4);
766 	for (i=1;i<=n; i++) {
767 		lua_rawgeti(L,4,i);
768 		if (lua_isstring(L, -1)) {
769 			const gchar*flagname=lua_tostring(L,-1);
770 			if (g_ascii_strcasecmp(flagname, "matchcase")==0){
771 				flags += SCFIND_MATCHCASE;
772 			} else if (g_ascii_strcasecmp(flagname, "wholeword")==0) {
773 				flags += SCFIND_WHOLEWORD;
774 			} else if (g_ascii_strcasecmp(flagname, "wordstart")==0) {
775 				flags += SCFIND_WORDSTART;
776 			} else if (g_ascii_strcasecmp(flagname, "regexp")==0) {
777 				flags += SCFIND_REGEXP;
778 			} else if (g_ascii_strcasecmp(flagname, "posix")==0) {
779 				flags += SCFIND_POSIX;
780 			} else {
781 				lua_pushfstring(L, _("Error in module \"%s\" at function %s():\n"
782 					" invalid table in argument #%d:\n"
783 					" unknown flag \"%s\" for element #%d\n"),
784 					LUA_MODULE_NAME, &__FUNCTION__[6], 4,
785 					(strlen(flagname)>64)?_("<too large to display>"):flagname, i);
786 				lua_error(L);
787 			}
788 		} else return glspi_fail_elem_type(L, __FUNCTION__, 4, i, "string");
789 		lua_pop(L, 1);
790 	}
791 
792 	if (scintilla_send_message(doc->editor->sci,SCI_FINDTEXT,flags,(sptr_t)&ttf)!=-1) {
793 		push_number(L,ttf.chrgText.cpMin);
794 		push_number(L,ttf.chrgText.cpMax);
795 		g_free(text);
796 		return 2;
797 	} else {
798 		g_free(text);
799 		return 0;
800 	}
801 }
802 
803 
804 
805 /*
806 SCFIND_MATCHCASE  A match only occurs with text that matches the case of the search string.
807 SCFIND_WHOLEWORD  A match only occurs if the characters before and after are not word characters.
808 SCFIND_WORDSTART  A match only occurs if the character before is not a word character.
809 SCFIND_REGEXP  The search string should be interpreted as a regular expression.
810 SCFIND_POSIX   Interpret bare ( and ) for tagged regex sections rather than \( and \).
811 */
812 
813 
814 /*
815 struct CharacterRange {
816 		long cpMin;
817 		long cpMax;
818 };
819 
820 */
821 
822 /*
823 struct Sci_TextToFind {
824 		struct CharacterRange chrg;     // range to search
825 		char *lpstrText;                // the search pattern (zero terminated)
826 		struct CharacterRange chrgText; // returned as position of matching text
827 };
828 */
829 
830 
831 
832 static const struct luaL_reg glspi_sci_funcs[] = {
833 	{"text",      glspi_text},
834 	{"selection", glspi_selection},
835 	{"select",    glspi_select},
836 	{"height",    glspi_height},
837 	{"length",    glspi_length},
838 	{"caret",     glspi_caret},
839 	{"rowcol",    glspi_rowcol},
840 	{"batch",     glspi_batch},
841 	{"word",      glspi_word},
842 	{"lines",     glspi_lines},
843 	{"navigate",  glspi_navigate},
844 	{"cut",       glspi_cut},
845 	{"copy",      glspi_copy},
846 	{"paste",     glspi_paste},
847 	{"match",     glspi_match},
848 	{"byte",      glspi_byte},
849 	{"scintilla", glspi_scintilla},
850 	{"find",      glspi_find},
851 	{NULL,NULL}
852 };
853 
glspi_init_sci_funcs(lua_State * L)854 void glspi_init_sci_funcs(lua_State *L) {
855 	luaL_register(L, NULL,glspi_sci_funcs);
856 }
857