From d52003fc0fd0befed4f0d688c7b84e7318a09ee6 Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Sun, 17 Aug 2008 17:09:42 -0500 Subject: [PATCH] Synced with upstream --- .../upstream/gtksourcelanguagemanager.c | 208 ++++++++++++++++++ .../upstream/gtksourcelanguagemanager.h | 4 + moo/mooedit/language-specs/c.lang | 2 +- moo/mooedit/language-specs/sh.lang | 100 ++++----- 4 files changed, 264 insertions(+), 50 deletions(-) diff --git a/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.c b/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.c index 6d70d737..dc525e89 100644 --- a/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.c +++ b/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.c @@ -27,6 +27,7 @@ #include "gtksourcelanguage-private.h" #include "gtksourcelanguage.h" #include "gtksourceview-utils.h" +#include #define RNG_SCHEMA_FILE "language2.rng" #define LANGUAGE_DIR "language-specs" @@ -408,3 +409,210 @@ gtk_source_language_manager_get_language (GtkSourceLanguageManager *lm, return g_hash_table_lookup (lm->priv->language_ids, id); } +static GtkSourceLanguage * +pick_lang_for_filename (GtkSourceLanguageManager *lm, + const gchar *filename) +{ + char *filename_utf8; + const gchar* const * p; + + /* Use g_filename_display_name() instead of g_filename_to_utf8() because + * g_filename_display_name() doesn't fail and replaces non-convertible + * characters to unicode substitution symbol. */ + filename_utf8 = g_filename_display_name (filename); + + for (p = gtk_source_language_manager_get_language_ids (lm); + p != NULL && *p != NULL; + p++) + { + GtkSourceLanguage *lang; + gchar **globs, **gptr; + + lang = gtk_source_language_manager_get_language (lm, *p); + globs = gtk_source_language_get_globs (lang); + + for (gptr = globs; gptr != NULL && *gptr != NULL; gptr++) + { + /* FIXME g_pattern_match is wrong: there are no '[...]' + * character ranges and '*' and '?' can not be escaped + * to include them literally in a pattern. */ + if (g_pattern_match_simple (*gptr, filename_utf8)) + { + g_strfreev (globs); + g_free (filename_utf8); + return lang; + } + } + + g_strfreev (globs); + } + + g_free (filename_utf8); + return NULL; +} + +static GtkSourceLanguage * +pick_lang_for_mime_type_pass (GtkSourceLanguageManager *lm, + const char *mime_type, + gboolean exact_match) +{ + const gchar* const * id_ptr; + + for (id_ptr = gtk_source_language_manager_get_language_ids (lm); + id_ptr != NULL && *id_ptr != NULL; + id_ptr++) + { + GtkSourceLanguage *lang; + gchar **mime_types, **mptr; + + lang = gtk_source_language_manager_get_language (lm, *id_ptr); + mime_types = gtk_source_language_get_mime_types (lang); + + for (mptr = mime_types; mptr != NULL && *mptr != NULL; mptr++) + { + gboolean matches; + + if (exact_match) + matches = strcmp (mime_type, *mptr) == 0; + else + matches = g_content_type_is_a (mime_type, *mptr); + + if (matches) + { + g_strfreev (mime_types); + return lang; + } + } + + g_strfreev (mime_types); + } + + return NULL; +} + +static GtkSourceLanguage * +pick_lang_for_mime_type (GtkSourceLanguageManager *lm, + const char *mime_type) +{ + GtkSourceLanguage *lang; + lang = pick_lang_for_mime_type_pass (lm, mime_type, TRUE); + if (!lang) + lang = pick_lang_for_mime_type_pass (lm, mime_type, FALSE); + return lang; +} + +#ifdef G_OS_WIN32 +static void +grok_win32_content_type (const gchar *content_type, + gchar **alt_filename, + gchar **mime_type) +{ + *alt_filename = NULL; + *mime_type = NULL; + + /* If it contains slash, then it's probably a mime type. + * Otherwise treat is an extension. */ + if (strchr (content_type, '/') != NULL) + *mime_type = g_strdup (content_type); + else + *alt_filename = g_strjoin ("filename", content_type, NULL); +} +#endif + +/** + * gtk_source_language_manager_guess_language: + * @lm: a #GtkSourceLanguageManager. + * @filename: a filename in Glib filename encoding, or %NULL. + * @content_type: a content type (as in GIO API), or %NULL. + * + * Picks a #GtkSourceLanguage for given file name and content type, + * according to the information in lang files. Either @filename or + * @content_type may be %NULL. This function can be used as follows: + * + * + * GtkSourceLanguage *lang; + * lang = gtk_source_language_manager_guess_language (filename, NULL); + * gtk_source_buffer_set_language (buffer, lang); + * + * + * or + * + * + * GtkSourceLanguage *lang = NULL; + * gboolean result_uncertain; + * gchar *content_type; + * + * content_type = g_content_type_guess (filename, NULL, 0, &result_uncertain); + * if (result_uncertain) + * { + * g_free (content_type); + * content_type = NULL; + * } + * + * lang = gtk_source_language_manager_guess_language (manager, filename, content_type); + * gtk_source_buffer_set_language (buffer, lang); + * + * g_free (content_type); + * + * + * etc. Use gtk_source_language_get_mime_types() and gtk_source_language_get_globs() + * if you need full control over file -> language mapping. + * + * Returns: a #GtkSourceLanguage, or %NULL if there is no suitable language + * for given @filename and/or @content_type. Return value is owned by @lm + * and should not be freed. + * + * Since: 2.4 + */ +GtkSourceLanguage * +gtk_source_language_manager_guess_language (GtkSourceLanguageManager *lm, + const gchar *filename, + const gchar *content_type) +{ + GtkSourceLanguage *lang = NULL; + + g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE_MANAGER (lm), NULL); + g_return_val_if_fail (filename != NULL || content_type != NULL, NULL); + g_return_val_if_fail ((filename == NULL || *filename != 0) && + (content_type == NULL || *content_type != 0), NULL); + + ensure_languages (lm); + + /* TODO + > Maybe the logic should be: + > - match mime + > - match glob + > - if just one matches use it + > - if they both match and the corresponding mime inside the lang files are one + > the anchestor of the other pick the more strict lang + > - if they both match and the corresponding mime inside the lang files are + > unrelated, pick the glob one + */ + + if (filename != NULL) + lang = pick_lang_for_filename (lm, filename); + + if (lang == NULL && content_type != NULL) + { +#ifndef G_OS_WIN32 + /* On Unix "content type" is mime type */ + lang = pick_lang_for_mime_type (lm, content_type); +#else + /* On Windows "content type" is an extension, but user may pass a mime type too */ + gchar *mime_type; + gchar *alt_filename; + + grok_win32_content_type (content_type, &alt_filename, &mime_type); + + if (alt_filename != NULL) + lang = pick_lang_for_filename (lm, alt_filename); + if (lang == NULL && mime_type != NULL) + lang = pick_lang_for_mime_type (lm, mime_type); + + g_free (mime_type); + g_free (alt_filename); +#endif + } + + return lang; +} diff --git a/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.h b/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.h index 5a2d5ddc..ccff631b 100644 --- a/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.h +++ b/moo/mooedit/gtksourceview/upstream/gtksourcelanguagemanager.h @@ -74,6 +74,10 @@ G_CONST_RETURN gchar* G_CONST_RETURN * GtkSourceLanguage *gtk_source_language_manager_get_language (GtkSourceLanguageManager *lm, const gchar *id); +GtkSourceLanguage *gtk_source_language_manager_guess_language (GtkSourceLanguageManager *lm, + const gchar *filename, + const gchar *content_type); + G_END_DECLS diff --git a/moo/mooedit/language-specs/c.lang b/moo/mooedit/language-specs/c.lang index f04afb2f..8b78b4e2 100644 --- a/moo/mooedit/language-specs/c.lang +++ b/moo/mooedit/language-specs/c.lang @@ -41,7 +41,7 @@