1 /*
2 * glspi_doc.c - This file is part of the Lua scripting plugin for the Geany IDE
3 * See the file "geanylua.c" for copyright information.
4 */
5
6 #define NEED_FAIL_ARG_TYPE
7 #define NEED_FAIL_ARG_TYPES
8 #include "glspi.h"
9
10
11 #define NOTEBOOK GTK_NOTEBOOK(main_widgets->notebook)
12
13
14 #ifdef G_OS_WIN32
15 #define fncmp(a,b) ( a && b && (strcasecmp(a,b)==0))
16 #else
17 #define fncmp(a,b) ( a && b && (strcmp(a,b)==0))
18 #endif
19
20
21
22 /* Return the filename of the currently active Geany document */
glspi_filename(lua_State * L)23 static gint glspi_filename(lua_State* L)
24 {
25 DOC_REQUIRED
26 lua_pushstring(L, (const gchar *) doc->file_name);
27 return 1;
28 }
29
30
31 /* Create a new Geany document tab */
glspi_newfile(lua_State * L)32 static gint glspi_newfile(lua_State* L)
33 {
34 const gchar *fn=NULL;
35 GeanyFiletype *ft=NULL;
36 switch (lua_gettop(L)) {
37 case 0: break;
38 case 2:
39 if (!lua_isstring(L, 2)) { return FAIL_STRING_ARG(2); }
40 const gchar *tmp=lua_tostring(L, 2);
41 if ( '\0' == tmp[0] ) {
42 ft=NULL;
43 } else {
44 ft=filetypes_lookup_by_name(tmp);
45 }
46 default:
47 if (!lua_isstring(L, 1)) { return FAIL_STRING_ARG(1); }
48 fn=lua_tostring(L, 1);
49 if ( '\0' == fn[0] ) { fn=NULL; }
50 }
51 document_new_file(fn, ft, NULL);
52 return 0;
53 }
54
55
56
57 /*
58 Try to find the geany->documents_array index of the specified filename.
59 Returns -1 if the filename doesn't match any open tabs.
60 */
filename_to_doc_idx(const gchar * fn)61 static gint filename_to_doc_idx(const gchar*fn)
62 {
63 if (fn && *fn) {
64 guint i=0;
65 foreach_document(i)
66 {
67 if fncmp(fn,documents[i]->file_name) {return i; }
68 }
69 }
70 return -1;
71 }
72
73
74 /* Converts a geany->documents_array index to a notebook tab index */
doc_idx_to_tab_idx(gint idx)75 static gint doc_idx_to_tab_idx(gint idx)
76 {
77 return (
78 (idx>=0) && ((guint)idx<geany->documents_array->len) && documents[idx]->is_valid
79 ) ? gtk_notebook_page_num(NOTEBOOK, GTK_WIDGET(documents[idx]->editor->sci)):-1;
80 }
81
82
83
84 /* Returns the filename of the specified document, or NULL on bad index */
doc_idx_to_filename(gint idx)85 static const gchar* doc_idx_to_filename(gint idx) {
86 if ( (idx >= 0 ) && ( ((guint)idx) < geany->documents_array->len ) ) {
87 GeanyDocument *doc=g_ptr_array_index(geany->documents_array, idx);
88 if (doc) { return doc->file_name?doc->file_name:GEANY_STRING_UNTITLED; }
89 }
90 return NULL;
91 }
92
93
94
95 /* Actvate and focus the specified document */
glspi_activate(lua_State * L)96 static gint glspi_activate(lua_State* L)
97 {
98 gint idx=-1;
99 if (lua_gettop(L)>0) {
100 if (lua_isnumber(L,1)) {
101 idx=(lua_tonumber(L,1));
102 if (idx<0) { /* Negative number refers to (absolute) GtkNotebook index */
103 idx=(0-idx)-1;
104 if (idx>=gtk_notebook_get_n_pages(NOTEBOOK)) { idx=-1;}
105 } else { /* A positive number refers to the geany->documents_array index */
106 idx=doc_idx_to_tab_idx(idx-1);
107 }
108
109 } else {
110 if (lua_isstring(L,1)) {
111 idx=doc_idx_to_tab_idx(filename_to_doc_idx(lua_tostring(L, 1)));
112 } else {
113 if (!lua_isnil(L,1)) { return FAIL_STR_OR_NUM_ARG(1); }
114 }
115 }
116 }
117 if (idx>=0) {
118 if (idx!=gtk_notebook_get_current_page(NOTEBOOK)) {
119 gtk_notebook_set_current_page(NOTEBOOK, idx);
120 }
121 }
122 lua_pushboolean(L, (idx>0));
123 return 1;
124 }
125
126
127
128 /* Lua "closure" function to iterate through the list of open documents */
documents_closure(lua_State * L)129 static gint documents_closure(lua_State *L)
130 {
131 gint idx=lua_tonumber(L, lua_upvalueindex(1));
132 int max=geany->documents_array->len;
133 do {
134 /* Find next valid index, skipping invalid (closed) files */
135 idx++;
136 } while (( idx < max ) && !documents[idx]->is_valid );
137 if ( idx < max ){
138 push_number(L, idx);
139 lua_pushvalue(L, -1);
140 lua_replace(L, lua_upvalueindex(1));
141 lua_pushstring(L,doc_idx_to_filename(idx));
142 return 1;
143 } else {
144 return 0;
145 }
146 }
147
148
149 /* Access the list of open documents */
glspi_documents(lua_State * L)150 static gint glspi_documents(lua_State *L)
151 {
152 if (lua_gettop(L)==0) {
153 push_number(L,-1);
154 lua_pushcclosure(L, &documents_closure, 1);
155 return 1;
156 } else {
157 gint idx;
158 const gchar *name;
159 DOC_REQUIRED
160 if (lua_isnumber(L,1)) {
161 idx=lua_tonumber(L,1)-1;
162 name=doc_idx_to_filename(idx);
163 if (name) {
164 lua_pushstring(L,name);
165 return 1;
166 } else {
167 return 0;
168 }
169 } else {
170 if (lua_isstring(L,1)) {
171 name=lua_tostring(L,1);
172 idx=filename_to_doc_idx(name);
173 if (idx>=0) {
174 push_number(L,idx+1);
175 return 1;
176 } else { return 0; }
177 } else { return FAIL_STR_OR_NUM_ARG(1); }
178 }
179 }
180 }
181
182
183 /* Returns the number of open documents */
glspi_count(lua_State * L)184 static gint glspi_count(lua_State* L)
185 {
186 guint i=0, n=0;
187 foreach_document(i)
188 {
189 if (documents[i]->is_valid){n++;}
190 }
191 push_number(L,n);
192 return 1;
193 }
194
195
196 /* Save a file to disk */
glspi_save(lua_State * L)197 static gint glspi_save(lua_State* L)
198 {
199 gboolean status=FALSE;
200 if (lua_gettop(L)==0){
201 DOC_REQUIRED
202 status=document_save_file(document_get_current(), TRUE);
203 } else {
204 if (lua_isnumber(L,1)) {
205 gint idx=(gint)lua_tonumber(L,1)-1;
206 status=document_save_file(documents[idx], TRUE);
207 } else {
208 if (lua_isstring(L,1)) {
209 gint idx=filename_to_doc_idx(lua_tostring(L,1));
210 status=document_save_file(documents[idx], TRUE);
211 } else { return FAIL_STR_OR_NUM_ARG(1); }
212 }
213 }
214 lua_pushboolean(L,status);
215 return 1;
216 }
217
218
219 /* Open or reload a file */
glspi_open(lua_State * L)220 static gint glspi_open(lua_State* L)
221 {
222 gint status=-1;
223 const gchar*fn=NULL;
224 gint idx=-1;
225
226 if (lua_gettop(L)==0) {
227 DOC_REQUIRED
228 idx=document_get_current()->index;
229 } else {
230 if (lua_isnumber(L,1)) {
231 idx=lua_tonumber(L,1)-1;
232 } else {
233 if (lua_isstring(L,1)) {
234 fn=lua_tostring(L,1);
235 } else { return FAIL_STR_OR_NUM_ARG(1); }
236 }
237 }
238 if (!fn) {
239 status=document_reload_force(documents[idx],NULL) ? idx : -1;
240 } else {
241 guint len=geany->documents_array->len;
242 GeanyDocument*doc=document_open_file(fn,FALSE,NULL,NULL);
243 status=doc?doc->index:-1;
244 if ( (status>=0) && (len==geany->documents_array->len))
245 {
246 /* if len doesn't change, it means we are reloading an already open file */
247 /* ntrel: actually, len can stay the same when reusing invalid document slots. */
248 idx=document_get_current()->index;
249 status=document_reload_force(documents[idx],NULL) ? idx : -1;
250 }
251 }
252 push_number(L,status+1);
253 return 1;
254 }
255
256
257 /* Close a document */
glspi_close(lua_State * L)258 static gint glspi_close(lua_State* L)
259 {
260 gboolean status=FALSE;
261 if (lua_gettop(L)==0){
262 DOC_REQUIRED
263 status=document_close(document_get_current());
264 } else {
265 if (lua_isnumber(L,1)) {
266 guint idx=(guint)lua_tonumber(L,1)-1;
267 status=document_close(documents[idx]);
268 } else {
269 if (lua_isstring(L,1)) {
270 guint idx=(guint)filename_to_doc_idx(lua_tostring(L,1));
271 status=document_close(documents[idx]);
272 } else { return FAIL_STR_OR_NUM_ARG(1); }
273 }
274 }
275 lua_pushboolean(L,status);
276 return 1;
277 }
278
279
280 #define StrField(rec,field) rec?rec->field?rec->field:"":""
281
282 #define FileTypeStr(field) StrField(doc->file_type,field)
283
284 #define BuildCmdStr(field) \
285 doc->file_type?StrField(doc->file_type->programs,field):""
286
287
288 /* Retrieve Geany's information about an open document */
glspi_fileinfo(lua_State * L)289 static gint glspi_fileinfo(lua_State* L)
290 {
291 DOC_REQUIRED
292 lua_newtable(L);
293 if (doc->file_name) {
294 gchar*tmp,*p;
295 tmp=g_path_get_dirname (doc->file_name);
296 p=strchr(tmp,'\0');
297 if (p>tmp) {p--;}
298 lua_pushstring(L, "path");
299 if (p && (*p==G_DIR_SEPARATOR)){
300 lua_pushstring(L, tmp);
301 } else {
302 lua_pushfstring(L, "%s%s", tmp, G_DIR_SEPARATOR_S);
303 }
304 lua_rawset(L,-3);
305 g_free(tmp);
306
307 tmp=g_path_get_basename (doc->file_name);
308 p=strrchr(tmp,'.');
309 if (p==tmp) {p=NULL;}
310 SetTableStr("name", tmp);
311 SetTableStr("ext", p?p:"");
312 g_free(tmp);
313 } else {
314 SetTableStr("name", "")
315 SetTableStr("path", "")
316 }
317 SetTableStr("type", FileTypeStr(name));
318 SetTableStr("desc", FileTypeStr(title));
319 SetTableStr("opener", FileTypeStr(comment_open));
320 SetTableStr("closer", FileTypeStr(comment_close));
321 SetTableStr("action", FileTypeStr(context_action_cmd));
322 /*
323 SetTableStr("compiler", BuildCmdStr(compiler));
324 SetTableStr("linker", BuildCmdStr(linker));
325 SetTableStr("exec", BuildCmdStr(run_cmd));
326 SetTableStr("exec2", BuildCmdStr(run_cmd2));
327 */
328 SetTableNum("ftid", GPOINTER_TO_INT(doc->file_type?doc->file_type->id:GEANY_FILETYPES_NONE));
329 SetTableStr("encoding", StrField(doc,encoding));
330 SetTableBool("bom",doc->has_bom);
331 SetTableBool("changed",doc->changed);
332 SetTableBool("readonly",doc->readonly);
333 return 1;
334 }
335
336
337
338
339 static const struct luaL_reg glspi_doc_funcs[] = {
340 {"filename", glspi_filename},
341 {"fileinfo", glspi_fileinfo},
342 {"documents", glspi_documents},
343 {"count", glspi_count},
344 {"activate", glspi_activate},
345 {"newfile", glspi_newfile},
346 {"save", glspi_save},
347 {"open", glspi_open},
348 {"close", glspi_close},
349 {NULL,NULL}
350 };
351
glspi_init_doc_funcs(lua_State * L)352 void glspi_init_doc_funcs(lua_State *L) {
353 luaL_register(L, NULL,glspi_doc_funcs);
354 }
355