SF.net SVN: geany: [1628] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Sun Jun 17 17:56:48 UTC 2007


Revision: 1628
          http://svn.sourceforge.net/geany/?rev=1628&view=rev
Author:   eht16
Date:     2007-06-17 10:56:48 -0700 (Sun, 17 Jun 2007)

Log Message:
-----------
Add new command line option --ft-names to get a list of supported filetype names.
Complete rewrite of auto completion to make it user-definable and much more flexible.	    

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/Makefile.am
    trunk/TODO
    trunk/doc/geany.1.in
    trunk/doc/geany.docbook
    trunk/src/editor.c
    trunk/src/editor.h
    trunk/src/keyfile.c
    trunk/src/keyfile.h
    trunk/src/main.c

Added Paths:
-----------
    trunk/data/autocomplete.conf

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/ChangeLog	2007-06-17 17:56:48 UTC (rev 1628)
@@ -2,6 +2,13 @@
 
  * src/templates.c, src/tools.c: Apply patch from Alexander Rodin to
                                  improve the class builder code(thanks).
+ * Makefile.am, TODO, data/autocomplete.conf, doc/geany.1.in,
+   doc/geany.docbook, src/editor.c, src/editor.h, src/keyfile.c,
+   src/keyfile.h, src/main.c:
+   Add new command line option --ft-names to get a list of supported
+   filetype names.
+   Complete rewrite of auto completion to make it user-definable and
+   much more flexible.
 
 
 2007-06-15  Frank Lanitz  <frank at frank.uvena.de>

Modified: trunk/Makefile.am
===================================================================
--- trunk/Makefile.am	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/Makefile.am	2007-06-17 17:56:48 UTC (rev 1628)
@@ -17,7 +17,8 @@
 	data/pascal.tags \
 	data/html_entities.tags \
 	$(srcdir)/data/filetypes.* \
-	data/filetype_extensions.conf
+	data/filetype_extensions.conf \
+	data/autocomplete.conf
 
 EXTRA_DIST = \
 	autogen.sh \

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/TODO	2007-06-17 17:56:48 UTC (rev 1628)
@@ -11,7 +11,6 @@
 	  return type with const, [] for D, etc.)
 	o documentation: list and explain filetype modes
 	o documentation: preferences
-	o user-definable construct completion
 	o line breaking mode to limit words on a line for e.g. XML content.
 	o common default highlighting for all programming languages
 	o fix parsing command line args after given filenames

Added: trunk/data/autocomplete.conf
===================================================================
--- trunk/data/autocomplete.conf	                        (rev 0)
+++ trunk/data/autocomplete.conf	2007-06-17 17:56:48 UTC (rev 1628)
@@ -0,0 +1,45 @@
+# Geany's auto completion configuration file
+# use \n or %newline% for a new line (it will be replaced by the used EOL char(s) - LF, CR/LF, CR)
+# use \t ot %ws% for an indentation step, if using only spaces for indentation only spaces will be used
+# use \s to force whitespace at beginning or end of a value ('key= value' won't work, use 'key=\svalue')
+# use %cursor% to define where the cursor should be placed after completion
+# use %key% for all keys defined in the [Special] section
+# you can define a section for each supported filetype to overwrite default settings, the section
+# name must match exactly the internal filetype name, run 'geany --ft-names' for a full list
+
+# filetype names:
+# C, C++, D, Java, Pascal, ASM, Fortran, CAML, Haskell, VHDL, Perl, PHP, Javascript, Python, Ruby,
+# Tcl, Lua, Ferite, Sh, Make, O-Matrix, XML, Docbook, HTML, CSS, SQL, LaTeX, Diff, Conf, None
+
+# Default is used for all filetypes and keys can be overwritten by [filetype] sections
+[Default]
+if=if (%cursor%)%brace_open%\n%brace_close%
+else=else%brace_open%\n%brace_close%
+for=for (i = 0; i < %cursor%; i++)%brace_open%\n%brace_close%
+while=while (%cursor%)%brace_open%\n%brace_close%
+do=do%brace_open%%cursor%\n%brace_close%while ()
+switch=switch (%cursor%)%brace_open%case : break;\n%ws%default: \n%brace_close%
+try=try%block_cursor%catch ()%block%
+
+# special keys to be used in other completions, cannot be used "standalone"
+# can be used by %key%, e.g. %brace_open%
+# nesting of special keys is not supported (e.g. brace_open=\n{\n%brace_close% won't work)
+[Special]
+brace_open=\n{\n\t
+brace_close=}\n
+block=\n{\n\t\n}\n
+block_cursor=\n{\n\t%cursor%\n}\n
+
+[C++]
+for=for (int i = 0; i < %cursor%; i++)%brace_open%\n%brace_close%
+
+[Java]
+for=for (int i = 0; i < %cursor%; i++)%brace_open%\n%brace_close%
+
+[PHP]
+for=for ($i = 0; $i < %cursor%; $i++)%brace_open%\n%brace_close%
+
+[Ferite]
+iferr=iferr%block_cursor%fix%block%
+monitor=monitor%block_cursor%handle%block%
+

Modified: trunk/doc/geany.1.in
===================================================================
--- trunk/doc/geany.1.in	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/doc/geany.1.in	2007-06-17 17:56:48 UTC (rev 1628)
@@ -1,4 +1,4 @@
-.TH "GEANY" "1" "May 21, 2007" "@PACKAGE@ @VERSION@" ""
+.TH "GEANY" "1" "June 17, 2007" "@PACKAGE@ @VERSION@" ""
 .SH "NAME"
 Geany \(em a small and lightweight IDE
 .SH "SYNOPSIS"
@@ -20,6 +20,8 @@
 ~/.geany/ and there resides geany.conf and some template files.
 .IP "\fB-d\fP           \fB\-\-debug\fP         " 10
 Run Geany in debug mode, which means being verbose and printing lots of information.
+.IP "\fB\fP             \fB\-\-ft\-names\fP         " 10
+Print a list of Geany's internal filetype names (useful for the auto completion list).
 .IP "\fB-i\fP           \fB\-\-new-instance\fP         " 10
 Don't open files in a running instance, force opening a new instance.
 Only available if Geany was compiled with support for Sockets.

Modified: trunk/doc/geany.docbook
===================================================================
--- trunk/doc/geany.docbook	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/doc/geany.docbook	2007-06-17 17:56:48 UTC (rev 1628)
@@ -229,6 +229,13 @@
 								</entry>
 							</row>
 							<row>
+								<entry></entry>
+								<entry>--ft-names</entry>
+								<entry>Print a list of <application>Geany</application>'s internal
+									   filetype names (useful for the auto completion list).
+								</entry>
+							</row>
+							<row>
 								<entry>-i</entry>
 								<entry>--new-instance</entry>
 								<entry>Do not open files in a running instance, force opening a
@@ -583,26 +590,6 @@
 					</variablelist>
 				</para>
 			</section>
-			<section id="editing_cc">
-				<title>Construct completion</title>
-				<para>
-					Built-in construct completion is available for C-like languages. By default the
-					<keycap>Tab</keycap> key is used straight after typing the construct keyword.
-				</para>
-				<para>
-					Example: <literal>for</literal><TAB>
-				</para>
-				<para>
-					typed into a C file expands to:
-				</para>
-				<para>
-					<literallayout><literal>for (i = 0; i < ; i++)
-					{
-
-					}
-					</literal></literallayout>
-				</para>
-			</section>
 			<section id="editing_bookmarks">
 				<title>Bookmarks</title>
 				<para>
@@ -675,6 +662,108 @@
 					and it will open the address: http://www.php.net/echo.
 				</para>
 			</section>
+			<section id="editing_cc">
+				<title>User-definable auto completion</title>
+				<para>
+					Geany can complete pre-defined constructs and often used strings automatically.
+					To know what to complete or replace Geany reads a configuration file called
+					<filename>autocomplete.conf</filename> at startup.
+				</para>
+				<para>
+					The system-wide configuration file can be found in
+					<filename>$prefix/share/geany</filename>, where $prefix is the path where
+					<application>Geany</application> is	installed (commonly
+					<filename>/usr/local</filename>). It is not recommended to edit the system-wide
+					file, because it will be overridden when <application>Geany</application> is
+					updated.
+				</para>
+				<para>
+					To change the settings, copy the file from
+					<filename>$prefix/share/geany</filename> in your configuration directory
+					(usually <filename>~/.geany/</filename>).
+				</para>
+				<para>
+					 For example:
+					 <screen><prompt>%</prompt> <userinput><command>cp /usr/local/share/geany/autocomplete.conf /home/username/.geany/</command></userinput></screen>
+					 Then you can edit the file and the changes are also available after an update of
+					 <application>Geany</application> because the file resides in your configuration
+					 directory. Alternatively, you can create a file
+					 <filename>~/.geany/autocomplete.conf</filename> and add only these settings
+					 you want to change. All missing settings will be read from the global auto
+					 completion file in <filename>$prefix/share/geany</filename>.
+				</para>
+				<para>
+					The file autocomplete.conf may contain several sections for each filetype. It
+					also contains two additional sections "Default" and "Special".
+					Default contains all completions which are available for every filetype. You
+					may define another section for a certain filetype(e.g. C++) containing the same
+					completions. Then when using such a completion in a C++ file the completion
+					defined in the C++ section will be used. In any other file the completion
+					defined in the Default section will be used unless a section for the current
+					filetype exists and the used completion is defined in this section.
+					The section "Special" contains special completions which can only be used in
+					other completions. So you can define often used parts of completions and just
+					use the special completion as a placeholder (see the autocomplete.conf for
+					details).
+				</para>
+				<para>
+					To define completions you can use several special characters which will be
+					replaced when using the completion:
+					<table frame="all" id="completion_wildcards">
+						<title>Wildcards for auto completion</title>
+						<tgroup cols="2">
+							<?dbhtml cellpadding="4" ?>
+							<?dbhtml cellspacing="0" ?>
+							<colspec colnum="1" colname="col1"/>
+							<colspec colnum="2" colname="col2"/>
+							<tbody>
+								<row>
+									<entry>\n or %newline%</entry>
+									<entry>Insert a new line (it will be replaced by the used
+										   EOL char(s) - LF, CR/LF, CR).</entry>
+								</row>
+								<row>
+									<entry>\t ot %ws%</entry>
+									<entry>Insert an indentation step, if using only spaces for
+										   indentation only spaces will be used.</entry>
+								</row>
+								<row>
+									<entry>\s</entry>
+									<entry>\s to force whitespace at beginning or end of a value
+										   ('key= value' won't work, use 'key=\svalue')</entry>
+								</row>
+								<row>
+									<entry>%cursor%</entry>
+									<entry>Place the cursor at this position after completion has
+										   been done.</entry>
+								</row>
+								<row>
+									<entry>%...%</entry>
+									<entry>... means the name of a key in the "Special" section.
+										   If you have defined a key "brace_open" in the "Special"
+										   section you can use %brace_open" in any other completion.
+									</entry>
+								</row>
+							</tbody>
+						</tgroup>
+					</table>
+				</para>
+				<para>
+					Defined completions must not contain spaces otherwise they won't work
+					correctly. But beside that you can define almost everything string as a
+					completion and use it later in Geany. It is not limited to existing contructs
+					of certain programming languages(like if, for, switch). Define whatever you
+					need.
+				</para>
+				<para>
+					Maybe you need to often type your name, so define a completion like this:
+					<literallayout><literal>[Default]
+					myname=Enrico Tröger</literal></literallayout>
+					Everytime you write <literal>myname</literal><TAB> in Geany, it will
+					replace "myname" by "Enrico Tröger". The key to start auto completion can
+					be changed in the preferences dialog, by default it is TAB.
+				</para>
+			</section>
 		</section>
 		<section id="search">
 			<title>Search, replace and go to</title>

Modified: trunk/src/editor.c
===================================================================
--- trunk/src/editor.c	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/src/editor.c	2007-06-17 17:56:48 UTC (rev 1628)
@@ -1081,137 +1081,119 @@
 }
 
 
-/* This should use a string with the current word instead of buf, but we will replace this
- * code with user-defined construct completion. */
-static gboolean complete_constructs(gint idx, gint pos, const gchar *buf, const gchar *space,
-		const gchar *eol)
+static gchar *ac_find_completion_by_name(const gchar *type, const gchar *name)
 {
-	gboolean result;
-	gchar *construct = NULL;
-	gint space_len = strlen(space);
-	ScintillaObject *sci = doc_list[idx].sci;
+	gchar *result = NULL;
+	GHashTable *tmp;
 
-	// "pattern", buf + x, y -> x + y = 15, because buf is (pos - 15)...(pos) = 15
-	if (! strncmp("if", buf + 13, 2))
-	{
-		if (! isspace(*(buf + 12)))
-			return FALSE;
+	g_return_val_if_fail(type != NULL && name != NULL, NULL);
 
-		construct = g_strdup_printf("()%s{%s%s%s}%s", eol, eol, space, eol, eol);
-
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 1, TRUE);
-	}
-	else if (! strncmp("else", buf + 11, 4))
+	tmp = g_hash_table_lookup(editor_prefs.auto_completions, type);
+	if (tmp != NULL)
 	{
-		if (! isspace(*(buf + 10)))
-			return FALSE;
-
-		construct = g_strdup_printf("%s{%s%s%s}%s", eol, eol, space, eol, eol);
-
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
+		result = g_hash_table_lookup(tmp, name);
 	}
-	else if (! strncmp("for", buf + 12, 3))
+	// whether nothing is set for the current filetype(tmp is NULL) or
+	// the particular completion for this filetype is not set (result is NULL)
+	if (tmp == NULL || result == NULL)
 	{
-		gchar *var;
-		gint contruct_len;
-
-		if (! isspace(*(buf + 11)))
-			return FALSE;
-
-		if (doc_list[idx].file_type->id == GEANY_FILETYPES_PHP)
+		tmp = g_hash_table_lookup(editor_prefs.auto_completions, "Default");
+		if (tmp != NULL)
 		{
-			var = g_strdup("$i");
-			contruct_len = 14;
+			result = g_hash_table_lookup(tmp, name);
 		}
-		else
-		{
-			var = g_strdup("i");
-			contruct_len = 12;
-		}
-		construct = g_strdup_printf("(%s%s = 0; %s < ; %s++)%s{%s%s%s}%s",
-						(doc_list[idx].file_type->id == GEANY_FILETYPES_CPP) ? "int " : "",
-						var, var, var, eol, eol, space, eol, eol);
-
-		// add 4 characters because of "int " in C++ mode
-		contruct_len += (doc_list[idx].file_type->id == GEANY_FILETYPES_CPP) ? 4 : 0;
-
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + contruct_len, TRUE);
-		g_free(var);
 	}
-	else if (! strncmp("while", buf + 10, 5))
-	{
-		if (! isspace(*(buf + 9)))
-			return FALSE;
+	// if result is still NULL here, no completion could be found
 
-		construct = g_strdup_printf("()%s{%s%s%s}%s", eol, eol, space, eol, eol);
+	// result is owned by the hash table and will be freed when the table will destroyed
+	return g_strdup(result);
+}
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 1, TRUE);
-	}
-	else if (! strncmp("do", buf + 13, 2))
-	{
-		if (! isspace(*(buf + 12)))
-			return FALSE;
 
-		construct = g_strdup_printf("%s{%s%s%s}%swhile ();%s", eol, eol, space, eol, eol, eol);
+/* This is very ugly but passing the pattern to ac_replace_specials() doesn't work because it is
+ * modified when replacing a completion but the foreach function still passes the old pointer
+ * to ac_replace_specials, so we use a global pointer outside of ac_replace_specials and
+ * ac_complete_constructs. Any hints to improve this are welcome. */
+static gchar *global_pattern = NULL;
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
-	}
-	else if (! strncmp("try", buf + 12, 3))
-	{
-		if (! isspace(*(buf + 11)))
-			return FALSE;
+void ac_replace_specials(gpointer key, gpointer value, gpointer user_data)
+{
+	gchar *needle;
 
-		construct = g_strdup_printf("%s{%s%s%s}%scatch ()%s{%s%s%s}%s",
-							eol, eol, space, eol, eol, eol, eol, space, eol, eol);
+	if (key == NULL || value == NULL)
+		return;
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
-	}
-	else if (! strncmp("switch", buf + 9, 6))
-	{
-		if (! isspace(*(buf + 8)))
-			return FALSE;
+	needle = g_strconcat("%", (gchar*) key, "%", NULL);
 
-		construct = g_strdup_printf("()%s{%s%scase : break;%s%sdefault: %s}%s",
-										eol, eol, space, eol, space, eol, eol);
+	global_pattern = utils_str_replace(global_pattern, needle, (gchar*) value);
+	g_free(needle);
+}
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 1, TRUE);
-	}
-	else if (doc_list[idx].file_type->id == GEANY_FILETYPES_FERITE && ! strncmp("iferr", buf + 10, 5))
-	{
-		if (! isspace(*(buf + 9)))
-			return FALSE;
 
-		construct = g_strdup_printf("%s{%s%s%s}%sfix%s{%s%s%s}%s",
-										eol, eol, space, eol, eol, eol, eol, space, eol, eol);
+static gboolean ac_complete_constructs(gint idx, gint pos, const gchar *word)
+{
+	gchar *str;
+	gchar *pattern;
+	gchar *lindent;
+	gchar *whitespace;
+	gint step, str_len;
+	GHashTable *specials;
+	ScintillaObject *sci = doc_list[idx].sci;
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
-	}
-	else if (doc_list[idx].file_type->id == GEANY_FILETYPES_FERITE && ! strncmp("monitor", buf + 8, 7))
+	str = g_strdup(word);
+	g_strstrip(str);
+
+	pattern = ac_find_completion_by_name(doc_list[idx].file_type->name, str);
+	if (pattern == NULL || pattern[0] == '\0')
 	{
-		if (! isspace(*(buf + 7)))
-			return FALSE;
+		utils_free_pointers(str, pattern, NULL); // free pattern in case it is ""
+		return FALSE;
+	}
 
-		construct = g_strdup_printf("%s{%s%s%s}%shandle%s{%s%s%s}%s",
-										eol, eol, space, eol, eol, eol, eol, space, eol, eol);
+	get_indent(sci, pos, TRUE);
+	lindent = g_strconcat(utils_get_eol_char(idx), indent, NULL);
+	whitespace = get_whitespace(editor_prefs.tab_width, FALSE);
 
-		SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) construct);
-		sci_goto_pos(sci, pos + 3 + space_len + (2 * strlen(indent)), TRUE);
-	}
-	result = (construct != NULL);
-	if (result)
+	// remove the typed word, it will be added again by the used auto completion
+	// (not really necessary but this makes the auto completion more flexible,
+	//  e.g. with a completion like hi=hello, so typing "hi<TAB>" will result in "hello")
+	str_len = strlen(str);
+	sci_set_selection_start(sci, pos - str_len);
+	sci_set_selection_end(sci, pos);
+	sci_replace_sel(sci, "");
+	pos -= str_len; // pos has changed while deleting
+
+	// replace 'special' completions
+	specials = g_hash_table_lookup(editor_prefs.auto_completions, "Special");
+	if (specials != NULL)
 	{
-		sci_insert_text(sci, pos, " ");	// prefix all constructs with a space
+		// ugly hack using global_pattern
+		global_pattern = pattern;
+		g_hash_table_foreach(specials, ac_replace_specials, NULL);
+		pattern = global_pattern;
 	}
-	g_free(construct);
-	return result;
+
+	// replace line breaks and whitespaces
+	pattern = utils_str_replace(pattern, "\n", "%newline%"); // to avoid endless replacing of \n
+	pattern = utils_str_replace(pattern, "%newline%", lindent);
+
+	pattern = utils_str_replace(pattern, "\t", "%ws%"); // to avoid endless replacing of \t
+	pattern = utils_str_replace(pattern, "%ws%", whitespace);
+
+	// find the %cursor% pos (has to be done after all other operations)
+	step = utils_strpos(pattern, "%cursor%");
+	if (step != -1)
+		pattern = utils_str_replace(pattern, "%cursor%", "");
+
+	// finally insert the text and set the cursor
+	SSM(sci, SCI_INSERTTEXT, pos, (sptr_t) pattern);
+	if (step != -1)
+		sci_goto_pos(sci, pos + step, TRUE);
+	else
+		sci_goto_pos(sci, pos + strlen(pattern), TRUE);
+
+	utils_free_pointers(pattern, whitespace, lindent, str, NULL);
+ 	return TRUE;
 }
 
 
@@ -1226,24 +1208,12 @@
 gboolean editor_auto_forif(gint idx, gint pos)
 {
 	gboolean result;
-	gchar buf[16];
-	gchar *eol;
-	gchar *space;
+	gchar *word;
 	gint lexer, style;
 	gint i;
 	ScintillaObject *sci;
 
-	if (idx == -1 || ! doc_list[idx].is_valid || doc_list[idx].file_type == NULL) return FALSE;
-
-	// only for C, C++, D, Ferite, Java, JavaScript, Perl and PHP
-	if (doc_list[idx].file_type->id != GEANY_FILETYPES_PHP &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_C &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_D &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_CPP &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_PERL &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_JAVA &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_JS &&
-		doc_list[idx].file_type->id != GEANY_FILETYPES_FERITE)
+	if (! DOC_IDX_VALID(idx) || doc_list[idx].file_type == NULL)
 		return FALSE;
 
 	sci = doc_list[idx].sci;
@@ -1260,35 +1230,30 @@
 	if (lexer == SCLEX_HTML && ! (style >= SCE_HPHP_DEFAULT && style <= SCE_HPHP_OPERATOR))
 		return FALSE;
 
-	sci_get_text_range(sci, pos - 15, pos, buf);
-	if (sizeof(buf) != strlen(buf) + 1)
-		return FALSE;	// not enough chars in document
+	// get the current line contents
+	word = sci_get_line(sci, SSM(sci, SCI_LINEFROMPOSITION, pos, 0));
 
 	/* check that the chars before the current word are only whitespace (on this line).
 	 * this prevents completion of '} while ' */
-	i = 14;	// index before \0 char
-	while (i >= 0 && isalpha(buf[i])) i--;	// find pos before keyword
-	while (i >= 0 && buf[i] != '\n' && buf[i] != '\r') // we want to stay in this line('\n' check)
+	i = strlen(word) - 1;
+	while (i >= 0 && isspace(word[i])) i--;	// skip trailing whitespace
+	while (i >= 0 && isalpha(word[i])) i--;	// find pos before keyword
+	while (i >= 0 && word[i] != '\n' && word[i] != '\r') // we want to stay in this line('\n' check)
 	{
-		if (! isspace(buf[i]))
-		{
+		if (! isspace(word[i]))
 			return FALSE;
-		}
 		i--;
 	}
 
 	// get the indentation
-	if (doc_list[idx].auto_indent) get_indent(sci, pos, TRUE);
-	eol = g_strconcat(utils_get_eol_char(idx), indent, NULL);
+	if (doc_list[idx].auto_indent)
+		get_indent(sci, pos, TRUE);
 
-	// get the whitespace for additional indentation
-	space = get_whitespace(editor_prefs.tab_width, FALSE);
-
-	sci_start_undo_action(sci);	// needed while we insert a space separately from construct
-	result = complete_constructs(idx, pos, buf, space, eol);
+	sci_start_undo_action(sci);	// needed because we insert a space separately from construct
+	result = ac_complete_constructs(idx, pos, word);
 	sci_end_undo_action(sci);
 
-	utils_free_pointers(eol, space, NULL);
+	utils_free_pointers(word, NULL);
 	return result;
 }
 
@@ -2331,3 +2296,9 @@
 }
 
 
+void editor_finalize()
+{
+	g_hash_table_destroy(editor_prefs.auto_completions);
+
+	scintilla_release_resources();
+}

Modified: trunk/src/editor.h
===================================================================
--- trunk/src/editor.h	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/src/editor.h	2007-06-17 17:56:48 UTC (rev 1628)
@@ -18,6 +18,7 @@
  *      along with this program; if not, write to the Free Software
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * $Id$
  */
 
 #ifndef GEANY_SCI_CB_H
@@ -58,12 +59,14 @@
 	gboolean	unfold_all_children;
 	gboolean	show_scrollbars;
 	gint		tab_width;
+	gint		caret_blink_time;
 	gboolean	use_tabs;
 	gint		default_encoding;
 	gboolean	new_line;
 	gboolean	replace_tabs;
 	gboolean	trail_space;
 	gboolean	disable_dnd;
+	GHashTable	*auto_completions;
 } EditorPrefs;
 
 extern EditorPrefs editor_prefs;
@@ -78,6 +81,15 @@
 extern EditorInfo editor_info;
 
 
+typedef struct
+{
+	gchar *type;	// represents in most cases the filetype(two exceptions: default and special)
+	gchar *name;	// name of the key in config file, represents the entered text to complete
+	gchar *value;
+} AutoCompletion;
+
+
+
 gboolean
 on_editor_button_press_event           (GtkWidget *widget,
                                         GdkEventButton *event,
@@ -125,4 +137,6 @@
 
 void editor_insert_alternative_whitespace(ScintillaObject *sci);
 
+void editor_finalize();
+
 #endif

Modified: trunk/src/keyfile.c
===================================================================
--- trunk/src/keyfile.c	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/src/keyfile.c	2007-06-17 17:56:48 UTC (rev 1628)
@@ -771,3 +771,79 @@
 	g_key_file_free(sysconfig);
 	g_key_file_free(userconfig);
 }
+
+
+void configuration_read_autocompletions()
+{
+	gsize i, j, len = 0, len_keys = 0;
+	gchar *sysconfigfile = g_strconcat(app->datadir, G_DIR_SEPARATOR_S,
+		"autocomplete.conf", NULL);
+	gchar *userconfigfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S,
+		"autocomplete.conf", NULL);
+	gchar **groups_user, **groups_sys;
+	gchar **keys_user, **keys_sys;
+	gchar *value;
+	GKeyFile *sysconfig = g_key_file_new();
+	GKeyFile *userconfig = g_key_file_new();
+	GHashTable *tmp;
+
+	g_key_file_load_from_file(sysconfig, sysconfigfile, G_KEY_FILE_NONE, NULL);
+	g_key_file_load_from_file(userconfig, userconfigfile, G_KEY_FILE_NONE, NULL);
+
+	// keys are strings, values are GHashTables, so use g_free and g_hash_table_destroy
+	editor_prefs.auto_completions =
+		g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_hash_table_destroy);
+
+	// first read all globally defined auto completions
+	groups_sys = g_key_file_get_groups(sysconfig, &len);
+	for (i = 0; i < len; i++)
+	{
+		keys_sys = g_key_file_get_keys(sysconfig, groups_sys[i], &len_keys, NULL);
+		// create new hash table for the read section (=> filetype)
+		tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+		g_hash_table_insert(editor_prefs.auto_completions, g_strdup(groups_sys[i]), tmp);
+
+		for (j = 0; j < len_keys; j++)
+		{
+			g_hash_table_insert(tmp, g_strdup(keys_sys[j]),
+						utils_get_setting_string(sysconfig, groups_sys[i], keys_sys[j], ""));
+		}
+		g_strfreev(keys_sys);
+	}
+
+	// now read defined completions in user's configuration directory and add / replace them
+	groups_user = g_key_file_get_groups(userconfig, &len);
+	for (i = 0; i < len; i++)
+	{
+		keys_user = g_key_file_get_keys(userconfig, groups_user[i], &len_keys, NULL);
+
+		tmp = g_hash_table_lookup(editor_prefs.auto_completions, groups_user[i]);
+		if (tmp == NULL)
+		{	// new key found, create hash table
+			tmp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+			g_hash_table_insert(editor_prefs.auto_completions, g_strdup(groups_user[i]), tmp);
+		}
+		for (j = 0; j < len_keys; j++)
+		{
+			value = g_hash_table_lookup(tmp, keys_user[j]);
+			if (value == NULL)
+			{	// value = NULL means the key doesn't yet exist, so insert
+				g_hash_table_insert(tmp, g_strdup(keys_user[j]),
+						utils_get_setting_string(userconfig, groups_user[i], keys_user[j], ""));
+			}
+			else
+			{	// old key and value will be freed by destroy function (g_free)
+				g_hash_table_replace(tmp, g_strdup(keys_user[j]),
+						utils_get_setting_string(userconfig, groups_user[i], keys_user[j], ""));
+			}
+		}
+		g_strfreev(keys_user);
+	}
+
+	g_free(sysconfigfile);
+	g_free(userconfigfile);
+	g_strfreev(groups_sys);
+	g_strfreev(groups_user);
+	g_key_file_free(sysconfig);
+	g_key_file_free(userconfig);
+}

Modified: trunk/src/keyfile.h
===================================================================
--- trunk/src/keyfile.h	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/src/keyfile.h	2007-06-17 17:56:48 UTC (rev 1628)
@@ -33,6 +33,8 @@
 
 void configuration_read_filetype_extensions();
 
+void configuration_read_autocompletions();
+
 /* set some settings which are already read from the config file, but need other things, like the
  * realisation of the main window */
 void configuration_apply_settings();

Modified: trunk/src/main.c
===================================================================
--- trunk/src/main.c	2007-06-17 16:55:25 UTC (rev 1627)
+++ trunk/src/main.c	2007-06-17 17:56:48 UTC (rev 1628)
@@ -89,12 +89,14 @@
 #endif
 static gboolean generate_datafiles = FALSE;
 static gboolean generate_tags = FALSE;
+static gboolean ft_names = FALSE;
 
 static GOptionEntry entries[] =
 {
 	{ "column", 0, 0, G_OPTION_ARG_INT, &cl_options.goto_column, N_("set initial column number for the first opened file (useful in conjunction with --line)"), NULL },
 	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("use an alternate configuration directory"), NULL },
 	{ "debug", 'd', 0, G_OPTION_ARG_NONE, &debug_mode, N_("runs in debug mode (means being verbose)"), NULL },
+	{ "ft-names", 0, 0, G_OPTION_ARG_NONE, &ft_names, N_("print internal filetype names"), NULL },
 	{ "generate-tags", 'g', 0, G_OPTION_ARG_NONE, &generate_tags, N_("generate global tags file (see documentation)"), NULL },
 	{ "generate-data-files", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &generate_datafiles, "", NULL },
 #ifdef HAVE_SOCKET
@@ -482,7 +484,20 @@
 		exit(ret);
 	}
 
+	if (ft_names)
+	{
+		int i;
 
+		printf("Geany's internal filetype names:\n");
+		filetypes_init_types();
+		for (i = 0; i < GEANY_MAX_FILE_TYPES; i++)
+		{
+			printf("%s\n", filetypes[i]->name);
+		}
+		filetypes_free_types();
+		exit(0);
+	}
+
 #ifdef HAVE_SOCKET
 	socket_info.ignore_socket = ignore_socket;
 #endif
@@ -665,6 +680,7 @@
 	templates_init();
 	document_init_doclist();
 	configuration_read_filetype_extensions();
+	configuration_read_autocompletions();
 
 	// set window icon
 	{
@@ -785,6 +801,7 @@
 	build_finalize();
 	document_finalize();
 	symbols_finalize();
+	editor_finalize();
 	if (app->project != NULL) project_close();
 
 	tm_workspace_free(TM_WORK_OBJECT(app->tm_workspace));
@@ -825,7 +842,6 @@
 		g_object_unref(app->default_tag_tree);
 		gtk_widget_destroy(app->default_tag_tree);
 	}
-	scintilla_release_resources();
 #ifdef HAVE_VTE
 	if (vte_info.have_vte) vte_close();
 	g_free(vte_info.lib_vte);


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list