Skip to content
Open
Show file tree
Hide file tree
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
64 changes: 0 additions & 64 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,10 @@ namespace Scratch {
public const string ACTION_OPEN_PROJECT = "action-open-project";
public const string ACTION_COLLAPSE_ALL_FOLDERS = "action-collapse-all-folders";
public const string ACTION_GO_TO = "action-go-to";
public const string ACTION_SORT_LINES = "action-sort-lines";
public const string ACTION_NEW_TAB = "action-new-tab";
public const string ACTION_NEW_FROM_CLIPBOARD = "action-new-from-clipboard";
public const string ACTION_DUPLICATE_TAB = "action-duplicate-tab";
public const string ACTION_PREFERENCES = "preferences";
public const string ACTION_ADD_MARK = "action_add_mark";
public const string ACTION_PREVIOUS_MARK = "action_previous_mark";
public const string ACTION_NEXT_MARK = "action_next_mark";

public const string ACTION_UNDO = "action-undo";
public const string ACTION_REDO = "action-redo";
Expand All @@ -104,7 +100,6 @@ namespace Scratch {
public const string ACTION_ZOOM_DEFAULT = "action-zoom-default";
public const string ACTION_ZOOM_IN = "action-zoom-in";
public const string ACTION_ZOOM_OUT = "action-zoom-out";
public const string ACTION_TOGGLE_COMMENT = "action-toggle-comment";
public const string ACTION_TOGGLE_SHOW_FIND = "action-toggle_show-find";
public const string ACTION_TOGGLE_SIDEBAR = "action-toggle-sidebar";
public const string ACTION_FOCUS_SIDEBAR = "action-focus-sidebar";
Expand Down Expand Up @@ -151,7 +146,6 @@ namespace Scratch {
{ ACTION_TOGGLE_SHOW_FIND, action_toggle_show_find, null, "false" },
{ ACTION_TEMPLATES, action_templates },
{ ACTION_GO_TO, action_go_to },
{ ACTION_SORT_LINES, action_sort_lines },
{ ACTION_NEW_TAB, action_new_tab },
{ ACTION_NEW_FROM_CLIPBOARD, action_new_tab_from_clipboard },
{ ACTION_DUPLICATE_TAB, action_duplicate_tab },
Expand All @@ -168,7 +162,6 @@ namespace Scratch {
{ ACTION_ZOOM_DEFAULT, action_set_default_zoom },
{ ACTION_ZOOM_IN, action_zoom_in },
{ ACTION_ZOOM_OUT, action_zoom_out},
{ ACTION_TOGGLE_COMMENT, action_toggle_comment },
{ ACTION_TOGGLE_SIDEBAR, action_toggle_sidebar, null, "true" },
{ ACTION_FOCUS_SIDEBAR, action_focus_sidebar },
{ ACTION_FOCUS_DOCUMENT, action_focus_document },
Expand All @@ -180,9 +173,6 @@ namespace Scratch {
{ ACTION_PREVIOUS_TAB, action_previous_tab },
{ ACTION_CLEAR_LINES, action_clear_lines },
{ ACTION_BRANCH_ACTIONS, action_branch_actions, "s" },
{ ACTION_ADD_MARK, action_add_mark},
{ ACTION_PREVIOUS_MARK, action_previous_mark},
{ ACTION_NEXT_MARK, action_next_mark},
{ ACTION_CLOSE_TAB, action_close_tab, "s" },
{ ACTION_CLOSE_TABS_TO_RIGHT, action_close_tabs_to_right },
{ ACTION_CLOSE_OTHER_TABS, action_close_other_tabs },
Expand Down Expand Up @@ -220,7 +210,6 @@ namespace Scratch {
action_accelerators.set (ACTION_SAVE, "<Control>s");
action_accelerators.set (ACTION_SAVE_AS, "<Control><shift>s");
action_accelerators.set (ACTION_GO_TO, "<Control>i");
action_accelerators.set (ACTION_SORT_LINES, "F5");
action_accelerators.set (ACTION_NEW_TAB, "<Control>n");
action_accelerators.set (ACTION_DUPLICATE_TAB, "<Control><Shift>k" );
action_accelerators.set (ACTION_UNDO, "<Control>z");
Expand All @@ -239,8 +228,6 @@ namespace Scratch {
action_accelerators.set (ACTION_ZOOM_IN, "<Control>KP_Add");
action_accelerators.set (ACTION_ZOOM_OUT, "<Control>minus");
action_accelerators.set (ACTION_ZOOM_OUT, "<Control>KP_Subtract");
action_accelerators.set (ACTION_TOGGLE_COMMENT, "<Control>m");
action_accelerators.set (ACTION_TOGGLE_COMMENT, "<Control>slash");
action_accelerators.set (ACTION_TOGGLE_SIDEBAR, "F9"); // GNOME
action_accelerators.set (ACTION_TOGGLE_SIDEBAR, "<Control>backslash"); // Atom
action_accelerators.set (ACTION_FOCUS_SIDEBAR, "<Control><Alt>Left");
Expand All @@ -255,9 +242,6 @@ namespace Scratch {
action_accelerators.set (ACTION_PREVIOUS_TAB, "<Control>Page_Up");
action_accelerators.set (ACTION_CLEAR_LINES, "<Control>K"); //Geany
action_accelerators.set (ACTION_BRANCH_ACTIONS + "::", "<Control>B");
action_accelerators.set (ACTION_ADD_MARK, "<Alt>equal");
action_accelerators.set (ACTION_PREVIOUS_MARK, "<Alt>Left");
action_accelerators.set (ACTION_NEXT_MARK, "<Alt>Right");
action_accelerators.set (ACTION_HIDE_PROJECT_DOCS + "::", "<Control><Shift>h");
action_accelerators.set (ACTION_MOVE_TAB_TO_NEW_WINDOW, "<Control><Alt>n");
action_accelerators.set (ACTION_RESTORE_PROJECT_DOCS + "::", "<Control><Shift>r");
Expand Down Expand Up @@ -1405,27 +1389,6 @@ namespace Scratch {
buffer.insert (ref start, selected.up (), -1);
}

private void action_toggle_comment () {
var doc = get_focused_document ();
if (doc == null) {
return;
}

var buffer = doc.source_view.buffer;
if (buffer is Gtk.SourceBuffer) {
CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer);
}
}

private void action_sort_lines () {
var doc = get_focused_document ();
if (doc == null) {
return;
}

doc.source_view.sort_selected_lines ();
}

private void action_toggle_sidebar (SimpleAction action) {
if (sidebar == null) {
return;
Expand Down Expand Up @@ -1526,33 +1489,6 @@ namespace Scratch {
folder_manager_view.branch_actions (get_target_path_for_actions (param));
}

private void action_previous_mark () {
var doc = get_focused_document ();
if (doc == null) {
return;
}

doc.source_view.goto_previous_mark ();
}

private void action_next_mark () {
var doc = get_focused_document ();
if (doc == null) {
return;
}

doc.source_view.goto_next_mark ();
}

private void action_add_mark () {
var doc = get_focused_document ();
if (doc == null) {
return;
}

doc.source_view.add_mark_at_cursor ();
}

private void action_move_tab_to_new_window () {
document_view.transfer_tab_to_new_window ();
}
Expand Down
2 changes: 1 addition & 1 deletion src/Services/Document.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,7 @@ namespace Scratch.Services {
/* Pull the buffer into an array and then work out which parts are to be deleted.
* Do not strip line currently being edited unless forced */
private void strip_trailing_spaces () {
if (!loaded || source_view.language == null) {
if (!loaded || source_view.language == null || source_view.buffer.has_selection) {
return;
}

Expand Down
3 changes: 2 additions & 1 deletion src/Widgets/NavMarkGutterRenderer.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPix
public Gtk.TextBuffer buffer { get; construct; }
public bool has_marks {
get {
purge_and_sort_mark_list ();
return mark_list.size > 0;
}
}
Expand Down Expand Up @@ -101,6 +100,8 @@ public class Scratch.Widgets.NavMarkGutterRenderer : Gtk.SourceGutterRendererPix
}

sorted_line_list.sort ();

notify_property ("has-marks");
}

public void delete_mark_at_line (int line) {
Expand Down
150 changes: 100 additions & 50 deletions src/Widgets/SourceView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace Scratch.Widgets {

public GLib.File location { get; set; }
public FolderManager.ProjectFolderItem project { get; set; default = null; }
public SimpleActionGroup actions { get; construct; }

private string font;
private uint selection_changed_timer = 0;
Expand All @@ -38,6 +39,7 @@ namespace Scratch.Widgets {
private string selected_text = "";
private GitGutterRenderer git_diff_gutter_renderer;
private NavMarkGutterRenderer navmark_gutter_renderer;
private Gtk.EventControllerKey key_controller;

private const uint THROTTLE_MS = 400;
private double total_delta = 0;
Expand All @@ -55,6 +57,7 @@ namespace Scratch.Widgets {
set {
((Gtk.SourceBuffer) buffer).language = value;
}

get {
return ((Gtk.SourceBuffer) buffer).language;
}
Expand Down Expand Up @@ -192,7 +195,103 @@ namespace Scratch.Widgets {
}
});

populate_popup.connect_after (on_context_menu);
// Actions and menumodel for additional context menu items
var sort_action = new SimpleAction ("sort-lines", null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we already have actions for these that we were using previously. Is there a reason to create new actions instead of reusing the existing ones?

@jeremypw jeremypw Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in the process of removing those actions and associated functions from MainWindow. It makes more sense to handle them locally, especially in Gtk4.

Note that this pattern has already been used for the Terminal pane and Sidebar for example.

var mark_action = new SimpleAction ("mark", null);
var next_mark_action = new SimpleAction ("next-mark", null);
var prev_mark_action = new SimpleAction ("prev-mark", null);
var toggle_comment_action = new SimpleAction ("toggle-comment", null);

actions = new SimpleActionGroup ();
actions.add_action (sort_action);
actions.add_action (mark_action);
actions.add_action (next_mark_action);
actions.add_action (prev_mark_action);
actions.add_action (toggle_comment_action);

insert_action_group ("sourceview", actions);
sort_action.activate.connect (sort_selected_lines);
mark_action.activate.connect (add_mark_at_cursor);
next_mark_action.activate.connect (goto_next_mark);
prev_mark_action.activate.connect (goto_previous_mark);
toggle_comment_action.activate.connect (() => {
CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer);
});

var extra_menu = new Menu ();
extra_menu.append (_("Sort Lines"), "sort-lines");
extra_menu.append (_("Mark Line"), "mark");
extra_menu.append (_("Previous Mark"), "next-mark");
extra_menu.append (_("Next Mark"), "prev-mark");
extra_menu.append (_("Toggle Comment"), "toggle-comment");

// enable/disable action depending on changes to language, selection, marks in document
buffer.notify["has-selection"].connect (() => {
sort_action.set_enabled (buffer.has_selection);
});
buffer.notify["language"].connect (() => {
toggle_comment_action.set_enabled (CommentToggler.language_has_comments (((Gtk.SourceBuffer)buffer).language));
});
buffer.notify_property ("has-selection");
buffer.notify_property ("language");

navmark_gutter_renderer.notify["has-marks"].connect (() => {
next_mark_action.set_enabled (navmark_gutter_renderer.has_marks);
prev_mark_action.set_enabled (next_mark_action.get_enabled ());
});
navmark_gutter_renderer.notify_property ("has-marks");

// For Gtk3 we need to convert extra_menu to additional Gtk.MenuItems. This is omitted in Gtk4
populate_popup.connect_after ((menu) => {
scroll_mark_onscreen (buffer.get_mark ("insert")); //TODO Check if still needed in Gtk4
for (int i = 0; i < extra_menu.get_n_items (); i++) {
var name = extra_menu.get_item_attribute_value (i, "label", VariantType.STRING).get_string ();
var action = extra_menu.get_item_attribute_value (i, "action", VariantType.STRING).get_string ();
// warning ("adding menuitem name %s, action_name %s", name, action);
menu.add (
new Gtk.MenuItem.with_label (name) {
action_name = "sourceview." + action
}
);
}
menu.show_all ();
});

// Handle context menu shortcuts here.
// In Gtk3 we use a EventControllerKey but after porting to Gtk4 we can replace with Gtk.Shortcuts
key_controller = new Gtk.EventControllerKey (application.get_active_window ()) {
propagation_phase = CAPTURE
};
key_controller.key_pressed.connect ((kv, kc, state) => {
if (!this.is_focus || !Gtk.accelerator_valid (kv, state)) {
return false;
}

var mods = (state & Gtk.accelerator_get_default_mod_mask ());
var accel = Gtk.accelerator_name (kv, mods);
switch (accel) {
case "F5":
sort_selected_lines ();
return true;
case "<Alt>equal":
add_mark_at_cursor ();
return true;
case "<Alt>Left":
goto_next_mark ();
return true;
case "<Alt>Right":
goto_previous_mark ();
return true;
case "<Primary>m":
case "<Primary>slash":
CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer);
return true;
default:
break;
}

return false;
});

size_allocate.connect ((allocation) => {
// Throttle for performance
Expand Down Expand Up @@ -588,55 +687,6 @@ namespace Scratch.Widgets {
}
}

private void on_context_menu (Gtk.Menu menu) {
scroll_mark_onscreen (buffer.get_mark ("insert"));

var sort_item = new Gtk.MenuItem.with_label (_("Sort Lines")) {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_SORT_LINES
};

var add_edit_item = new Gtk.MenuItem.with_label (_("Mark Line")) {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_ADD_MARK
};

var previous_edit_item = new Gtk.MenuItem.with_label (_("Previous Mark")) {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_PREVIOUS_MARK
};

var next_edit_item = new Gtk.MenuItem.with_label (_("Next Mark")) {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_NEXT_MARK
};

menu.add (sort_item);
menu.add (add_edit_item);
menu.add (previous_edit_item);
menu.add (next_edit_item);

if (buffer is Gtk.SourceBuffer) {
var comment_item = new Gtk.MenuItem.with_label (_("Toggle Comment")) {
action_name = MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_COMMENT
};

var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ());
if (!can_comment) {
comment_item.action_name = "";
}

menu.add (comment_item);
}

menu.show_all ();

if (!(get_selected_line_count () > 1)) {
sort_item.action_name = "";
}

if (!navmark_gutter_renderer.has_marks) {
previous_edit_item.action_name = "";
next_edit_item.action_name = "";
}
}

private static int calculate_bottom_margin (int height_in_px) {
const int LINES_TO_KEEP = 3;
const double PT_TO_PX = 1.6667; // Normally 1.3333, but this accounts for line-height
Expand Down