@@ -21,8 +21,64 @@ using ThiefMD;
21
21
using ThiefMD.Widgets ;
22
22
23
23
namespace ThiefMD.Enrichments {
24
+ public class FountainCharacterSuggestor : Gtk .SourceCompletionProvider , GLib .Object {
25
+ public Gee . HashSet<string> characters;
26
+
27
+ public class FountainCharacterSuggestor () {
28
+ characters = new Gee .HashSet<string> ();
29
+ }
30
+
31
+ public override string get_name () {
32
+ return _(" Characters" );
33
+ }
34
+
35
+ public override bool match (Gtk .SourceCompletionContext context ) {
36
+ Gtk . TextIter ? start = null , iter = null ;
37
+ if (context. get_iter (out iter)) {
38
+ if (iter. ends_line () && context. get_iter (out start)) {
39
+ start. backward_word_start ();
40
+ if ((iter. get_offset () - start. get_offset ()) >= 2 ) {
41
+ string check = start. get_text (iter);
42
+ return check == check. up ();
43
+ }
44
+ }
45
+ }
46
+
47
+ return false ;
48
+ }
49
+
50
+ public override void populate (Gtk .SourceCompletionContext context ) {
51
+ List<Gtk . SourceCompletionItem > completions = new List<Gtk . SourceCompletionItem > ();
52
+ Gtk . TextIter ? start = null , iter = null ;
53
+ if (context. get_iter (out iter)) {
54
+ if (iter. ends_line () && context. get_iter (out start)) {
55
+ start. backward_word_start ();
56
+ if ((iter. get_offset () - start. get_offset ()) >= 2 ) {
57
+ string check = start. get_text (iter);
58
+ foreach (var character in characters) {
59
+ if (character. has_prefix (check) && character != check) {
60
+ var com_item = new Gtk .SourceCompletionItem ();
61
+ com_item. text = character;
62
+ com_item. label = character;
63
+ com_item. markup = character;
64
+ completions. append (com_item);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ context. add_proposals (this , completions, true );
71
+ }
72
+
73
+ public override bool activate_proposal (Gtk .SourceCompletionProposal proposal , Gtk .TextIter iter ) {
74
+ return false ;
75
+ }
76
+ }
77
+
24
78
public class FountainEnrichment {
25
- private Gtk . TextView view;
79
+ private FountainCharacterSuggestor character_suggester;
80
+ private Gtk . SourceCompletionWords source_completion;
81
+ private Gtk . SourceView view;
26
82
private Gtk . TextBuffer buffer;
27
83
private Mutex checking;
28
84
@@ -49,9 +105,11 @@ namespace ThiefMD.Enrichments {
49
105
} catch (Error e) {
50
106
warning (" Could not build regexes: %s " , e. message);
51
107
}
108
+ character_suggester = new FountainCharacterSuggestor ();
52
109
checking = Mutex ();
53
110
limit_updates = new TimedMutex (250 );
54
111
last_cursor = - 1 ;
112
+ source_completion = null ;
55
113
}
56
114
57
115
public void reset () {
@@ -139,6 +197,9 @@ namespace ThiefMD.Enrichments {
139
197
}
140
198
141
199
private void tag_char_diag_helper (Regex regex ) {
200
+ Gtk . TextIter cursor_iter;
201
+ var cursor = buffer. get_insert ();
202
+ buffer. get_iter_at_mark (out cursor_iter, cursor);
142
203
try {
143
204
MatchInfo match_info;
144
205
if (regex. match_full (checking_copy, checking_copy. length, 0 , 0 , out match_info)) {
@@ -175,6 +236,22 @@ namespace ThiefMD.Enrichments {
175
236
buffer. apply_tag (tag_parenthetical, start, end);
176
237
} else {
177
238
buffer. apply_tag (tag_character, start, end);
239
+ start. backward_word_start ();
240
+ end. forward_word_end ();
241
+ if (! character_suggester. characters. contains (character) && ! cursor_iter. in_range (start, end)) {
242
+ bool partial_character_name = false ;
243
+ if (character. has_suffix (" ^" )) {
244
+ character = character. substring (0 , character. length - 1 );
245
+ }
246
+ foreach (var person in character_suggester. characters) {
247
+ if (person. contains (character)) {
248
+ partial_character_name = true ;
249
+ }
250
+ }
251
+ if (! partial_character_name) {
252
+ character_suggester. characters. add (character);
253
+ }
254
+ }
178
255
}
179
256
}
180
257
@@ -226,7 +303,7 @@ namespace ThiefMD.Enrichments {
226
303
} while (match_info. next ());
227
304
}
228
305
229
- public bool attach (Gtk .TextView textview ) {
306
+ public bool attach (Gtk .SourceView textview ) {
230
307
if (textview == null ) {
231
308
return false ;
232
309
}
@@ -265,10 +342,26 @@ namespace ThiefMD.Enrichments {
265
342
last_cursor = - 1 ;
266
343
267
344
calculate_margins ();
345
+ settings_changed ();
346
+ settings. changed. connect (settings_changed);
268
347
269
348
return true ;
270
349
}
271
350
351
+ private void settings_changed () {
352
+ var settings = AppSettings . get_default ();
353
+ if (settings. experimental && source_completion == null ) {
354
+ var completion = view. get_completion ();
355
+ completion. add_provider (character_suggester);
356
+ source_completion = new Gtk .SourceCompletionWords (" Character Suggestor" , null );
357
+ source_completion. register (buffer);
358
+ } else if (! settings. experimental && source_completion != null ) {
359
+ var completion = view. get_completion ();
360
+ source_completion. unregister (buffer);
361
+ completion. remove_provider (character_suggester);
362
+ }
363
+ }
364
+
272
365
private void calculate_margins () {
273
366
var settings = AppSettings . get_default ();
274
367
int f_w = (int )(settings. get_css_font_size () * ((settings. fullscreen ? 1.4 : 1 )));
@@ -321,6 +414,7 @@ namespace ThiefMD.Enrichments {
321
414
}
322
415
323
416
public void detach () {
417
+ var settings = AppSettings . get_default ();
324
418
Gtk . TextIter start, end;
325
419
buffer. get_bounds (out start, out end);
326
420
@@ -332,7 +426,17 @@ namespace ThiefMD.Enrichments {
332
426
buffer. tag_table. remove (tag_character);
333
427
buffer. tag_table. remove (tag_parenthetical);
334
428
buffer. tag_table. remove (tag_dialogue);
429
+
430
+ if (source_completion != null ) {
431
+ source_completion. unregister (buffer);
432
+ }
433
+
434
+ settings. changed. disconnect (settings_changed);
435
+
335
436
tag_scene_heading = null ;
437
+ tag_character = null ;
438
+ tag_parenthetical = null ;
439
+ tag_dialogue = null ;
336
440
337
441
view = null ;
338
442
buffer = null ;
0 commit comments