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