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
Editor_dealloc(Editor * self)9 Editor_dealloc(Editor *self)
10 {
11 	self->ob_type->tp_free((PyObject *) self);
12 }
13 
14 
15 static int
Editor_init(Editor * self)16 Editor_init(Editor *self)
17 {
18 	self->editor = NULL;
19 	return 0;
20 }
21 
22 
23 static PyObject *
Editor_get_property(Editor * self,const gchar * prop_name)24 Editor_get_property(Editor *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->editor)
30 	{
31 		PyErr_SetString(PyExc_RuntimeError,
32 			"Editor instance not initialized properly");
33 		return NULL;
34 	}
35 
36 	if (g_str_equal(prop_name, "eol_char"))
37 		return PyString_FromString(editor_get_eol_char(self->editor));
38 	else if (g_str_equal(prop_name, "eol_char_name"))
39 		return PyString_FromString(editor_get_eol_char_name(self->editor));
40 	else if (g_str_equal(prop_name, "indent_prefs"))
41 	{
42 		const GeanyIndentPrefs *indent_prefs;
43 		IndentPrefs *py_prefs;
44 		indent_prefs = editor_get_indent_prefs(self->editor);
45 		if (indent_prefs)
46 		{
47 			py_prefs = IndentPrefs_create_new_from_geany_indent_prefs(
48 							(GeanyIndentPrefs *) indent_prefs);
49 			return (PyObject *) py_prefs;
50 		}
51 		Py_RETURN_NONE;
52 	}
53 	else if (g_str_equal(prop_name, "auto_indent"))
54 	{
55 		if (self->editor->auto_indent)
56 			Py_RETURN_TRUE;
57 		else
58 			Py_RETURN_FALSE;
59 	}
60 	else if (g_str_equal(prop_name, "document"))
61 	{
62 		PyObject *py_doc;
63 		py_doc = (PyObject *) Document_create_new_from_geany_document(
64 									self->editor->document);
65 		if (!py_doc || py_doc == Py_None)
66 			Py_RETURN_NONE;
67 		return py_doc;
68 	}
69 	else if (g_str_equal(prop_name, "line_breaking"))
70 	{
71 		if (self->editor->line_breaking)
72 			Py_RETURN_TRUE;
73 		else
74 			Py_RETURN_FALSE;
75 	}
76 	else if (g_str_equal(prop_name, "line_wrapping"))
77 	{
78 		if (self->editor->line_wrapping)
79 			Py_RETURN_TRUE;
80 		else
81 			Py_RETURN_FALSE;
82 	}
83 	else if (g_str_equal(prop_name, "scintilla"))
84 	{
85 		Scintilla *sci;
86 		sci = Scintilla_create_new_from_scintilla(self->editor->sci);
87 		if (!sci)
88 			Py_RETURN_NONE;
89 		return (PyObject *) sci;
90 	}
91 	else if (g_str_equal(prop_name, "scroll_percent"))
92 		return PyFloat_FromDouble((gdouble) self->editor->scroll_percent);
93 
94 	PyErr_SetString(PyExc_AttributeError, "can't get property");
95 	Py_RETURN_NONE;
96 }
97 
98 
99 static int
Editor_set_property(Editor * self,PyObject * value,const gchar * prop_name)100 Editor_set_property(Editor *self, PyObject *value, const gchar *prop_name)
101 {
102 	g_return_val_if_fail(self != NULL, -1);
103 	g_return_val_if_fail(value != NULL, -1);
104 	g_return_val_if_fail(prop_name != NULL, -1);
105 
106 	if (!self->editor)
107 	{
108 		PyErr_SetString(PyExc_RuntimeError,
109 			"Editor instance not initialized properly");
110 		return -1;
111 	}
112 
113 	if (g_str_equal(prop_name, "indent_type"))
114 	{
115 		long indent_type = PyInt_AsLong(value);
116 		if (indent_type == -1 && PyErr_Occurred())
117 		{
118 			PyErr_Print();
119 			return -1;
120 		}
121 		editor_set_indent_type(self->editor, (GeanyIndentType) indent_type);
122 		return 0;
123 	}
124 
125 	PyErr_SetString(PyExc_AttributeError, "can't set property");
126 	return -1;
127 }
128 
129 
130 static PyObject *
Editor_create_widget(Editor * self)131 Editor_create_widget(Editor *self)
132 {
133 	ScintillaObject *sci;
134 	PyObject *pysci;
135 
136 	if (self->editor == NULL)
137 		Py_RETURN_NONE;
138 
139 	sci = editor_create_widget(self->editor);
140 	if (!sci)
141 		Py_RETURN_NONE;
142 
143 	pysci = pygobject_new(G_OBJECT(sci));
144 	if (!pysci)
145 	{
146 		gtk_widget_destroy(GTK_WIDGET(sci));
147 		Py_RETURN_NONE;
148 	}
149 
150 	return pysci;
151 }
152 
153 
154 static PyObject *
Editor_find_snippet(Editor * self,PyObject * args,PyObject * kwargs)155 Editor_find_snippet(Editor *self, PyObject *args, PyObject *kwargs)
156 {
157 	gchar *name;
158 	const gchar *snippet;
159 	static gchar *kwlist[] = { "snippet_name", NULL };
160 
161 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
162 	{
163 		if (name != NULL)
164 		{
165 			snippet = editor_find_snippet(self->editor, name);
166 			if (snippet != NULL)
167 				return Py_BuildValue("s", snippet);
168 		}
169 	}
170 	Py_RETURN_NONE;
171 }
172 
173 
174 static PyObject *
Editor_get_word_at_position(Editor * self,PyObject * args,PyObject * kwargs)175 Editor_get_word_at_position(Editor *self, PyObject *args, PyObject *kwargs)
176 {
177 	gint pos = -1;
178 	gchar *wordchars = NULL, *word = NULL;
179 	PyObject *py_word;
180 	static gchar *kwlist[] = { "pos", "wordchars", NULL };
181 
182 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "|iz", kwlist, &pos, &wordchars))
183 	{
184 		word = editor_get_word_at_pos(self->editor, pos, wordchars);
185 		if (word != NULL)
186 		{
187 			py_word = Py_BuildValue("s", word);
188 			g_free(word);
189 			return py_word;
190 		}
191 	}
192 
193 	Py_RETURN_NONE;
194 }
195 
196 
197 static PyObject *
Editor_goto_pos(Editor * self,PyObject * args,PyObject * kwargs)198 Editor_goto_pos(Editor *self, PyObject *args, PyObject *kwargs)
199 {
200 	gint pos, mark = FALSE, result;
201 	static gchar *kwlist[] = { "pos", "mark", NULL };
202 
203 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, &pos, &mark))
204 	{
205 		result = editor_goto_pos(self->editor, pos, mark);
206 		if (result)
207 			Py_RETURN_TRUE;
208 		else
209 			Py_RETURN_FALSE;
210 	}
211 	Py_RETURN_NONE;
212 }
213 
214 
215 static PyObject *
Editor_indicator_clear(Editor * self,PyObject * args,PyObject * kwargs)216 Editor_indicator_clear(Editor *self, PyObject *args, PyObject *kwargs)
217 {
218 	gint indic;
219 	static gchar *kwlist[] = { "indic", NULL };
220 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &indic))
221 		editor_indicator_clear(self->editor, indic);
222 	Py_RETURN_NONE;
223 }
224 
225 
226 static PyObject *
Editor_indicator_set_on_line(Editor * self,PyObject * args,PyObject * kwargs)227 Editor_indicator_set_on_line(Editor *self, PyObject *args, PyObject *kwargs)
228 {
229 	gint indic, line_num;
230 	static gchar *kwlist[] = { "indic", "line", NULL };
231 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &indic, &line_num))
232 		editor_indicator_set_on_line(self->editor, indic, line_num);
233 	Py_RETURN_NONE;
234 }
235 
236 
237 static PyObject *
Editor_indicator_set_on_range(Editor * self,PyObject * args,PyObject * kwargs)238 Editor_indicator_set_on_range(Editor *self, PyObject *args, PyObject *kwargs)
239 {
240 	gint indic, start, end;
241 	static gchar *kwlist[] = { "indic", "start", "end", NULL };
242 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "iii", kwlist, &indic, &start, &end))
243 		editor_indicator_set_on_range(self->editor, indic, start, end);
244 	Py_RETURN_NONE;
245 }
246 
247 
248 static PyObject *
Editor_insert_snippet(Editor * self,PyObject * args,PyObject * kwargs)249 Editor_insert_snippet(Editor *self, PyObject *args, PyObject *kwargs)
250 {
251 	gint pos = 0;
252 	gchar *snippet = NULL;
253 	static gchar *kwlist[] = { "pos", "snippet", NULL };
254 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "is", kwlist, &pos, &snippet))
255 		editor_insert_snippet(self->editor, pos, snippet);
256 	Py_RETURN_NONE;
257 }
258 
259 
260 static PyObject *
Editor_insert_text_block(Editor * self,PyObject * args,PyObject * kwargs)261 Editor_insert_text_block(Editor *self, PyObject *args, PyObject *kwargs)
262 {
263 	gchar *text = NULL;
264 	gint insert_pos, cursor_index = -1, newline_indent_size = -1;
265 	gint replace_newlines = 0;
266 	static gchar *kwlist[] = { "text", "insert_pos", "cursor_index",
267 		"newline_indent_size", "replace_newlines", NULL };
268 
269 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "si|iii", kwlist, &text,
270 		&insert_pos, &cursor_index, &newline_indent_size, &replace_newlines))
271 	{
272 		editor_insert_text_block(self->editor, text, insert_pos, cursor_index,
273 			newline_indent_size, (gboolean) replace_newlines);
274 	}
275 
276 	Py_RETURN_NONE;
277 }
278 
279 
280 static PyMethodDef Editor_methods[] = {
281 	{ "create_widget", (PyCFunction) Editor_create_widget, METH_NOARGS,
282 		"Creates a new Scintilla widget based on the settings for "
283 		"editor." },
284 	{ "find_snippet", (PyCFunction) Editor_find_snippet, METH_KEYWORDS,
285 		"Get snippet by name." },
286 	{ "get_word_at_position", (PyCFunction) Editor_get_word_at_position, METH_KEYWORDS,
287 		"Finds the word at the position specified." },
288 	{ "goto_pos", (PyCFunction) Editor_goto_pos, METH_KEYWORDS,
289 		"Moves to position, switching to the current document if "
290 		"necessary, setting a marker if mark is set." },
291 	{ "indicator_clear", (PyCFunction) Editor_indicator_clear, METH_KEYWORDS,
292 		"Deletes all currently set indicators matching the specified "
293 		"indicator in the editor." },
294 	{ "indicator_set_on_line", (PyCFunction) Editor_indicator_set_on_line, METH_KEYWORDS,
295 		"Sets an indicator on the specified line." },
296 	{ "indicator_set_on_range", (PyCFunction) Editor_indicator_set_on_range, METH_KEYWORDS,
297 		"Sets an indicator on the range specified." },
298 	{ "insert_snippet", (PyCFunction) Editor_insert_snippet, METH_KEYWORDS,
299 		"Replaces all special sequences in snippet and inserts it at "
300 		"the specified position." },
301 	{ "insert_text_block", (PyCFunction) Editor_insert_text_block, METH_KEYWORDS,
302 		"Inserts text, replacing tab chars and newline chars accordingly "
303 		"for the document." },
304 	{ NULL }
305 };
306 
307 
308 static PyGetSetDef Editor_getseters[] = {
309 	GEANYPY_GETSETDEF(Editor, "eol_char",
310 		"The endo of line character(s)."),
311 	GEANYPY_GETSETDEF(Editor, "eol_char_name",
312 		"The localized name (for displaying) of the used end of line "
313 		"characters in the editor."),
314 	GEANYPY_GETSETDEF(Editor, "indent_prefs",
315 		"Editor's indentation preferences."),
316 	GEANYPY_GETSETDEF(Editor, "indent_type",
317 		"Sets the indent type for the editor."),
318 	GEANYPY_GETSETDEF(Editor, "auto_indent",
319 		"True if auto-indentation is enabled."),
320 	GEANYPY_GETSETDEF(Editor, "document",
321 		"The document associated with the editor."),
322 	GEANYPY_GETSETDEF(Editor, "line_breaking",
323 		"Whether to split long lines as you type."),
324 	GEANYPY_GETSETDEF(Editor, "line_wrapping",
325 		"True if line wrapping is enabled."),
326 	GEANYPY_GETSETDEF(Editor, "scintilla",
327 		"The Scintilla widget used by the editor."),
328 	GEANYPY_GETSETDEF(Editor, "scroll_percent",
329 		"Percentage to scroll view by on paint, if positive."),
330 	{ NULL },
331 };
332 
333 
334 static PyTypeObject EditorType = {
335 	PyObject_HEAD_INIT(NULL)
336 	0,											/* ob_size */
337 	"geany.editor.Editor",						/* tp_name */
338 	sizeof(Editor),								/* tp_basicsize */
339 	0,											/* tp_itemsize */
340 	(destructor)Editor_dealloc,					/* tp_dealloc */
341 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* tp_print - tp_as_buffer */
342 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* tp_flags */
343 	"Wrapper around a GeanyEditor structure.",	/* tp_doc */
344 	0, 0, 0, 0, 0, 0,							/* tp_traverse - tp_iternext */
345 	Editor_methods,								/* tp_methods */
346 	0,											/* tp_members */
347 	Editor_getseters,							/* tp_getset */
348 	0, 0, 0, 0, 0,								/* tp_base - tp_dictoffset */
349 	(initproc)Editor_init,						/* tp_init */
350 	0, 0,										/* tp_alloc - tp_new */
351 
352 };
353 
354 
355 static PyObject *
Editor__find_snippet(PyObject * module,PyObject * args,PyObject * kwargs)356 Editor__find_snippet(PyObject *module, PyObject *args, PyObject *kwargs)
357 {
358 	gchar *name;
359 	const gchar *snippet;
360 	static gchar *kwlist[] = { "snippet_name", NULL };
361 
362 	if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
363 	{
364 		if (name != NULL)
365 		{
366 			snippet = editor_find_snippet(NULL, name);
367 			if (snippet != NULL)
368 				return Py_BuildValue("s", snippet);
369 		}
370 	}
371 	Py_RETURN_NONE;
372 }
373 
374 
375 static PyObject *
Editor_get_default_eol_char(PyObject * module)376 Editor_get_default_eol_char(PyObject *module)
377 {
378 	const gchar *eol_char = editor_get_eol_char(NULL);
379 	if (eol_char != NULL)
380 		return Py_BuildValue("s", eol_char);
381 	Py_RETURN_NONE;
382 }
383 
384 
385 static PyObject *
Editor_get_default_eol_char_name(PyObject * module)386 Editor_get_default_eol_char_name(PyObject *module)
387 {
388 	const gchar *eol_char_name = editor_get_eol_char_name(NULL);
389 	if (eol_char_name != NULL)
390 		return Py_BuildValue("s", eol_char_name);
391 	Py_RETURN_NONE;
392 }
393 
394 
395 static PyObject *
Editor_get_default_indent_prefs(PyObject * module)396 Editor_get_default_indent_prefs(PyObject *module)
397 {
398 	const GeanyIndentPrefs *indent_prefs;
399 	IndentPrefs *py_prefs;
400 	indent_prefs = editor_get_indent_prefs(NULL);
401 	if (indent_prefs != NULL)
402 	{
403 		py_prefs = IndentPrefs_create_new_from_geany_indent_prefs((GeanyIndentPrefs *)indent_prefs);
404 		return (PyObject *) py_prefs;
405 	}
406 	Py_RETURN_NONE;
407 }
408 
409 
410 static
411 PyMethodDef EditorModule_methods[] = {
412 	{ "find_snippet", (PyCFunction) Editor__find_snippet, METH_VARARGS,
413 		"Gets a snippet by name from the default set." },
414 	{ "get_default_eol_char", (PyCFunction) Editor_get_default_eol_char, METH_NOARGS,
415 		"The default eol char." },
416 	{ "get_default_eol_char_name", (PyCFunction) Editor_get_default_eol_char_name, METH_NOARGS,
417 		"Retrieves the localized name (for displaying) of the default end "
418 		"of line characters." },
419 	{ "get_default_indent_prefs", (PyCFunction) Editor_get_default_indent_prefs, METH_NOARGS,
420 		"Gets the default indentation preferences." },
421 	{ NULL }
422 };
423 
424 
initeditor(void)425 PyMODINIT_FUNC initeditor(void)
426 {
427 	PyObject *m;
428 
429 	EditorType.tp_new = PyType_GenericNew;
430 	if (PyType_Ready(&EditorType) < 0)
431 		return;
432 
433 	IndentPrefsType.tp_new = PyType_GenericNew;
434 	if (PyType_Ready(&IndentPrefsType) < 0)
435 		return;
436 
437 	m = Py_InitModule3("editor", EditorModule_methods,
438 			"Editor information and management.");
439 
440 	Py_INCREF(&EditorType);
441 	PyModule_AddObject(m, "Editor", (PyObject *)&EditorType);
442 
443 	Py_INCREF(&IndentPrefsType);
444 	PyModule_AddObject(m, "IndentPrefs", (PyObject *)&IndentPrefsType);
445 
446 	PyModule_AddIntConstant(m, "INDENT_TYPE_SPACES",
447 		(glong) GEANY_INDENT_TYPE_SPACES);
448 	PyModule_AddIntConstant(m, "INDENT_TYPE_TABS",
449 		(glong) GEANY_INDENT_TYPE_TABS);
450 	PyModule_AddIntConstant(m, "INDENT_TYPE_BOTH",
451 		(glong) GEANY_INDENT_TYPE_BOTH);
452 	PyModule_AddIntConstant(m, "INDICATOR_ERROR",
453 		(glong) GEANY_INDICATOR_ERROR);
454 	PyModule_AddIntConstant(m, "INDICATOR_SEARCH",
455 		(glong) GEANY_INDICATOR_SEARCH);
456 	PyModule_AddStringConstant(m, "WORDCHARS", GEANY_WORDCHARS);
457 
458 	PyModule_AddIntConstant(m, "INDENT_TYPE_SPACES", (glong) GEANY_INDENT_TYPE_SPACES);
459 	PyModule_AddIntConstant(m, "INDENT_TYPE_TABS", (glong) GEANY_INDENT_TYPE_TABS);
460 	PyModule_AddIntConstant(m, "INDENT_TYPE_BOTH", (glong) GEANY_INDENT_TYPE_BOTH);
461 }
462 
463 
Editor_create_new_from_geany_editor(GeanyEditor * editor)464 Editor *Editor_create_new_from_geany_editor(GeanyEditor *editor)
465 {
466 	Editor *self;
467 	self = (Editor *) PyObject_CallObject((PyObject *) &EditorType, NULL);
468 	self->editor = editor;
469 	return self;
470 }
471