~codygarver/+junk/gnome-builder

« back to all changes in this revision

Viewing changes to plugins/c-pack/ide-c-format-provider.c

  • Committer: Cody Garver
  • Date: 2015-11-21 00:50:38 UTC
  • Revision ID: cody@elementary.io-20151121005038-8wygis63zt0ljqlz
Import https://github.com/chergert/gnome-builder 06e3158922a02a27f4abca250d70aa7b2970e06a

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ide-c-format-provider.c
 
2
 *
 
3
 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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/>.
 
17
 */
 
18
 
 
19
#include <glib/gi18n.h>
 
20
#include <gtksourceview/gtksource.h>
 
21
 
 
22
#include "ide-c-format-provider.h"
 
23
 
 
24
struct _IdeCFormatProvider
 
25
{
 
26
  IdeObject parent_instance;
 
27
};
 
28
 
 
29
enum {
 
30
  TYPE_NONE,
 
31
  TYPE_PRINTF,
 
32
  TYPE_SCANF,
 
33
  TYPE_STRFTIME,
 
34
  TYPE_STRPTIME,
 
35
  TYPE_G_DATE_TIME_FORMAT,
 
36
};
 
37
 
 
38
typedef struct
 
39
{
 
40
  const gchar *format;
 
41
  const gchar *description;
 
42
} FormatItem;
 
43
 
 
44
static void completion_provider_iface_init (GtkSourceCompletionProviderIface *);
 
45
 
 
46
G_DEFINE_DYNAMIC_TYPE_EXTENDED (IdeCFormatProvider,
 
47
                                ide_c_format_provider,
 
48
                                IDE_TYPE_OBJECT,
 
49
                                0,
 
50
                                G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_COMPLETION_PROVIDER,
 
51
                                                       completion_provider_iface_init)
 
52
                                G_IMPLEMENT_INTERFACE (IDE_TYPE_COMPLETION_PROVIDER, NULL))
 
53
 
 
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" },
 
95
  { NULL }
 
96
};
 
97
 
 
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) { }
 
101
 
 
102
static int
 
103
guess_type (const GtkTextIter *location)
 
104
{
 
105
  GtkTextIter iter = *location;
 
106
  g_autofree gchar *text = NULL;
 
107
 
 
108
  /* walk back to opening ( */
 
109
  if (!gtk_text_iter_backward_search (&iter, "(", GTK_TEXT_SEARCH_TEXT_ONLY, &iter, NULL, NULL))
 
110
    return TYPE_NONE;
 
111
 
 
112
  /* swallow ( */
 
113
  if (!gtk_text_iter_backward_char (&iter))
 
114
    return TYPE_NONE;
 
115
 
 
116
  /* try to find the word previous */
 
117
  while (g_unichar_isspace (gtk_text_iter_get_char (&iter)))
 
118
    {
 
119
      if (!gtk_text_iter_backward_char (&iter))
 
120
        return TYPE_NONE;
 
121
    }
 
122
 
 
123
  /* walk backward to space */
 
124
  while (!g_unichar_isspace (gtk_text_iter_get_char (&iter)))
 
125
    {
 
126
      if (!gtk_text_iter_backward_char (&iter))
 
127
        break;
 
128
    }
 
129
 
 
130
  text = gtk_text_iter_get_slice (&iter, location);
 
131
 
 
132
  if (strstr (text, "printf") || strstr (text, "g_print"))
 
133
    return TYPE_PRINTF;
 
134
  else if (strstr (text, "scanf"))
 
135
    return TYPE_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;
 
142
  else
 
143
    return TYPE_NONE;
 
144
}
 
145
 
 
146
static GList *
 
147
create_matches_strftime (const gchar *text)
 
148
{
 
149
  return NULL;
 
150
}
 
151
 
 
152
static GList *
 
153
create_matches_strptime (const gchar *text)
 
154
{
 
155
  return NULL;
 
156
}
 
157
 
 
158
static GList *
 
159
create_matches_g_date_time_format (const gchar *text)
 
160
{
 
161
  GList *list = NULL;
 
162
  gsize i;
 
163
 
 
164
  g_print (">>>> %s\n", text);
 
165
 
 
166
  text = strstr (text, "%");
 
167
 
 
168
  if (text)
 
169
    {
 
170
      for (i = 0; gGDateTimeFormats [i].format; i++)
 
171
        {
 
172
          if (g_str_has_prefix (gGDateTimeFormats [i].format, text))
 
173
            {
 
174
              g_autofree gchar *markup = NULL;
 
175
              const gchar *insert;
 
176
 
 
177
              insert = gGDateTimeFormats [i].format + strlen (text);
 
178
 
 
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,
 
184
                                                   "markup", markup,
 
185
                                                   "text", insert,
 
186
                                                   NULL));
 
187
            }
 
188
        }
 
189
    }
 
190
 
 
191
  return g_list_reverse (list);
 
192
}
 
193
 
 
194
static GList *
 
195
create_matches_printf (const gchar *text)
 
196
{
 
197
  return NULL;
 
198
}
 
199
 
 
200
static GList *
 
201
create_matches_scanf (const gchar *text)
 
202
{
 
203
  return NULL;
 
204
}
 
205
 
 
206
static GList *
 
207
create_matches (int type,
 
208
                const gchar *text)
 
209
{
 
210
  switch (type)
 
211
    {
 
212
    case TYPE_STRFTIME:
 
213
      return create_matches_strftime (text);
 
214
 
 
215
    case TYPE_STRPTIME:
 
216
      return create_matches_strptime (text);
 
217
 
 
218
    case TYPE_G_DATE_TIME_FORMAT:
 
219
      return create_matches_g_date_time_format (text);
 
220
 
 
221
    case TYPE_PRINTF:
 
222
      return create_matches_printf (text);
 
223
 
 
224
    case TYPE_SCANF:
 
225
      return create_matches_scanf (text);
 
226
 
 
227
    case TYPE_NONE:
 
228
    default:
 
229
      return NULL;
 
230
    }
 
231
}
 
232
 
 
233
static void
 
234
ide_c_format_provider_populate (GtkSourceCompletionProvider *provider,
 
235
                                GtkSourceCompletionContext  *context)
 
236
{
 
237
  GtkSourceBuffer *buffer;
 
238
  GtkTextIter iter;
 
239
  GList *list = NULL;
 
240
  int type;
 
241
 
 
242
  if (!gtk_source_completion_context_get_iter (context, &iter))
 
243
    goto failure;
 
244
 
 
245
  buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (&iter));
 
246
  g_assert (buffer != NULL);
 
247
 
 
248
  if (gtk_source_buffer_iter_has_context_class (buffer, &iter, "string"))
 
249
    {
 
250
      GtkTextIter line_start = iter;
 
251
      GtkTextIter begin;
 
252
      GtkTextIter end;
 
253
 
 
254
      gtk_text_iter_set_line_offset (&line_start, 0);
 
255
 
 
256
      if (gtk_text_iter_backward_search (&iter, "%", GTK_TEXT_SEARCH_TEXT_ONLY,
 
257
                                         &begin, &end, &line_start))
 
258
        {
 
259
          g_autofree gchar *text = NULL;
 
260
 
 
261
          if (!gtk_source_buffer_iter_has_context_class (buffer, &begin, "string"))
 
262
            goto failure;
 
263
 
 
264
          type = guess_type (&begin);
 
265
          if (type == TYPE_NONE)
 
266
            goto failure;
 
267
 
 
268
          text = gtk_text_iter_get_slice (&begin, &iter);
 
269
          list = create_matches (type, text);
 
270
        }
 
271
    }
 
272
 
 
273
failure:
 
274
  gtk_source_completion_context_add_proposals (context, provider, list, TRUE);
 
275
  g_list_free_full (list, g_object_unref);
 
276
}
 
277
 
 
278
static gchar *
 
279
ide_c_format_provider_get_name (GtkSourceCompletionProvider *provider)
 
280
{
 
281
  return g_strdup (_("Format Strings"));
 
282
}
 
283
 
 
284
static void
 
285
completion_provider_iface_init (GtkSourceCompletionProviderIface *iface)
 
286
{
 
287
  iface->populate = ide_c_format_provider_populate;
 
288
  iface->get_name = ide_c_format_provider_get_name;
 
289
}
 
290
 
 
291
void
 
292
_ide_c_format_provider_register_type (GTypeModule *module)
 
293
{
 
294
  ide_c_format_provider_register_type (module);
 
295
}