Refactor: Renamed text tool methods (suggestions and docs) for clarity and consistency.
[blender-staging.git] / source / blender / python / api2_2x / Text.c
1 /* 
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * This is a new part of Blender.
24  *
25  * Contributor(s): Willian P. Germano
26  *
27  * ***** END GPL LICENSE BLOCK *****
28 */
29
30 #include "Text.h" /*This must come first*/
31
32 #include "BKE_library.h"
33 #include "BKE_sca.h"
34 #include "BKE_global.h"
35 #include "BKE_main.h"
36 #include "BIF_drawtext.h"
37 #include "BIF_screen.h"
38 #include "BKE_text.h"
39 #include "BKE_suggestions.h"
40 #include "BLI_blenlib.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_space_types.h"
43 #include "MEM_guardedalloc.h"
44 #include "gen_utils.h"
45 #include "gen_library.h"
46 #include "../BPY_extern.h"
47
48 #define EXPP_TEXT_MODE_FOLLOW TXT_FOLLOW
49
50 /*****************************************************************************/
51 /* Python API function prototypes for the Text module.                       */
52 /*****************************************************************************/
53 static PyObject *M_Text_New( PyObject * self, PyObject * args);
54 static PyObject *M_Text_Get( PyObject * self, PyObject * args );
55 static PyObject *M_Text_Load( PyObject * self, PyObject * value );
56 static PyObject *M_Text_unlink( PyObject * self, PyObject * args );
57
58 /*****************************************************************************/
59 /* The following string definitions are used for documentation strings.      */
60 /* In Python these will be written to the console when doing a               */
61 /* Blender.Text.__doc__                                                      */
62 /*****************************************************************************/
63 static char M_Text_doc[] = "The Blender Text module\n\n";
64
65 static char M_Text_New_doc[] = "() - return a new Text object";
66
67 static char M_Text_Get_doc[] = "(name) - return the Text with name 'name', \
68 returns None if not found.\n If 'name' is not specified, \
69 it returns a list of all Texts in the\ncurrent scene.";
70
71 static char M_Text_Load_doc[] =
72         "(filename) - return text from file filename as a Text Object, \
73 returns None if not found.\n";
74
75 static char M_Text_unlink_doc[] =
76         "(text) - remove Text object 'text' from Blender";
77
78 /*****************************************************************************/
79 /* Python method structure definition for Blender.Text module:               */
80 /*****************************************************************************/
81 struct PyMethodDef M_Text_methods[] = {
82         {"New", M_Text_New, METH_VARARGS, M_Text_New_doc},
83         {"Get", M_Text_Get, METH_VARARGS, M_Text_Get_doc},
84         {"get", M_Text_Get, METH_VARARGS, M_Text_Get_doc},
85         {"Load", M_Text_Load, METH_O, M_Text_Load_doc},
86         {"unlink", M_Text_unlink, METH_VARARGS, M_Text_unlink_doc},
87         {NULL, NULL, 0, NULL}
88 };
89
90
91 /*****************************************************************************/
92 /* Python BPy_Text methods declarations:                                     */
93 /*****************************************************************************/
94 static PyObject *Text_getFilename( BPy_Text * self );
95 static PyObject *Text_getNLines( BPy_Text * self );
96 static PyObject *Text_clear( BPy_Text * self );
97 static PyObject *Text_reset( BPy_Text * self );
98 static PyObject *Text_readline( BPy_Text * self );
99 static PyObject *Text_write( BPy_Text * self, PyObject * value );
100 static PyObject *Text_insert( BPy_Text * self, PyObject * value );
101 static PyObject *Text_set( BPy_Text * self, PyObject * args );
102 static PyObject *Text_asLines( BPy_Text * self );
103 static PyObject *Text_getCursorPos( BPy_Text * self );
104 static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args );
105 static PyObject *Text_suggest( BPy_Text * self, PyObject * args );
106 static PyObject *Text_showDocs( BPy_Text * self, PyObject * args );
107
108 /*****************************************************************************/
109 /* Python BPy_Text methods table:                                            */
110 /*****************************************************************************/
111 static PyMethodDef BPy_Text_methods[] = {
112         /* name, method, flags, doc */
113         {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
114          "() - Return Text Object name"},
115         {"getFilename", ( PyCFunction ) Text_getFilename, METH_VARARGS,
116          "() - Return Text Object filename"},
117         {"getNLines", ( PyCFunction ) Text_getNLines, METH_VARARGS,
118          "() - Return number of lines in text buffer"},
119         {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
120          "(str) - Change Text Object name"},
121         {"clear", ( PyCFunction ) Text_clear, METH_NOARGS,
122          "() - Clear Text buffer"},
123         {"reset", ( PyCFunction ) Text_reset, METH_NOARGS,
124          "() - Moves the IO pointer back to the start of the Text buffer for reading"},
125         {"readline", ( PyCFunction ) Text_readline, METH_NOARGS,
126          "() - Reads a line of text from the buffer and returns it incrementing the internal IO pointer."},
127         {"write", ( PyCFunction ) Text_write, METH_O,
128          "(line) - Append string 'str' to Text buffer"},
129         {"insert", ( PyCFunction ) Text_insert, METH_O,
130          "(line) - Insert string 'str' to Text buffer at cursor location"},
131         {"set", ( PyCFunction ) Text_set, METH_VARARGS,
132          "(name, val) - Set attribute 'name' to value 'val'"},
133         {"asLines", ( PyCFunction ) Text_asLines, METH_NOARGS,
134          "() - Return text buffer as a list of lines"},
135         {"getCursorPos", ( PyCFunction ) Text_getCursorPos, METH_NOARGS,
136          "() - Return cursor position as (row, col) tuple"},
137         {"setCursorPos", ( PyCFunction ) Text_setCursorPos, METH_VARARGS,
138          "(row, col) - Set the cursor position to (row, col)"},
139         {"suggest", ( PyCFunction ) Text_suggest, METH_VARARGS,
140          "(list, prefix='') - Presents a list of suggestions. List is of strings, or tuples. Tuples must be of the form (name, type) where type is one of 'm', 'v', 'f', 'k' for module, variable, function and keyword respectively or '?' for other types"},
141         {"showDocs", ( PyCFunction ) Text_showDocs, METH_VARARGS,
142          "(docs) - Documentation string"},
143         {NULL, NULL, 0, NULL}
144 };
145
146 /*****************************************************************************/
147 /* Python Text_Type callback function prototypes:                            */
148 /*****************************************************************************/
149 static int Text_compare( BPy_Text * a, BPy_Text * b );
150 static PyObject *Text_repr( BPy_Text * self );
151
152 /*****************************************************************************/
153 /* Function:              M_Text_New                                         */
154 /* Python equivalent:     Blender.Text.New                                   */
155 /*****************************************************************************/
156 static PyObject *M_Text_New( PyObject * self, PyObject * args)
157 {
158         char *name = "Text";
159         int follow = 0;
160         Text *bl_text;          /* blender text object */
161         PyObject *py_text;      /* python wrapper */
162
163         if( !PyArg_ParseTuple( args, "|si", &name, &follow ) )
164                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
165                                               "expected string and int arguments (or nothing)" );
166
167         bl_text = add_empty_text( name );
168
169         if( bl_text ) {
170                 /* do not set user count because Text is already linked */
171
172                 /* create python wrapper obj */
173                 py_text = Text_CreatePyObject( bl_text );
174         } else
175                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
176                                               "couldn't create Text Object in Blender" );
177         if( !py_text )
178                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
179                                               "couldn't create Text Object wrapper" );
180
181         if( follow )
182                 bl_text->flags |= EXPP_TEXT_MODE_FOLLOW;
183
184         return py_text;
185 }
186
187 /*****************************************************************************/
188 /* Function:              M_Text_Get                                         */
189 /* Python equivalent:     Blender.Text.Get                                   */
190 /* Description:           Receives a string and returns the text object      */
191 /*                        whose name matches the string.  If no argument is  */
192 /*                        passed in, a list of all text names in the current */
193 /*                        scene is returned.                                 */
194 /*****************************************************************************/
195 static PyObject *M_Text_Get( PyObject * self, PyObject * args )
196 {
197         char *name = NULL;
198         Text *txt_iter;
199
200         if( !PyArg_ParseTuple( args, "|s", &name ) )
201                 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
202                                                 "expected string argument (or nothing)" ) );
203
204         txt_iter = G.main->text.first;
205
206         if( name ) {            /* (name) - Search text by name */
207
208                 PyObject *wanted_txt = NULL;
209
210                 while( ( txt_iter ) && ( wanted_txt == NULL ) ) {
211
212                         if( strcmp( name, txt_iter->id.name + 2 ) == 0 ) {
213                                 wanted_txt = Text_CreatePyObject( txt_iter );
214                         }
215
216                         txt_iter = txt_iter->id.next;
217                 }
218
219                 if( wanted_txt == NULL ) {      /* Requested text doesn't exist */
220                         char error_msg[64];
221                         PyOS_snprintf( error_msg, sizeof( error_msg ),
222                                 "Text \"%s\" not found", name );
223                         return ( EXPP_ReturnPyObjError
224                                 ( PyExc_NameError, error_msg ) );
225                 }
226
227                 return wanted_txt;
228         }
229
230         else {                  /* () - return a list of all texts in the scene */
231                 int index = 0;
232                 PyObject *txtlist, *pyobj;
233
234                 txtlist = PyList_New( BLI_countlist( &( G.main->text ) ) );
235
236                 if( txtlist == NULL )
237                         return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
238                                                         "couldn't create PyList" ) );
239
240                 while( txt_iter ) {
241                         pyobj = Text_CreatePyObject( txt_iter );
242
243                         if( !pyobj ) {
244                                 Py_DECREF(txtlist);
245                                 return ( EXPP_ReturnPyObjError
246                                          ( PyExc_MemoryError,
247                                            "couldn't create PyString" ) );
248                         }
249                         PyList_SET_ITEM( txtlist, index, pyobj );
250
251                         txt_iter = txt_iter->id.next;
252                         index++;
253                 }
254
255                 return ( txtlist );
256         }
257 }
258
259 /*****************************************************************************/
260 /* Function:              M_Text_Load                                        */
261 /* Python equivalent:     Blender.Text.Load                                  */
262 /* Description:           Receives a filename and returns the text object    */
263 /*                        created from the corresponding file.               */
264 /*****************************************************************************/
265 static PyObject *M_Text_Load( PyObject * self, PyObject * value )
266 {
267         char *fname = PyString_AsString(value);
268         char fpath[FILE_MAXDIR + FILE_MAXFILE];
269         Text *txt_ptr = NULL;
270         unsigned int maxlen = FILE_MAXDIR + FILE_MAXFILE;
271
272         if( !fname )
273                 return ( EXPP_ReturnPyObjError( PyExc_TypeError,
274                                                 "expected string argument" ) );
275
276         if (strlen(fname) > (maxlen - 1))
277                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
278                         "text filename too long");
279         else if (!BLI_exists(fname))
280                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
281                         "text file not found");
282
283         BLI_strncpy(fpath, fname, maxlen);
284
285         txt_ptr = add_text( fpath );
286         if( !txt_ptr )
287                 return EXPP_ReturnPyObjError( PyExc_IOError,
288                                               "couldn't load text" );
289
290         return Text_CreatePyObject(txt_ptr);
291 }
292
293 /*****************************************************************************/
294 /* Function:              M_Text_unlink                                      */
295 /* Python equivalent:     Blender.Text.unlink                                */
296 /* Description:           Removes the given Text object from Blender         */
297 /*****************************************************************************/
298 static PyObject *M_Text_unlink( PyObject * self, PyObject * args )
299 {
300         BPy_Text *textobj;
301         Text *text;
302
303         if( !PyArg_ParseTuple( args, "O!", &Text_Type, &textobj ) )
304                 return EXPP_ReturnPyObjError( PyExc_TypeError,
305                                               "expected a Text object as argument" );
306
307         text = ( ( BPy_Text * ) textobj )->text;
308
309         if( !text )
310                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
311                                               "this text was already unlinked!" );
312
313         BPY_clear_bad_scriptlinks( text );
314         BPY_free_pyconstraint_links( text );
315         free_text_controllers( text );
316         unlink_text( text );
317
318         free_libblock( &G.main->text, text );
319
320         ( ( BPy_Text * ) textobj )->text = NULL;
321
322         Py_RETURN_NONE;
323 }
324
325 /*****************************************************************************/
326 /* Function:              Text_Init                                          */
327 /*****************************************************************************/
328 PyObject *Text_Init( void )
329 {
330         PyObject *submodule;
331
332         if( PyType_Ready( &Text_Type ) < 0 )
333                 return NULL;
334
335         submodule =
336                 Py_InitModule3( "Blender.Text", M_Text_methods, M_Text_doc );
337
338         return ( submodule );
339 }
340
341 /*****************************************************************************/
342 /* Function:              Text_CreatePyObject                                */
343 /*****************************************************************************/
344 PyObject *Text_CreatePyObject( Text * txt )
345 {
346         BPy_Text *pytxt;
347
348         pytxt = ( BPy_Text * ) PyObject_NEW( BPy_Text, &Text_Type );
349
350         if( !pytxt )
351                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
352                                               "couldn't create BPy_Text PyObject" );
353
354         pytxt->text = txt;
355         pytxt->iol = 0;
356         pytxt->ioc = 0;
357
358         return ( PyObject * ) pytxt;
359 }
360
361 /*****************************************************************************/
362 /* Python BPy_Text methods:                                                  */
363 /*****************************************************************************/
364 static PyObject *Text_getFilename( BPy_Text * self )
365 {
366         if( self->text->name )
367                 return PyString_FromString( self->text->name );
368         
369         Py_RETURN_NONE;
370 }
371
372 static PyObject *Text_getNLines( BPy_Text * self )
373 {                               /* text->nlines isn't updated in Blender (?) */
374         int nlines = 0;
375         TextLine *line;
376
377         line = self->text->lines.first;
378
379         while( line ) {         /* so we have to count them ourselves */
380                 line = line->next;
381                 nlines++;
382         }
383
384         self->text->nlines = nlines;    /* and update Blender, too (should we?) */
385
386         return PyInt_FromLong( nlines );
387 }
388
389 static PyObject *Text_clear( BPy_Text * self)
390 {
391         int oldstate;
392
393         if( !self->text )
394                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
395                                               "This object isn't linked to a Blender Text Object" );
396
397         oldstate = txt_get_undostate(  );
398         txt_set_undostate( 1 );
399         txt_sel_all( self->text );
400         txt_cut_sel( self->text );
401         txt_set_undostate( oldstate );
402
403         Py_RETURN_NONE;
404 }
405
406 static PyObject *Text_reset( BPy_Text * self )
407 {
408         self->iol = 0;
409         self->ioc = 0;
410
411         Py_RETURN_NONE;
412 }
413
414 static PyObject *Text_readline( BPy_Text * self )
415 {
416         PyObject *tmpstr;
417         TextLine *line;
418         int i;
419         
420         if( !self->text )
421                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
422                                               "This object isn't linked to a Blender Text Object" );
423
424         for (i=0, line=self->text->lines.first; i<self->iol && line; i++, line=line->next);
425
426         if (!line) {
427                 PyErr_SetString( PyExc_StopIteration, "End of buffer reached" );
428                 return PyString_FromString( "" );
429         }
430
431         if (self->ioc > line->len)
432                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
433                                                   "Line length exceeded, text may have changed while reading" );
434
435         tmpstr = PyString_FromString( line->line + self->ioc );
436         if (line->next)
437                 PyString_ConcatAndDel( &tmpstr, PyString_FromString("\n") );
438
439         self->iol++;
440         self->ioc = 0;
441
442         return tmpstr;
443 }
444
445 static PyObject *Text_write( BPy_Text * self, PyObject * value )
446 {
447         char *str = PyString_AsString(value);
448         int oldstate;
449
450         if( !self->text )
451                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
452                                               "This object isn't linked to a Blender Text Object" );
453
454         if( !str )
455                 return EXPP_ReturnPyObjError( PyExc_TypeError,
456                                               "expected string argument" );
457
458         oldstate = txt_get_undostate(  );
459         txt_insert_buf( self->text, str );
460         txt_move_eof( self->text, 0 );
461         txt_set_undostate( oldstate );
462
463         Py_RETURN_NONE;
464 }
465
466 static PyObject *Text_insert( BPy_Text * self, PyObject * value )
467 {
468         char *str = PyString_AsString(value);
469         int oldstate;
470
471         if( !self->text )
472                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
473                                               "This object isn't linked to a Blender Text Object" );
474
475         if( !str )
476                 return EXPP_ReturnPyObjError( PyExc_TypeError,
477                                               "expected string argument" );
478
479         oldstate = txt_get_undostate(  );
480         txt_insert_buf( self->text, str );
481         txt_set_undostate( oldstate );
482
483         Py_RETURN_NONE;
484 }
485
486 static PyObject *Text_set( BPy_Text * self, PyObject * args )
487 {
488         int ival;
489         char *attr;
490
491         if( !PyArg_ParseTuple( args, "si", &attr, &ival ) )
492                 return EXPP_ReturnPyObjError( PyExc_TypeError,
493                                               "expected a string and an int as arguments" );
494
495         if( strcmp( "follow_cursor", attr ) == 0 ) {
496                 if( ival )
497                         self->text->flags |= EXPP_TEXT_MODE_FOLLOW;
498                 else
499                         self->text->flags &= EXPP_TEXT_MODE_FOLLOW;
500         }
501
502         Py_RETURN_NONE;
503 }
504
505 static PyObject *Text_asLines( BPy_Text * self )
506 {
507         TextLine *line;
508         PyObject *list, *tmpstr;
509
510         if( !self->text )
511                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
512                                               "This object isn't linked to a Blender Text Object" );
513
514         line = self->text->lines.first;
515         list = PyList_New( 0 );
516
517         if( !list )
518                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
519                                               "couldn't create PyList" );
520
521         while( line ) {
522                 tmpstr = PyString_FromString( line->line );
523                 PyList_Append( list, tmpstr );
524                 Py_DECREF(tmpstr);
525                 line = line->next;
526         }
527
528         return list;
529 }
530
531 static PyObject *Text_getCursorPos( BPy_Text * self )
532 {
533         Text *text;
534         TextLine *linep;
535         int row, col;
536
537         text = self->text;
538         if( !text )
539                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
540                                               "This object isn't linked to a Blender Text Object" );
541
542         for (row=0,linep=text->lines.first; linep!=text->curl; linep=linep->next)
543                 row++;
544         col= text->curc;
545
546         return Py_BuildValue( "ii", row, col );
547 }
548
549 static PyObject *Text_setCursorPos( BPy_Text * self, PyObject * args )
550 {
551         int row, col;
552         int oldstate;
553         SpaceText *st;
554
555         if (!self->text)
556                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
557                                               "This object isn't linked to a Blender Text Object");
558
559         if (!PyArg_ParseTuple(args, "ii", &row, &col))
560                 return EXPP_ReturnPyObjError(PyExc_TypeError,
561                                               "expected two ints as arguments.");
562         if (col<0) col=0;
563         if (col>self->text->curl->len) col=self->text->curl->len;
564
565         oldstate = txt_get_undostate();
566         txt_move_to(self->text, row, col, 0);
567         txt_set_undostate(oldstate);
568
569         if (curarea->spacetype == SPACE_TEXT && (st=curarea->spacedata.first))
570                 pop_space_text(st);
571
572         Py_RETURN_NONE;
573 }
574
575 static PyObject *Text_suggest( BPy_Text * self, PyObject * args )
576 {
577         PyObject *item = NULL, *tup1 = NULL, *tup2 = NULL;
578         PyObject *list = NULL, *resl = NULL;
579         int list_len, i;
580         char *prefix = NULL, *name, type;
581         SpaceText *st;
582
583         if (!self->text)
584                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
585                                 "This object isn't linked to a Blender Text Object");
586
587         /* Parse args for a list of strings/tuples */
588         if (!PyArg_ParseTuple(args, "O!|s", &PyList_Type, &list, &prefix))
589                 return EXPP_ReturnPyObjError(PyExc_TypeError,
590                                 "expected list of strings or tuples followed by an optional string");
591
592         if (curarea->spacetype != SPACE_TEXT)
593                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
594                                 "Active space type is not text");
595         
596         st = curarea->spacedata.first;
597         if (!st || !st->text)
598                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
599                                 "Active text area has no Text object");
600         
601         texttool_suggest_clear();
602         texttool_text_set_active(st->text);
603         list_len = PyList_Size(list);
604         
605         for (i = 0; i < list_len; i++) {
606                 item = PyList_GetItem(list, i);
607
608                 if (PyString_Check(item)) {
609                         name = PyString_AsString(item);
610                         type = '?';
611                 } else if (PyTuple_Check(item) && PyTuple_GET_SIZE(item) == 2) {
612                         tup1 = PyTuple_GetItem(item, 0);
613                         tup2 = PyTuple_GetItem(item, 1);
614                         if (PyString_Check(tup1) && PyString_Check(tup2)) {
615                                 name = PyString_AsString(tup1);
616                                 type = PyString_AsString(tup2)[0];
617                         } else
618                                 return EXPP_ReturnPyObjError(PyExc_AttributeError,
619                                                 "list must contain tuples of two strings only: (name, type)" );
620                 } else
621                         return EXPP_ReturnPyObjError(PyExc_AttributeError,
622                                         "list must contain only individual strings or tuples of size 2" );
623
624                 if (!strlen(name) || (type!='m' && type!='v' && type!='f' && type!='k' && type!='?'))
625                         return EXPP_ReturnPyObjError(PyExc_AttributeError,
626                                         "names must be non-empty and types in ['m', 'v', 'f', 'k', '?']" );
627
628                 texttool_suggest_add(name, type);
629         }
630         if (!prefix)
631                 prefix = "";
632         texttool_suggest_prefix(prefix);
633         scrarea_queue_redraw(curarea);
634
635         Py_RETURN_NONE;
636 }
637
638 static PyObject *Text_showDocs( BPy_Text * self, PyObject * args )
639 {
640         char *docs;
641         SpaceText *st;
642
643         if (!self->text)
644                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
645                                 "This object isn't linked to a Blender Text Object");
646
647         if (!PyArg_ParseTuple(args, "s", &docs))
648                 return EXPP_ReturnPyObjError( PyExc_TypeError,
649                                               "expected a string as argument" );
650
651         if (curarea->spacetype != SPACE_TEXT)
652                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
653                                 "Active space type is not text");
654         
655         st = curarea->spacedata.first;
656         if (!st || !st->text)
657                 return EXPP_ReturnPyObjError(PyExc_RuntimeError,
658                                 "Active text area has no Text object");
659
660         texttool_text_set_active(st->text);
661         texttool_docs_show(docs);
662         scrarea_queue_redraw(curarea);
663
664         Py_RETURN_NONE;
665 }
666
667 /*****************************************************************************/
668 /* Function:    Text_compare                                                 */
669 /* Description: This is a callback function for the BPy_Text type. It        */
670 /*              compares two Text_Type objects. Only the "==" and "!="       */
671 /*              comparisons are meaninful. Returns 0 for equality and -1 if  */
672 /*              they don't point to the same Blender Text struct.            */
673 /*              In Python it becomes 1 if they are equal, 0 otherwise.       */
674 /*****************************************************************************/
675 static int Text_compare( BPy_Text * a, BPy_Text * b )
676 {
677         return ( a->text == b->text ) ? 0 : -1;
678 }
679
680 /*****************************************************************************/
681 /* Function:    Text_repr                                                    */
682 /* Description: This is a callback function for the BPy_Text type. It        */
683 /*              builds a meaninful string to represent text objects.         */
684 /*****************************************************************************/
685 static PyObject *Text_repr( BPy_Text * self )
686 {
687         if( self->text )
688                 return PyString_FromFormat( "[Text \"%s\"]",
689                                             self->text->id.name + 2 );
690         else
691                 return PyString_FromString( "[Text <deleted>]" );
692 }
693
694 /*****************************************************************************/
695 /* Python attributes get/set functions:                                      */
696 /*****************************************************************************/
697 static PyObject *Text_getMode(BPy_Text * self)
698 {
699         return PyInt_FromLong( self->text->flags );
700 }
701
702 /*****************************************************************************/
703 /* Python attributes get/set structure:                                      */
704 /*****************************************************************************/
705 static PyGetSetDef BPy_Text_getseters[] = {
706         GENERIC_LIB_GETSETATTR,
707         {"filename", (getter)Text_getFilename, (setter)NULL,
708          "text filename", NULL},
709         {"mode", (getter)Text_getMode, (setter)NULL,
710          "text mode flag", NULL},
711         {"nlines", (getter)Text_getNLines, (setter)NULL,
712          "number of lines", NULL},
713         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
714 };
715
716 /*****************************************************************************/
717 /* Python Text_Type structure definition:                                    */
718 /*****************************************************************************/
719 PyTypeObject Text_Type = {
720         PyObject_HEAD_INIT( NULL ) 
721         0,      /* ob_size */
722         "Blender Text",         /* tp_name */
723         sizeof( BPy_Text ),     /* tp_basicsize */
724         0,                      /* tp_itemsize */
725         /* methods */
726         NULL,   /* tp_dealloc */
727         NULL,                   /* tp_print */
728         NULL,   /* tp_getattr */
729         NULL,   /* tp_setattr */
730         ( cmpfunc ) Text_compare,       /* tp_compare */
731         ( reprfunc ) Text_repr, /* tp_repr */
732
733         /* Method suites for standard classes */
734
735         NULL,                       /* PyNumberMethods *tp_as_number; */
736         NULL,                       /* PySequenceMethods *tp_as_sequence; */
737         NULL,                       /* PyMappingMethods *tp_as_mapping; */
738
739         /* More standard operations (here for binary compatibility) */
740
741         ( hashfunc ) GenericLib_hash,   /* hashfunc tp_hash; */
742         NULL,                       /* ternaryfunc tp_call; */
743         NULL,                       /* reprfunc tp_str; */
744         NULL,                       /* getattrofunc tp_getattro; */
745         NULL,                       /* setattrofunc tp_setattro; */
746
747         /* Functions to access object as input/output buffer */
748         NULL,                       /* PyBufferProcs *tp_as_buffer; */
749  
750   /*** Flags to define presence of optional/expanded features ***/
751         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
752
753         NULL,                       /*  char *tp_doc;  Documentation string */
754   /*** Assigned meaning in release 2.0 ***/
755         /* call function for all accessible objects */
756         NULL,                       /* traverseproc tp_traverse; */
757
758         /* delete references to contained objects */
759         NULL,                       /* inquiry tp_clear; */
760
761   /***  Assigned meaning in release 2.1 ***/
762   /*** rich comparisons ***/
763         NULL,                       /* richcmpfunc tp_richcompare; */
764
765   /***  weak reference enabler ***/
766         0,                          /* long tp_weaklistoffset; */
767
768   /*** Added in release 2.2 ***/
769         /*   Iterators */
770         NULL,                       /* getiterfunc tp_iter; */
771         NULL,                       /* iternextfunc tp_iternext; */
772
773   /*** Attribute descriptor and subclassing stuff ***/
774         BPy_Text_methods,           /* struct PyMethodDef *tp_methods; */
775         NULL,                       /* struct PyMemberDef *tp_members; */
776         BPy_Text_getseters,         /* struct PyGetSetDef *tp_getset; */
777         NULL,                       /* struct _typeobject *tp_base; */
778         NULL,                       /* PyObject *tp_dict; */
779         NULL,                       /* descrgetfunc tp_descr_get; */
780         NULL,                       /* descrsetfunc tp_descr_set; */
781         0,                          /* long tp_dictoffset; */
782         NULL,                       /* initproc tp_init; */
783         NULL,                       /* allocfunc tp_alloc; */
784         NULL,                       /* newfunc tp_new; */
785         /*  Low-level free-memory routine */
786         NULL,                       /* freefunc tp_free;  */
787         /* For PyObject_IS_GC */
788         NULL,                       /* inquiry tp_is_gc;  */
789         NULL,                       /* PyObject *tp_bases; */
790         /* method resolution order */
791         NULL,                       /* PyObject *tp_mro;  */
792         NULL,                       /* PyObject *tp_cache; */
793         NULL,                       /* PyObject *tp_subclasses; */
794         NULL,                       /* PyObject *tp_weaklist; */
795         NULL
796 };