1
/* ide-c-format-provider.c
3
* Copyright (C) 2015 Christian Hergert <christian@hergert.me>
5
* This program is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#include <glib/gi18n.h>
20
#include <gtksourceview/gtksource.h>
22
#include "ide-c-format-provider.h"
24
struct _IdeCFormatProvider
26
IdeObject parent_instance;
35
TYPE_G_DATE_TIME_FORMAT,
41
const gchar *description;
44
static void completion_provider_iface_init (GtkSourceCompletionProviderIface *);
46
G_DEFINE_DYNAMIC_TYPE_EXTENDED (IdeCFormatProvider,
47
ide_c_format_provider,
50
G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
51
completion_provider_iface_init)
52
G_IMPLEMENT_INTERFACE (IDE_TYPE_COMPLETION_PROVIDER, NULL))
54
static const FormatItem gGDateTimeFormats[] = {
55
{ "%a", "the abbreviated weekday name according to the current locale" },
56
{ "%A", "the full weekday name according to the current locale" },
57
{ "%b", "the abbreviated month name according to the current locale" },
58
{ "%B", "the full month name according to the current locale" },
59
{ "%c", "the preferred date and time rpresentation for the current locale" },
60
{ "%C", "the century number (year/100) as a 2-digit integer (00-99)" },
61
{ "%d", "the day of the month as a decimal number (range 01 to 31)" },
62
{ "%e", "the day of the month as a decimal number (range 1 to 31)" },
63
{ "%F", "equivalent to %Y-%m-%d (the ISO 8601 date format)" },
64
{ "%g", "the last two digits of the ISO 8601 week-based year as a decimal number (00-99). This works well with %V and %u." },
65
{ "%G", "the ISO 8601 week-based year as a decimal number. This works well with %V and %u." },
66
{ "%h", "equivalent to %b" },
67
{ "%H", "the hour as a decimal number using a 24-hour clock (range 00 to 23)" },
68
{ "%I", "the hour as a decimal number using a 12-hour clock (range 01 to 12)" },
69
{ "%j", "the day of the year as a decimal number (range 001 to 366)" },
70
{ "%k", "the hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank" },
71
{ "%l", "the hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank" },
72
{ "%m", "the month as a decimal number (range 01 to 12)" },
73
{ "%M", "the minute as a decimal number (range 00 to 59)" },
74
{ "%p", "either \"AM\" or \"PM\" according to the given time value, or the corresponding strings for the current locale. Noon is treated as \"PM\" and midnight as \"AM\"." },
75
{ "%P", "like %p but lowercase, \"am\" or \"pm\" or a corresponding string for the current locale" },
76
{ "%r", "the time in a.m. or p.m. notation" },
77
{ "%R", "the time in 24-hour notation (%H:%M)" },
78
{ "%s", "the number of seconds since the Epoch, that is, since 1970-01-01 00:00:00 UTC" },
79
{ "%S", "the second as a decimal number (range 00 to 60)" },
80
{ "%t", "a tab character" },
81
{ "%T", "the time in 24-hour notation with seconds (%H:%M:%S)" },
82
{ "%u", "the ISO 8601 standard day of the week as a decimal, range 1 to 7, Monday being 1. This works well with %G and %V." },
83
{ "%V", "the ISO 8601 standard week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See g_date_time_get_week_of_year(). This works well with %G and %u." },
84
{ "%w", "the day of the week as a decimal, range 0 to 6, Sunday being 0. This is not the ISO 8601 standard format -- use %u instead." },
85
{ "%x", "the preferred date representation for the current locale without the time" },
86
{ "%X", "the preferred time representation for the current locale without the date" },
87
{ "%y", "the year as a decimal number without the century" },
88
{ "%Y", "the year as a decimal number including the century" },
89
{ "%z", "the time zone as an offset from UTC (+hhmm)" },
90
{ "%:z", "the time zone as an offset from UTC (+hh:mm). This is a gnulib strftime() extension. Since: 2.38" },
91
{ "%::z", ": the time zone as an offset from UTC (+hh:mm:ss). This is a gnulib strftime() extension. Since: 2.38" },
92
{ "%:::z", ": the time zone as an offset from UTC, with : to necessary precision (e.g., -04, +05:30). This is a gnulib strftime() extension. Since: 2.38" },
93
{ "%Z", ": the time zone or name or abbreviation" },
94
{ "%%", ": a literal % character" },
98
static void ide_c_format_provider_class_init (IdeCFormatProviderClass *klass) { }
99
static void ide_c_format_provider_class_finalize (IdeCFormatProviderClass *klass) { }
100
static void ide_c_format_provider_init (IdeCFormatProvider *self) { }
103
guess_type (const GtkTextIter *location)
105
GtkTextIter iter = *location;
106
g_autofree gchar *text = NULL;
108
/* walk back to opening ( */
109
if (!gtk_text_iter_backward_search (&iter, "(", GTK_TEXT_SEARCH_TEXT_ONLY, &iter, NULL, NULL))
113
if (!gtk_text_iter_backward_char (&iter))
116
/* try to find the word previous */
117
while (g_unichar_isspace (gtk_text_iter_get_char (&iter)))
119
if (!gtk_text_iter_backward_char (&iter))
123
/* walk backward to space */
124
while (!g_unichar_isspace (gtk_text_iter_get_char (&iter)))
126
if (!gtk_text_iter_backward_char (&iter))
130
text = gtk_text_iter_get_slice (&iter, location);
132
if (strstr (text, "printf") || strstr (text, "g_print"))
134
else if (strstr (text, "scanf"))
136
else if (strstr (text, "g_date_time_format"))
137
return TYPE_G_DATE_TIME_FORMAT;
138
else if (strstr (text, "strftime"))
139
return TYPE_STRFTIME;
140
else if (strstr (text, "strptime"))
141
return TYPE_STRFTIME;
147
create_matches_strftime (const gchar *text)
153
create_matches_strptime (const gchar *text)
159
create_matches_g_date_time_format (const gchar *text)
164
g_print (">>>> %s\n", text);
166
text = strstr (text, "%");
170
for (i = 0; gGDateTimeFormats [i].format; i++)
172
if (g_str_has_prefix (gGDateTimeFormats [i].format, text))
174
g_autofree gchar *markup = NULL;
177
insert = gGDateTimeFormats [i].format + strlen (text);
179
markup = g_strdup_printf ("%s - %s",
180
gGDateTimeFormats [i].format,
181
gGDateTimeFormats [i].description);
182
list = g_list_prepend (list,
183
g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
191
return g_list_reverse (list);
195
create_matches_printf (const gchar *text)
201
create_matches_scanf (const gchar *text)
207
create_matches (int type,
213
return create_matches_strftime (text);
216
return create_matches_strptime (text);
218
case TYPE_G_DATE_TIME_FORMAT:
219
return create_matches_g_date_time_format (text);
222
return create_matches_printf (text);
225
return create_matches_scanf (text);
234
ide_c_format_provider_populate (GtkSourceCompletionProvider *provider,
235
GtkSourceCompletionContext *context)
237
GtkSourceBuffer *buffer;
242
if (!gtk_source_completion_context_get_iter (context, &iter))
245
buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (&iter));
246
g_assert (buffer != NULL);
248
if (gtk_source_buffer_iter_has_context_class (buffer, &iter, "string"))
250
GtkTextIter line_start = iter;
254
gtk_text_iter_set_line_offset (&line_start, 0);
256
if (gtk_text_iter_backward_search (&iter, "%", GTK_TEXT_SEARCH_TEXT_ONLY,
257
&begin, &end, &line_start))
259
g_autofree gchar *text = NULL;
261
if (!gtk_source_buffer_iter_has_context_class (buffer, &begin, "string"))
264
type = guess_type (&begin);
265
if (type == TYPE_NONE)
268
text = gtk_text_iter_get_slice (&begin, &iter);
269
list = create_matches (type, text);
274
gtk_source_completion_context_add_proposals (context, provider, list, TRUE);
275
g_list_free_full (list, g_object_unref);
279
ide_c_format_provider_get_name (GtkSourceCompletionProvider *provider)
281
return g_strdup (_("Format Strings"));
285
completion_provider_iface_init (GtkSourceCompletionProviderIface *iface)
287
iface->populate = ide_c_format_provider_populate;
288
iface->get_name = ide_c_format_provider_get_name;
292
_ide_c_format_provider_register_type (GTypeModule *module)
294
ide_c_format_provider_register_type (module);