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