Sublime Forum

Made a neat plugin for easily adding a new view into a file

#1

Hi ST forum! I’m new here, so I apologize if this is the wrong section or something.

Previously, if you wanted to edit the same file in two different views simultaneously side-by-side, you would need to:

  1. Go to File -> New View Into File
  2. Split the view, i.e. alt+shift+2
  3. Drag the copied file into the new view
  4. (To undo it) Close the file (getting a save prompt for some reason), and reset the view layout to 1

So I wrote this plugin to do all that for me. I have the command mapped to f1:

*.sublime-keymap:

[
  ...
  { "keys": ["f1"], "command": "clone_file_to_new_view"},
  ...
]

So pressing f1 does one of the following, depending on the context:

  • If only 1 group is open, set the layout to 2 views side-by-side and clone the active view to the second one.
  • If 2 groups are open and the same file is active in both, remove the copy. If there are no other tabs in the second group, set the layout back to 1 group
  • If 2 groups are open and the same file is in both, but not necessarily active, focuses on the correct tab in the second group
    If 2 groups are open and the same file isn’t in both, copies the active view into the second group

Apologies for this nasty code :slight_smile: this was the easiest way I knew how to get the functionality I wanted.
Tools -> Developer -> New Plugin … (save as clone_file_to_new_view.py):

import sublime
import sublime_plugin

class CloneFileToNewViewCommand(sublime_plugin.WindowCommand):
    def run(self):
        if (self.window.num_groups() < 2):
            self.window.run_command('clone_file')

            self.window.set_layout({
                "cols": [0.0, 0.5, 1.0],
                "rows": [0.0, 1.0],
                "cells": [[0, 0, 1, 1], [1, 0, 2, 1]]
                })

            self.window.run_command('focus_group', {'group': 0})
            self.window.run_command('move_to_group', {'group': 1})

        else:
            view0 = self.window.active_view_in_group(0)
            view1 = self.window.active_view_in_group(1)

            # Same file open in each of the two windows, cull to 1 if possible
            if (view0.file_name() == view1.file_name()):
                self.window.focus_view(view1)

                view1.set_scratch(True)
                view1.close()

                self.window.focus_view(view0)

                # just deleted the only window, fix layout
                if (len(self.window.views_in_group(1)) == 0):
                    print("NO MORE")
                    self.window.set_layout({
                        "cols": [0.0, 1.0],
                        "rows": [0.0, 1.0],
                        "cells": [[0, 0, 1, 1]]})

            # Two views, but not the same file
            else:
                othergroup = 0
                if (self.window.active_group() == 0): othergroup = 1

                # Check if a copy already exists in 'othergroup' and just
                # focus on it if so
                otherviews = self.window.views_in_group(othergroup)
                for view in otherviews:
                    if (view.file_name() == self.window.active_view().file_name()):
                        self.window.focus_view(view)
                        return

                # No existing views found - make a new one
                self.window.run_command('clone_file')
                self.window.run_command('move_to_group', {'group': othergroup})
1 Like

On_load is not triggered in a new view with Ctrl+N
#2

This looks cool, you should submit this to the package repo.

0 Likes

#3

Thanks. Nice plugin. In case you are interested, the following addition also clones the viewport position and current selections:

import sublime
import sublime_plugin

class CloneFileToNewViewCommand(sublime_plugin.WindowCommand):
    def run(self):
        if (self.window.num_groups() < 2):
            self.window.run_command('clone_file')

            self.window.set_layout({
                "cols": [0.0, 0.5, 1.0],
                "rows": [0.0, 1.0],
                "cells": [[0, 0, 1, 1], [1, 0, 2, 1]]
                })

            self.window.run_command('focus_group', {'group': 0})
            self.window.run_command('move_to_group', {'group': 1})

            self.copy_position_and_selections(self.window.active_view_in_group(0), self.window.active_view_in_group(1))
        else:
            view0 = self.window.active_view_in_group(0)
            view1 = self.window.active_view_in_group(1)

            # Same file open in each of the two windows, cull to 1 if possible
            if (view0.file_name() == view1.file_name()):
                self.window.focus_view(view1)

                is_scratch = view1.is_scratch()
                view1.set_scratch(True)
                view1.close()
                view0.set_scratch(is_scratch)

                self.window.focus_view(view0)

                # just deleted the only window, fix layout
                if (len(self.window.views_in_group(1)) == 0):
                    print("NO MORE")
                    self.window.set_layout({
                        "cols": [0.0, 1.0],
                        "rows": [0.0, 1.0],
                        "cells": [[0, 0, 1, 1]]})

            # Two views, but not the same file
            else:
                othergroup = 0
                if (self.window.active_group() == 0): othergroup = 1

                # Check if a copy already exists in 'othergroup' and just
                # focus on it if so
                otherviews = self.window.views_in_group(othergroup)
                for view in otherviews:
                    if (view.file_name() == self.window.active_view().file_name()):
                        self.copy_position_and_selections(self.window.active_view(), view)
                        self.window.focus_view(view)
                        return

                # No existing views found - make a new one
                self.window.run_command('clone_file')
                self.window.run_command('move_to_group', {'group': othergroup})

                self.copy_position_and_selections(self.window.active_view_in_group(1 - othergroup), self.window.active_view_in_group(othergroup))

    def copy_position_and_selections(self, view_source, view_destination):
        view_destination.set_viewport_position(view_source.viewport_position(), False)
        view_destination.sel().clear()
        view_destination.sel().add_all(view_source.sel())
1 Like

#4

@Markus_Gritsch, That’s a great suggestion - was thinking about doing something like that but got lazy :slight_smile: Not sure if I would use it, personally (since I usually just use the second view for referencing), but it would definitely be a good optional setting to have. I would probably just modify copy_position_and_selections to take in two views, since you’re allowed to clone from group 1 to group 0 as well, depending on where the active view is (that’s what the whole othergroup nonsense is).

Also just thought of this, but I should also probably break this into two commands, one for cloning and one for removing. That way, people could just set them to the same or different keybindings if they wanted (I think…).

0 Likes

#5

Thanks for that hint. Edited the code above as you suggested.

0 Likes

#6

This plugin is super handy :rocket:, you should submit it in a repo.

0 Likes

#7

I also added some remembering of the scratch state before setting it to True and deleting the cloned view. Otherwise the original view would not be recognized as dirty after editing anymore, since the scratch state is a property of the underlying buffer.

0 Likes

#8

Fantastic plugin, thanks very much. I would repeat that manual task exactly myself multiple times a day. I’d love to see this added to PackageControl as a repo managed plugin.

0 Likes

#9

Origami plugin already have this feature — clone_file_to_pane command. Ctrl+K, Alt+Rightdefault Windows shortcut:

Thanks.

2 Likes