1 #if defined(HAVE_CONFIG_H) && !defined(GEANYPY_WINDOWS)
2 # include "config.h"
3 #endif
4
5 #include "geanypy.h"
6
7
8 static void
Document_dealloc(Document * self)9 Document_dealloc(Document *self)
10 {
11 self->ob_type->tp_free((PyObject *) self);
12 }
13
14
15 static int
Document_init(Document * self)16 Document_init(Document *self)
17 {
18 self->doc = NULL;
19 return 0;
20 }
21
22
23 static PyObject *
Document_get_property(Document * self,const gchar * prop_name)24 Document_get_property(Document *self, const gchar *prop_name)
25 {
26 g_return_val_if_fail(self != NULL, NULL);
27 g_return_val_if_fail(prop_name != NULL, NULL);
28
29 if (!self->doc)
30 {
31 PyErr_SetString(PyExc_RuntimeError,
32 "Document instance not initialized properly");
33 return NULL;
34 }
35
36 if (!DOC_VALID(self->doc))
37 {
38 PyErr_SetString(PyExc_RuntimeError, "Document is invalid");
39 return NULL;
40 }
41
42 if (g_str_equal(prop_name, "basename_for_display"))
43 {
44 PyObject *py_str = NULL;
45 gchar *res_string;
46 res_string = document_get_basename_for_display(self->doc, -1);
47 if (!res_string)
48 {
49 PyErr_SetString(PyExc_RuntimeError,
50 "Geany API failed to return a string");
51 Py_RETURN_NONE;
52 }
53 py_str = PyString_FromString(res_string);
54 g_free(res_string);
55 return py_str;
56 }
57 else if (g_str_equal(prop_name, "notebook_page"))
58 return Py_BuildValue("i", document_get_notebook_page(self->doc));
59 else if (g_str_equal(prop_name, "status_color"))
60 {
61 const GdkColor *color = document_get_status_color(self->doc);
62 if (!color)
63 Py_RETURN_NONE;
64 return Py_BuildValue("iii", color->red, color->green, color->blue);
65 }
66 else if (g_str_equal(prop_name, "editor") && self->doc->editor)
67 {
68 Editor *editor;
69 if (self->doc->editor != NULL)
70 {
71 editor = Editor_create_new_from_geany_editor(self->doc->editor);
72 return (PyObject *) editor;
73 }
74 Py_RETURN_NONE;
75 }
76 else if (g_str_equal(prop_name, "encoding") && self->doc->encoding)
77 return PyString_FromString(self->doc->encoding);
78 else if (g_str_equal(prop_name, "file_name") && self->doc->file_name)
79 return PyString_FromString(self->doc->file_name);
80 else if (g_str_equal(prop_name, "file_type") && self->doc->file_type)
81 return (PyObject *) Filetype_create_new_from_geany_filetype(self->doc->file_type);
82 else if (g_str_equal(prop_name, "has_bom"))
83 {
84 if (self->doc->has_bom)
85 Py_RETURN_TRUE;
86 else
87 Py_RETURN_FALSE;
88 }
89 else if (g_str_equal(prop_name, "has_tags"))
90 {
91 if (self->doc->has_tags)
92 Py_RETURN_TRUE;
93 else
94 Py_RETURN_FALSE;
95 }
96 else if (g_str_equal(prop_name, "index"))
97 return Py_BuildValue("i", self->doc->index);
98 else if (g_str_equal(prop_name, "is_valid"))
99 {
100 if (self->doc->is_valid)
101 Py_RETURN_TRUE;
102 else
103 Py_RETURN_FALSE;
104 }
105 else if (g_str_equal(prop_name, "readonly"))
106 {
107 if (self->doc->readonly)
108 Py_RETURN_TRUE;
109 else
110 Py_RETURN_FALSE;
111 }
112 else if (g_str_equal(prop_name, "real_path"))
113 {
114 if (self->doc->real_path)
115 return PyString_FromString(self->doc->real_path);
116 Py_RETURN_NONE;
117 }
118 else if (g_str_equal(prop_name, "text_changed"))
119 {
120 if (self->doc->changed)
121 Py_RETURN_TRUE;
122 else
123 Py_RETURN_FALSE;
124 }
125
126 Py_RETURN_NONE;
127 }
128
129
130 static int
Document_set_property(Document * self,PyObject * value,const gchar * prop_name)131 Document_set_property(Document *self, PyObject *value, const gchar *prop_name)
132 {
133 g_return_val_if_fail(self != NULL, -1);
134 g_return_val_if_fail(value != NULL, -1);
135 g_return_val_if_fail(prop_name != NULL, -1);
136
137 if (!self->doc)
138 {
139 PyErr_SetString(PyExc_RuntimeError,
140 "Document instance not initialized properly");
141 return -1;
142 }
143
144 if (g_str_equal(prop_name, "encoding"))
145 {
146 gchar *encoding = PyString_AsString(value);
147 if (encoding)
148 {
149 document_set_encoding(self->doc, encoding);
150 return 0;
151 }
152 }
153 else if (g_str_equal(prop_name, "filetype"))
154 {
155 Filetype *filetype = (Filetype *) value;
156 if (filetype->ft)
157 {
158 document_set_filetype(self->doc, filetype->ft);
159 return 0;
160 }
161 }
162 else if (g_str_equal(prop_name, "text_changed"))
163 {
164 long v = PyInt_AsLong(value);
165 if (v == -1 && PyErr_Occurred())
166 {
167 PyErr_Print();
168 return -1;
169 }
170 document_set_text_changed(self->doc, (gboolean) v);
171 return 0;
172 }
173
174 PyErr_SetString(PyExc_AttributeError, "can't set property");
175 return -1;
176 }
177
178
179 static PyObject*
Document_close(Document * self)180 Document_close(Document *self)
181 {
182 if (document_close(self->doc))
183 Py_RETURN_TRUE;
184 else
185 Py_RETURN_FALSE;
186 }
187
188
189 static PyObject*
Document_reload_force(Document * self,PyObject * args,PyObject * kwargs)190 Document_reload_force(Document *self, PyObject *args, PyObject *kwargs)
191 {
192 gchar *forced_enc = NULL;
193 static gchar *kwlist[] = { "forced_enc", NULL };
194
195 if (PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwlist, &forced_enc))
196 {
197 if (document_reload_force(self->doc, forced_enc))
198 Py_RETURN_TRUE;
199 else
200 Py_RETURN_FALSE;
201 }
202
203 Py_RETURN_NONE;
204 }
205
206
207 static PyObject*
Document_rename_file(Document * self,PyObject * args,PyObject * kwargs)208 Document_rename_file(Document *self, PyObject *args, PyObject *kwargs)
209 {
210 gchar *new_fn = NULL;
211 static gchar *kwlist[] = { "new_filename", NULL };
212
213 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &new_fn))
214 {
215 if (new_fn != NULL)
216 document_rename_file(self->doc, new_fn);
217 }
218
219 if (DOC_VALID(self->doc) && self->doc->file_name == new_fn)
220 Py_RETURN_TRUE;
221 else
222 Py_RETURN_FALSE;
223
224 Py_RETURN_NONE;
225 }
226
227
228 static PyObject*
Document_save_file(Document * self,PyObject * args,PyObject * kwargs)229 Document_save_file(Document *self, PyObject *args, PyObject *kwargs)
230 {
231 gboolean result;
232 gint force = 0;
233 static gchar *kwlist[] = { "force", NULL };
234
235 if (PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &force))
236 {
237 result = document_save_file(self->doc, (gboolean) force);
238 if (result)
239 Py_RETURN_TRUE;
240 else
241 Py_RETURN_FALSE;
242 }
243 Py_RETURN_NONE;
244 }
245
246
247 static PyObject*
Document_save_file_as(Document * self,PyObject * args,PyObject * kwargs)248 Document_save_file_as(Document *self, PyObject *args, PyObject *kwargs)
249 {
250 gboolean result;
251 gchar *filename = NULL;
252 static gchar *kwlist[] = { "new_filename", NULL };
253
254 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &filename))
255 {
256 if (filename != NULL)
257 {
258 result = document_save_file_as(self->doc, filename);
259 if (result)
260 Py_RETURN_TRUE;
261 else
262 Py_RETURN_FALSE;
263 }
264 }
265 Py_RETURN_NONE;
266 }
267
268
269 static PyMethodDef Document_methods[] = {
270 { "close", (PyCFunction)Document_close, METH_NOARGS,
271 "Closes the document." },
272 /* Geany deprecated alias */
273 { "reload_file", (PyCFunction)Document_reload_force, METH_KEYWORDS,
274 "Reloads the document with the specified file encoding or None "
275 "to auto-detect the file encoding." },
276 { "reload_force", (PyCFunction)Document_reload_force, METH_KEYWORDS,
277 "Reloads the document with the specified file encoding or None "
278 "to auto-detect the file encoding." },
279 { "rename_file", (PyCFunction)Document_rename_file, METH_KEYWORDS,
280 "Renames the document's file." },
281 { "save_file", (PyCFunction)Document_save_file, METH_KEYWORDS,
282 "Saves the document's file." },
283 { "save_file_as", (PyCFunction)Document_save_file_as, METH_KEYWORDS,
284 "Saves the document with a new filename, detecting the filetype." },
285 { NULL }
286 };
287
288
289 static PyGetSetDef Document_getseters[] = {
290 GEANYPY_GETSETDEF(Document, "editor",
291 "The editor associated with the document."),
292 GEANYPY_GETSETDEF(Document, "encoding",
293 "The encoding of the document."),
294 GEANYPY_GETSETDEF(Document, "file_name",
295 "The document's filename."),
296 GEANYPY_GETSETDEF(Document, "file_type",
297 "The filetype for this document."),
298 GEANYPY_GETSETDEF(Document, "has_bom",
299 "Internally used flag to indicate whether the file of this document "
300 "has a byte-order-mark."),
301 GEANYPY_GETSETDEF(Document, "has_tags",
302 "Whether this document supports source code symbols (tags) to "
303 "show in the sidebar."),
304 GEANYPY_GETSETDEF(Document, "index",
305 "Index of the document."),
306 GEANYPY_GETSETDEF(Document, "is_valid",
307 "General flag to represent this document is active and all properties "
308 "are set correctly."),
309 GEANYPY_GETSETDEF(Document, "readonly",
310 "Whether this document is read-only."),
311 GEANYPY_GETSETDEF(Document, "real_path",
312 "The link-dereferenced filename of the document."),
313 GEANYPY_GETSETDEF(Document, "basename_for_display",
314 "Returns the basename of the document's file."),
315 GEANYPY_GETSETDEF(Document, "notebook_page",
316 "Gets the notebook page index for the document."),
317 GEANYPY_GETSETDEF(Document, "status_color",
318 "Gets the status color of the document or None for default."),
319 GEANYPY_GETSETDEF(Document, "text_changed",
320 "Whether the document has been changed since it was last saved."),
321 { NULL },
322 };
323
324
325
326 static PyTypeObject DocumentType = {
327 PyObject_HEAD_INIT(NULL)
328 0, /* ob_size */
329 "geany.document.Document", /* tp_name */
330 sizeof(Document), /* tp_basicsize */
331 0, /* tp_itemsize */
332 (destructor) Document_dealloc, /* tp_dealloc */
333 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* tp_print - tp_as_buffer */
334 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
335 "Wrapper around a GeanyDocument structure.",/* tp_doc */
336 0, 0, 0, 0, 0, 0, /* tp_traverse - tp_iternext */
337 Document_methods, /* tp_methods */
338 0, /* tp_members */
339 Document_getseters, /* tp_getset */
340 0, 0, 0, 0, 0, /* tp_base - tp_dictoffset */
341 (initproc) Document_init, /* tp_init */
342 0, 0, /* tp_alloc - tp_new */
343
344 };
345
346
347 static PyObject*
Document_find_by_filename(PyObject * self,PyObject * args,PyObject * kwargs)348 Document_find_by_filename(PyObject *self, PyObject *args, PyObject *kwargs)
349 {
350 gchar *fn;
351 GeanyDocument *doc;
352 static gchar *kwlist[] = { "filename", NULL };
353
354 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &fn))
355 {
356 doc = document_find_by_filename(fn);
357 if (DOC_VALID(doc))
358 return (PyObject *) Document_create_new_from_geany_document(doc);
359 }
360 Py_RETURN_NONE;
361 }
362
363
364 static PyObject*
Document_find_by_real_path(PyObject * self,PyObject * args,PyObject * kwargs)365 Document_find_by_real_path(PyObject *self, PyObject *args, PyObject *kwargs)
366 {
367 gchar *fn;
368 GeanyDocument *doc;
369 static gchar *kwlist[] = { "real_path", NULL };
370
371 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &fn))
372 {
373 doc = document_find_by_real_path(fn);
374 if (DOC_VALID(doc))
375 return (PyObject *) Document_create_new_from_geany_document(doc);
376 }
377 Py_RETURN_NONE;
378 }
379
380
381 static PyObject*
Document_get_current(PyObject * self)382 Document_get_current(PyObject *self)
383 {
384 GeanyDocument *doc;
385
386 doc = document_get_current();
387 if (DOC_VALID(doc))
388 return (PyObject *) Document_create_new_from_geany_document(doc);
389 Py_RETURN_NONE;
390 }
391
392
393 static PyObject*
Document_get_from_page(PyObject * self,PyObject * args,PyObject * kwargs)394 Document_get_from_page(PyObject *self, PyObject *args, PyObject *kwargs)
395 {
396 gint page_num;
397 GeanyDocument *doc;
398 static gchar *kwlist[] = { "page_num", NULL };
399
400 if (PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &page_num))
401 {
402 doc = document_get_from_page(page_num);
403 if (DOC_VALID(doc))
404 return (PyObject *) Document_create_new_from_geany_document(doc);
405 }
406 Py_RETURN_NONE;
407 }
408
409
410 static PyObject*
Document_get_from_index(PyObject * self,PyObject * args,PyObject * kwargs)411 Document_get_from_index(PyObject *self, PyObject *args, PyObject *kwargs)
412 {
413 gint idx;
414 GeanyDocument *doc;
415 static gchar *kwlist[] = { "index", NULL };
416
417 if (PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &idx))
418 {
419 doc = document_index(idx);
420 if (DOC_VALID(doc))
421 return (PyObject *) Document_create_new_from_geany_document(doc);
422 }
423 Py_RETURN_NONE;
424 }
425
426
427 static PyObject*
Document_new_file(PyObject * self,PyObject * args,PyObject * kwargs)428 Document_new_file(PyObject *self, PyObject *args, PyObject *kwargs)
429 {
430 gchar *filename = NULL, *initial_text = NULL;
431 Filetype *filetype = NULL;
432 PyObject *py_ft = NULL;
433 GeanyDocument *doc;
434 GeanyFiletype *ft = NULL;
435 static gchar *kwlist[] = { "filename", "filetype", "initial_text", NULL };
436
437 if (PyArg_ParseTupleAndKeywords(args, kwargs, "|zOz", kwlist,
438 &filename, &py_ft, &initial_text))
439 {
440 if (py_ft != NULL && py_ft != Py_None)
441 {
442 filetype = (Filetype *) py_ft;
443 if (filetype->ft != NULL)
444 ft = filetype->ft;
445 }
446 doc = document_new_file(filename, ft, initial_text);
447 if (DOC_VALID(doc))
448 return (PyObject *) Document_create_new_from_geany_document(doc);
449 }
450 Py_RETURN_NONE;
451 }
452
453
454 static PyObject*
Document_open_file(PyObject * self,PyObject * args,PyObject * kwargs)455 Document_open_file(PyObject *self, PyObject *args, PyObject *kwargs)
456 {
457 gint read_only = 0;
458 gchar *filename = NULL, *forced_encoding = NULL;
459 GeanyDocument *doc;
460 GeanyFiletype *ft = NULL;
461 Filetype *filetype = NULL;
462 PyObject *py_ft = NULL;
463 static gchar *kwlist[] = { "filename", "read_only", "filetype",
464 "forced_enc", NULL };
465
466 if (PyArg_ParseTupleAndKeywords(args, kwargs, "s|iOz", kwlist, &filename,
467 &read_only, &py_ft, &forced_encoding))
468 {
469 if (py_ft != NULL && py_ft != Py_None)
470 {
471 filetype = (Filetype *) py_ft;
472 if (filetype->ft != NULL)
473 ft = filetype->ft;
474 }
475 doc = document_open_file(filename, read_only, ft, forced_encoding);
476 if (DOC_VALID(doc))
477 return (PyObject *) Document_create_new_from_geany_document(doc);
478 }
479 Py_RETURN_NONE;
480 }
481
482
483 static PyObject*
Document_remove_page(PyObject * self,PyObject * args,PyObject * kwargs)484 Document_remove_page(PyObject *self, PyObject *args, PyObject *kwargs)
485 {
486 guint page_num;
487 static gchar *kwlist[] = { "page_num", NULL };
488
489 if (PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &page_num))
490 {
491 if (document_remove_page(page_num))
492 Py_RETURN_TRUE;
493 else
494 Py_RETURN_FALSE;
495 }
496 Py_RETURN_NONE;
497 }
498
499
500 static PyObject *
Document_get_documents_list(PyObject * module)501 Document_get_documents_list(PyObject *module)
502 {
503 guint i;
504 GeanyDocument *doc;
505 PyObject *list;
506
507 list = PyList_New(0);
508
509 for (i = 0; i < geany_data->documents_array->len; i++)
510 {
511 doc = g_ptr_array_index(geany_data->documents_array, i);
512 if (DOC_VALID(doc))
513 {
514 PyList_Append(list,
515 (PyObject *) Document_create_new_from_geany_document(doc));
516 }
517 }
518
519 return list;
520 }
521
522
523 static
524 PyMethodDef DocumentModule_methods[] = {
525 { "find_by_filename", (PyCFunction) Document_find_by_filename, METH_KEYWORDS,
526 "Finds a document with the given filename." },
527 { "find_by_real_path", (PyCFunction) Document_find_by_real_path, METH_KEYWORDS,
528 "Finds a document whose real path matches the given filename." },
529 { "get_current", (PyCFunction) Document_get_current, METH_NOARGS,
530 "Finds the current document."},
531 { "get_from_page", (PyCFunction) Document_get_from_page, METH_KEYWORDS,
532 "Finds the document for the given notebook page." },
533 { "index", (PyCFunction) Document_get_from_index, METH_KEYWORDS,
534 "Finds the document with the given index." },
535 { "new_file", (PyCFunction) Document_new_file, METH_KEYWORDS,
536 "Creates a new document." },
537 { "open_file", (PyCFunction) Document_open_file, METH_KEYWORDS,
538 "Opens a new document specified by the given filename." },
539 { "remove_page", (PyCFunction) Document_remove_page, METH_KEYWORDS,
540 "Removes the given notebook tab page and clears all related "
541 "information in the documents list." },
542 { "get_documents_list", (PyCFunction) Document_get_documents_list, METH_NOARGS,
543 "Returns a sequence of valid documents." },
544 { NULL }
545 };
546
547
initdocument(void)548 PyMODINIT_FUNC initdocument(void)
549 {
550 PyObject *m;
551
552 DocumentType.tp_new = PyType_GenericNew;
553 if (PyType_Ready(&DocumentType) < 0)
554 return;
555
556 m = Py_InitModule3("document", DocumentModule_methods,
557 "Document information and management.");
558
559 Py_INCREF(&DocumentType);
560 PyModule_AddObject(m, "Document", (PyObject *)&DocumentType);
561 }
562
563
Document_create_new_from_geany_document(GeanyDocument * doc)564 Document *Document_create_new_from_geany_document(GeanyDocument *doc)
565 {
566 Document *self;
567 self = (Document *) PyObject_CallObject((PyObject *) &DocumentType, NULL);
568 self->doc = doc;
569 return self;
570 }
571