Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 98 additions & 114 deletions src/Widgets/FormatBar.vala
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,19 @@ public class Code.FormatBar : Gtk.Box {
public bool tab_width_set_by_editor_config { get; set; default = false; }

private FormatBox line_formatbox;
private Gtk.MenuButton line_menubutton;
private FormatBox lang_formatbox;
private FormatBox tab_formatbox;
private Granite.SwitchModelButton space_tab_modelbutton;
private Gtk.Entry goto_entry;
private Gtk.InfoBar editorconfig_infobar;
private Gtk.ListBox lang_selection_listbox;
private Gtk.MenuButton line_menubutton;
private Gtk.SourceLanguageManager manager;
private Gtk.SpinButton width_spinbutton;
private LangEntry normal_entry;
private SimpleAction language_action;
private ulong cursor_handler = 0;
private ulong language_handler = 0;

private unowned Scratch.Services.Document? doc = null;
private unowned Scratch.Services.Document? current_doc = null;

construct {
get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED);
Expand Down Expand Up @@ -97,7 +98,7 @@ public class Code.FormatBar : Gtk.Box {
placeholder_text = _("Filter languages")
};

lang_selection_listbox = new Gtk.ListBox () {
var lang_selection_listbox = new Gtk.ListBox () {
selection_mode = SINGLE
};
lang_selection_listbox.set_sort_func ((row1, row2) => {
Expand All @@ -108,16 +109,13 @@ public class Code.FormatBar : Gtk.Box {
return (((LangEntry) row).lang_name.down ().contains (lang_selection_filter.text.down ().strip ()));
});

unowned SList<Gtk.RadioButton> group = null;
foreach (unowned string id in manager.get_language_ids ()) {
weak Gtk.SourceLanguage lang = manager.get_language (id);
var entry = new LangEntry (id, lang.name, group);
group = entry.get_radio_group ();
var entry = new LangEntry (id, lang.name);
lang_selection_listbox.add (entry);
}

normal_entry = new LangEntry (null, _("Plain Text"), group);

var normal_entry = new LangEntry ("", _("Plain Text"));
lang_selection_listbox.add (normal_entry);

var lang_scrolled = new Gtk.ScrolledWindow (null, null) {
Expand Down Expand Up @@ -187,16 +185,32 @@ public class Code.FormatBar : Gtk.Box {
add (lang_menubutton);
add (line_menubutton);

lang_selection_listbox.row_activated.connect ((row) => {
var lang_entry = ((LangEntry) row);
select_language (lang_entry);
language_action = new SimpleAction.stateful ("language", VariantType.STRING, new Variant.string (""));
language_action.change_state.connect ((parameter) => {
language_action.set_state (parameter);
var lang_id = parameter.get_string ();

if (current_doc.source_view.language.id != lang_id) { // Avoids loop
current_doc.source_view.language = lang_id != "" ? manager.get_language (lang_id) : null;
}

if (lang_id != "") {
unowned var lang = manager.get_language (lang_id);
lang_formatbox.text = lang.name;
} else {
lang_formatbox.text = _("Plain Text");
current_doc.source_view.language = null;
}
});

var action_group = new SimpleActionGroup ();
action_group.add_action (language_action);
insert_action_group ("format", action_group);

lang_selection_filter.changed.connect (() => {
lang_selection_listbox.invalidate_filter ();
});

format_tab_header_from_global_settings ();
width_spinbutton.value_changed.connect (() => {
if (!tab_width_set_by_editor_config) {
Scratch.settings.set_int (
Expand All @@ -215,14 +229,16 @@ public class Code.FormatBar : Gtk.Box {
}
});

// We need to connect_after because otherwise, the text isn't parsed into the "value" property and we only get the previous value
// We need to connect_after because otherwise, the text isn't parsed into the "value" property
// and we only get the previous value
goto_entry.activate.connect_after (() => {
int line, column;
goto_entry.text = goto_entry.text.replace (":", ".");
goto_entry.text.scanf ("%i.%i", out line, out column);
doc.source_view.go_to_line (line, column - 1);
// Focuses parent to the source view, so that the cursor, which indicates line and column is actually visible.
doc.source_view.grab_focus ();
current_doc.source_view.go_to_line (line, column - 1);
// Focuses parent to the source view, so that the cursor, which indicates line and column
// is actually visible.
current_doc.source_view.grab_focus ();
});

Scratch.settings.changed["indent-width"].connect (format_tab_header_from_global_settings);
Expand All @@ -236,32 +252,60 @@ public class Code.FormatBar : Gtk.Box {
line_menubutton.active = true;
}

private void select_language (LangEntry lang, bool update_source_view = true) {
lang_selection_listbox.select_row (lang);
lang_formatbox.text = lang.lang_name;
if (update_source_view) {
lang.active = true;
doc.source_view.language = lang.lang_id != null ? manager.get_language (lang.lang_id) : null;
public void set_document (Scratch.Services.Document doc) requires (doc != null) {
if (current_doc != null) {
SignalHandler.disconnect (current_doc, cursor_handler);
SignalHandler.disconnect (current_doc, language_handler);
}

current_doc = doc;
if (doc.loading) {
Timeout.add (200, () => {
if (doc.loading) {
return Source.CONTINUE;
} else {
update_widgets ();
return Source.REMOVE;
}
});
} else {
lang.selected = true;
update_widgets ();
}
}

private void format_tab_header_from_global_settings () {
if (!tab_style_set_by_editor_config) {
set_insert_spaces_instead_of_tabs (Scratch.settings.get_boolean ("spaces-instead-of-tabs"));
public void set_insert_spaces_instead_of_tabs (bool use_spaces) requires (current_doc != null) {
space_tab_modelbutton.active = use_spaces;
current_doc.source_view.insert_spaces_instead_of_tabs = use_spaces;
}

public void set_tab_width (int indent_width) requires (current_doc != null) {
width_spinbutton.@value = indent_width;
if (space_tab_modelbutton.active) {
tab_formatbox.text = ngettext ("%d Space", "%d Spaces", indent_width).printf (indent_width);
} else {
tab_formatbox.text = ngettext ("%d Tab", "%d Tabs", indent_width).printf (indent_width);
}

if (!tab_width_set_by_editor_config) {
set_tab_width (Scratch.settings.get_int ("indent-width"));
current_doc.source_view.indent_width = indent_width;
current_doc.source_view.tab_width = indent_width;
}

private void update_widgets () requires (current_doc != null) {
format_tab_header_from_global_settings ();
update_current_lang ();
format_tab_header_from_global_settings ();
format_line_header ();
if (cursor_handler == 0) {
cursor_handler = current_doc.source_view.buffer.notify["cursor-position"].connect (format_line_header);
}

editorconfig_infobar.revealed = tab_style_set_by_editor_config || tab_width_set_by_editor_config;
space_tab_modelbutton.sensitive = !tab_style_set_by_editor_config;
if (language_handler == 0) {
language_handler = current_doc.source_view.notify["language"].connect (update_current_lang);
}
}

private void format_line_header () {
var buffer = doc.source_view.buffer;
private void format_line_header () requires (current_doc != null) {
var buffer = current_doc.source_view.buffer;
var position = buffer.cursor_position;
Gtk.TextIter iter;
buffer.get_iter_at_offset (out iter, position);
Expand All @@ -270,52 +314,24 @@ public class Code.FormatBar : Gtk.Box {
goto_entry.text = "%d.%d".printf (line, iter.get_line_offset () + 1);
}

public void set_document (Scratch.Services.Document doc) {
if (this.doc != null) {
this.doc.source_view.buffer.notify["cursor-position"].disconnect (format_line_header);
}

this.doc = doc;
update_current_lang ();
format_tab_header_from_global_settings ();
format_line_header ();
this.doc.source_view.buffer.notify["cursor-position"].connect (format_line_header);
private void update_current_lang () requires (current_doc != null) {
var language = current_doc.source_view.language;
var lang_id = language != null ? language.id : "";
// Should not directly modify action state
language_action.change_state (new Variant.string (lang_id));
}

public void set_insert_spaces_instead_of_tabs (bool use_spaces) {
space_tab_modelbutton.active = use_spaces;
if (doc != null) {
doc.source_view.insert_spaces_instead_of_tabs = use_spaces;
}
}

public void set_tab_width (int indent_width) {
width_spinbutton.@value = indent_width;
if (space_tab_modelbutton.active) {
tab_formatbox.text = ngettext ("%d Space", "%d Spaces", indent_width).printf (indent_width);
} else {
tab_formatbox.text = ngettext ("%d Tab", "%d Tabs", indent_width).printf (indent_width);
private void format_tab_header_from_global_settings () {
if (!tab_style_set_by_editor_config) {
set_insert_spaces_instead_of_tabs (Scratch.settings.get_boolean ("spaces-instead-of-tabs"));
}

if (doc != null) {
doc.source_view.indent_width = indent_width;
doc.source_view.tab_width = indent_width;
if (!tab_width_set_by_editor_config) {
set_tab_width (Scratch.settings.get_int ("indent-width"));
}
}

private void update_current_lang () {
var language = doc.source_view.language;
if (language != null) {
var lang_id = language.id;
lang_selection_listbox.get_children ().foreach ((child) => {
var lang_entry = ((LangEntry) child);
if (lang_entry.lang_id == lang_id) {
select_language (lang_entry, false);
}
});
} else {
select_language (normal_entry, false);
}
editorconfig_infobar.revealed = tab_style_set_by_editor_config || tab_width_set_by_editor_config;
space_tab_modelbutton.sensitive = !tab_style_set_by_editor_config;
}

private class FormatBox : Gtk.Box {
Expand Down Expand Up @@ -348,56 +364,24 @@ public class Code.FormatBar : Gtk.Box {
}

private class LangEntry : Gtk.ListBoxRow {
public string? lang_id { get; construct; }
public string lang_id { get; construct; }
public string lang_name { get; construct; }
public unowned SList<Gtk.RadioButton> group { get; construct; }

public bool active {
get {
return lang_radio.active;
}

set {
lang_radio.active = value;
}
}

public bool selected {
get {
return lang_radio.active;
}

set {
lang_radio.toggled.disconnect (radio_toggled);
lang_radio.active = value;
lang_radio.toggled.connect (radio_toggled);
}
}

private Gtk.RadioButton lang_radio;
public LangEntry (string? lang_id, string lang_name, SList<Gtk.RadioButton> group) {
Object (group: group, lang_id: lang_id, lang_name: lang_name);
public LangEntry (string lang_id, string lang_name) {
Object (lang_id: lang_id, lang_name: lang_name);
}

class construct {
set_css_name (Gtk.STYLE_CLASS_MENUITEM);
}

construct {
lang_radio = new Gtk.RadioButton.with_label (group, lang_name);

add (lang_radio);
lang_radio.toggled.connect (radio_toggled);
}

private void radio_toggled () {
if (lang_radio.active) {
activate ();
}
}
var lang_checkbutton = new Gtk.CheckButton.with_label (lang_name) {
action_name = "format.language",
action_target = new Variant.string (lang_id)
};

public unowned SList<Gtk.RadioButton> get_radio_group () {
return lang_radio.get_group ();
child = lang_checkbutton;
}
}
}
Loading