~ubuntu-branches/ubuntu/wily/gedit-valencia-plugin/wily

« back to all changes in this revision

Viewing changes to .pc/01-fix_vala_dependencies.patch/autocomplete.vala

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2011-03-05 10:12:45 UTC
  • mfrom: (2.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110305101245-xf8a4akrwdiemflp
Tags: 0.3.0-2
* Package moved to section devel
* Port to vala-0.10 (01-fix_vala_dependencies.patch)
* Bump dependencies to use vala-0.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2009-2010 Yorba Foundation
 
2
 *
 
3
 * This software is licensed under the GNU Lesser General Public License
 
4
 * (version 2.1 or later).  See the COPYING file in this distribution. 
 
5
 */
 
6
 
 
7
using Gee;
 
8
using Valencia;
 
9
 
 
10
class AutocompleteDialog : Object {
 
11
    weak Gedit.Window parent;
 
12
    Gtk.Window window;
 
13
    ListViewString list;
 
14
    bool visible;
 
15
    string partial_name;
 
16
    bool inserting_text;
 
17
 
 
18
    public AutocompleteDialog(Gedit.Window parent_win) {
 
19
        parent = parent_win;
 
20
        visible = false;
 
21
        inserting_text = false;
 
22
        list = new ListViewString(Gtk.TreeViewColumnSizing.AUTOSIZE, 100);
 
23
        list.row_activated += select_item;
 
24
 
 
25
        window = new Gtk.Window(Gtk.WindowType.POPUP); 
 
26
        window.add(list.scrolled_window);
 
27
        window.set_destroy_with_parent(true);
 
28
        window.set_default_size(200, 1); 
 
29
        window.set_resizable(true);
 
30
        window.set_title("");
 
31
        window.set_border_width(1);
 
32
      
 
33
        window.show_all();
 
34
        window.hide();
 
35
 
 
36
        Signal.connect(window, "expose-event", (Callback) draw_callback, this);
 
37
    }
 
38
 
 
39
    static bool draw_callback(Gtk.Window window, Gdk.EventExpose event, AutocompleteDialog dialog) {
 
40
        Gtk.paint_flat_box(dialog.window.style, dialog.window.window, 
 
41
                           Gtk.StateType.NORMAL, Gtk.ShadowType.OUT, 
 
42
                           null, dialog.window, "tooltip",
 
43
                           dialog.window.allocation.x, dialog.window.allocation.y,
 
44
                           dialog.window.allocation.width, dialog.window.allocation.height);
 
45
 
 
46
        dialog.list.scrolled_window.expose_event(event);
 
47
 
 
48
        return true;
 
49
    }
 
50
 
 
51
    unowned string? get_completion_target(Gtk.TextBuffer buffer) {
 
52
        Gtk.TextIter start = get_insert_iter(buffer);
 
53
        Gtk.TextIter end = start;
 
54
        
 
55
        while (true) {
 
56
            start.backward_char();
 
57
            unichar c = start.get_char();
 
58
            if (!c.isalnum() && c != '.' && c != '_')
 
59
                break;
 
60
        }
 
61
        // Only include characters in the ID name
 
62
        start.forward_char();
 
63
        
 
64
        if (start.get_offset() == end.get_offset())
 
65
            return null;
 
66
        
 
67
        return start.get_slice(end);
 
68
    }
 
69
    
 
70
    string strip_completed_classnames(string list_name, string completion_target) {
 
71
        string[] classnames = completion_target.split(".");
 
72
        int names = classnames.length;
 
73
        // If the last classname is not explicitly part of the class qualification, then it 
 
74
        // should not be removed from the completion suggestion's name
 
75
        if (!completion_target.has_suffix("."))
 
76
            --names;
 
77
            
 
78
        for (int i = 0; i < names; ++i) {
 
79
            weak string name = classnames[i];
 
80
 
 
81
            // If the name doesn't contain the current classname, it may be a namespace name that
 
82
            // isn't part of the list_name string - we shouldn't stop the comparison early
 
83
            if (list_name.contains(name)) {
 
84
                // Add one to the offset of a string to account for the "."
 
85
                long offset = name.length;
 
86
                if (offset > 0)
 
87
                    ++offset;
 
88
                list_name = list_name.offset(offset);
 
89
            }
 
90
        }
 
91
 
 
92
        return list_name;
 
93
    }
 
94
 
 
95
    string parse_single_symbol(Symbol symbol, string? completion_target, bool constructor) {
 
96
        string list_name = "";
 
97
        
 
98
        if (constructor) {
 
99
            // Get the fully-qualified constructor name
 
100
            Constructor c = symbol as Constructor;
 
101
            assert(c != null);
 
102
 
 
103
            list_name = c.parent.to_string();
 
104
            
 
105
            if (c.name != null)
 
106
                list_name += "." + c.name;
 
107
            list_name += "()";
 
108
 
 
109
            // If the user hasn't typed anything or if either the completion string or this 
 
110
            // constructor is not qualified, keep the original name
 
111
            if (completion_target != null && completion_target.contains(".") 
 
112
                && list_name.contains("."))
 
113
                list_name = strip_completed_classnames(list_name, completion_target);
 
114
            
 
115
        } else {
 
116
            list_name = symbol.name;
 
117
            if (symbol is Method && !(symbol is VSignal) && !(symbol is Delegate))
 
118
                list_name = symbol.name + "()";
 
119
        }
 
120
        
 
121
        return list_name;
 
122
    }
 
123
 
 
124
    string[]? parse_symbol_names(HashSet<Symbol>? symbols) {
 
125
        if (symbols == null)
 
126
            return null;
 
127
            
 
128
        string[] list = new string[symbols.size];
 
129
 
 
130
        // If the first element is a constructor, all elements will be constructors
 
131
        Iterator<Symbol> iter = symbols.iterator();
 
132
        iter.next();
 
133
        bool constructor = iter.get() is Constructor;
 
134
 
 
135
        // match the extent of what the user has already typed with named constructors
 
136
        string? completion_target = null;
 
137
        if (constructor) {          
 
138
            completion_target = get_completion_target(parent.get_active_document());
 
139
        }
 
140
 
 
141
        int i = 0;
 
142
        foreach (Symbol symbol in symbols) {
 
143
            list[i] = parse_single_symbol(symbol, completion_target, constructor);
 
144
            ++i;
 
145
        }
 
146
            
 
147
        qsort(list, symbols.size, sizeof(string), (GLib.CompareFunc) compare_string);
 
148
        return list;
 
149
    }
 
150
 
 
151
    public void show(SymbolSet symbol_set) {
 
152
        if (inserting_text)
 
153
            return;
 
154
 
 
155
        list.clear();
 
156
        visible = true;
 
157
        partial_name = symbol_set.get_name();
 
158
 
 
159
       weak HashSet<Symbol>? symbols = symbol_set.get_symbols();
 
160
       string[]? symbol_strings = parse_symbol_names(symbols);
 
161
 
 
162
        if (symbol_strings != null) {
 
163
            foreach (string s in symbol_strings) {
 
164
                list.append(s);
 
165
            }
 
166
        } else {
 
167
            hide();
 
168
            return;
 
169
        }
 
170
 
 
171
        // TODO: this must be updated to account for font size changes when adding ticket #560        
 
172
        int size = list.size();
 
173
        if (size > 6) {
 
174
            list.set_vscrollbar_policy(Gtk.PolicyType.AUTOMATIC);
 
175
            window.resize(200, 140);
 
176
        } else {
 
177
            list.set_vscrollbar_policy(Gtk.PolicyType.NEVER);
 
178
            window.resize(200, size * 23);
 
179
        }
 
180
 
 
181
        Gedit.Document document = parent.get_active_document(); 
 
182
        Gtk.TextMark insert_mark = document.get_insert();
 
183
        Gtk.TextIter insert_iter;
 
184
        document.get_iter_at_mark(out insert_iter, insert_mark); 
 
185
        int x, y;
 
186
        get_coords_at_buffer_offset(parent, insert_iter.get_offset(), false, true, out x, out y);
 
187
 
 
188
        window.move(x, y);
 
189
        window.show_all(); 
 
190
        window.queue_draw();
 
191
        select_first_cell();
 
192
    }
 
193
    
 
194
    public void hide() {
 
195
        if (!visible)
 
196
            return;
 
197
        
 
198
        visible = false;
 
199
        window.hide();
 
200
    }
 
201
 
 
202
    public bool is_visible() {
 
203
        return visible;
 
204
    }
 
205
 
 
206
    public void select_first_cell() {
 
207
        list.select_first_cell();
 
208
    }
 
209
 
 
210
    public void select_last_cell() {
 
211
        list.select_last_cell();
 
212
    }
 
213
 
 
214
    public void select_previous() {
 
215
        list.select_previous();
 
216
    }
 
217
 
 
218
    public void select_next() {
 
219
        list.select_next();
 
220
    }
 
221
 
 
222
    public void page_up() {
 
223
        list.page_up();
 
224
    }
 
225
 
 
226
    public void page_down() {
 
227
        list.page_down();
 
228
    }
 
229
 
 
230
    public void select_item() {
 
231
        string selection = list.get_selected_item();
 
232
        Gedit.Document buffer = parent.get_active_document();
 
233
 
 
234
        // delete the whole string to be autocompleted and replace it (the case may not match)
 
235
        Gtk.TextIter start = get_insert_iter(buffer);
 
236
        while (true) {
 
237
            if (!start.backward_char())
 
238
                break;
 
239
            unichar c = start.get_char();
 
240
            if (!c.isalnum() && c != '_')
 
241
                break;
 
242
        }
 
243
        // don't include the nonalphanumeric character
 
244
        start.forward_char();
 
245
 
 
246
        Gtk.TextIter end = start;
 
247
        while (true) {
 
248
            unichar c = end.get_char();
 
249
            if (c == '(') {
 
250
                end.forward_char();
 
251
                break;
 
252
            }
 
253
            if (!c.isalnum() && c != '_' && c != '.')
 
254
                break;
 
255
            if (!end.forward_char())
 
256
                break;
 
257
        }
 
258
 
 
259
        // Text insertion/deletion signals have been linked to updating the autocomplete dialog -
 
260
        // we don't want to do that if we're already inserting text.
 
261
        inserting_text = true;
 
262
        buffer.delete(start, end);
 
263
 
 
264
        long offset = selection.has_suffix(")") ? 1 : 0;
 
265
        buffer.insert_at_cursor(selection, (int) (selection.length - offset));
 
266
        inserting_text = false;
 
267
 
 
268
        hide();
 
269
    }
 
270
}
 
271