Sublime Forum

Making Sublime Text 3 Read Only

#1

Is there a way to make Sublime read only? Many times I’m in vs2019 doing a debug session and I keep Sublime up on my second monitor to use as a reference. I’ll be stepping through a file in VS and sometimes switch over to the same source file in Sublime to look up something. Then I can forget to switch focus back to VS…

Anyway, it would be nice to be able to “lock” Sublime into a read only mode.

0 Likes

Unexpected Behaviour - Can't Find Explanation
#2

There’s not a direct feature that does it, but a plugin can make a view read-only. For example if you use View Package File to open a package file, anything that comes from a sublime-package file is marked as read only as an indication that you can’t modify it.

One way to do this would be something like the following plugin:

import sublime
import sublime_plugin


class ToggleReadOnlyCommand(sublime_plugin.ApplicationCommand):
    def run(self):
        view = sublime.active_window().active_view()
        view.set_read_only(not view.is_read_only())

    def is_checked(self):
        view = sublime.active_window().active_view()
        if view and view.is_read_only():
            return True

        return False

    def is_enabled(self):
        return sublime.active_window().active_view() is not None

That implements a toggle_read_only command that flips the state of a file. You could then bind that to a key as desired, or add it to the command palette. You could also create a Context.sublime-menu file in your User package like the following to add it to the context menu:

[
    { "command": "toggle_read_only", "caption": "Read-Only", "mnemonic": "R", "checkbox": true },
]

How you ultimately set this up depends on how you’d like it to work. For example, the command could toggle the state of every file in the current window (or force it to be one way or the other). You could also extend it so that once this feature is “turned on”, anything that’s opened in that window is automatically made read-only without your having to do anything.

You could also set it up to automatically mark files as read-only when they open based on their location on disk as well.

This example does it a file at a time under the theory that if you’re opening a file like this you perhaps know in advance that this is definitely a file you don’t want to modify, which leaves you free to edit other things as needed.

2 Likes

[Finished]How to open a file in read-only mode
Sub make text to on read
#3

Thanks Terence!

0 Likes

#4

You can add the following event listener to the plugin listed in the post above:

class ReadOnlyEventListener(sublime_plugin.EventListener):
    def on_window_command(self, window, command, args):
        if command in ("prompt_open_file", "prompt_open"):
            readonly = False if args is None else args.get("readonly", False)
            window.settings().set("_open_read_only",readonly)

    def on_load(self, view):
        if view.window() is not None:
            readonly = view.window().settings().get("_open_read_only", False)
            view.set_read_only(readonly)
            view.window().settings().erase("_open_read_only")

This does two things:

  1. It watches to see if the command prompt_open_file or prompt_open is executed, and if it is it sets a setting in the current window indicating if the command had an argument labeled readonly or not (defaulting to False if it does not)

  2. It watches to see when a file has been newly loaded, and then checks the window it was loaded into to see if the setting added by #1 indicates that the file should be opened read-only or not, and if the answer it yes, it makes the tab read-only.

With that in place in the plugin, add a file named Main.sublime-menu to your User package with the following content:

[
    {
        "id": "file",
        "children":
        [
            { "caption": "-" },
            { "command": "prompt_open_file", "caption": "Open File (Read Only)…","platform": "!OSX", "args": {"readonly": true} },
            { "command": "prompt_open", "caption": "Open (Read Only)…", "platform": "OSX", "args": {"readonly": true} },
        ]
    }
]

This adds in two new entries (one for OSX and one for other OS’s) that execute the built in command for opening a file, but which give it arguments that say that the file should be opened read only.

The commands themselves ignore the argument (normally it would be an error to give a command an argument it does not understand, but these ones are in the core and don’t check that), but the plugin still triggers and can tell if it was provided or not.

This should do what you want, but note that it’s not 100% foolproof; there’s no way to tell if someone picked the command to open a file and then cancelled.

This means that if you invoke that command and don’t actually open a file, it’s still recorded that you intended to, and so the next file that loads without using the File > Open command will get the read-only state (for example if you cancelled and then drag and drop a file to open it).

Not a deal breaker (key binding or menu entry on standby as a fix), but something to be aware of. In theory the plugin could revert the setting if the file doesn’t open in a set period, but anything where you’re trying to guess how long something should take is going to be wrong sometimes (being a guess), so in my opinion it’s not worth it.

In ST4, plugins can prompt the user for a filename to load, which makes this more seamless (though the code looks similar). This particular version should work in ST4 though.

0 Likes

#5

This is amazing! Thank you very much.

0 Likes

#6

@foolc made an additional request via a DM here on the forum for having this also display something in the status bar that tells you when a file is read only.

The change for that is pretty simple, but in the interests of keeping all of this information together in one place for future reference, here’s a complete new plugin that does all of the things outlined in the previous posts with the addition of this new feature. You should use this one rather than the fragments above unless you want to manually make the required modifications.

The plugin (instructions for installing a plugin if you’re unfamiliar can be found here) provides a command for toggling the read only state of a file, which will stop you from being able to type into it. Whenever a file is made read-only, the status bar will say [READONLY] as an indication of this.

Additionally, there is also an event listener that will allow you to use the main menu augmentation outlined below to open a file in a read only state directly. How this works is explained in a post further up in this thread.

import sublime
import sublime_plugin


def _toggle_read_only(view):
    """
    Toggle the read-only state of the provided view, and update the status bar
    to provide an indication of the state.
    """
    if view.is_read_only():
        view.set_read_only(False)
        view.erase_status('rostate')
    else:
        view.set_read_only(True)
        view.set_status('rostate', '[READONLY]')


class ToggleReadOnlyCommand(sublime_plugin.ApplicationCommand):
    def run(self):
        _toggle_read_only(sublime.active_window().active_view())

    def is_checked(self):
        view = sublime.active_window().active_view()
        if view and view.is_read_only():
            return True

        return False

    def is_enabled(self):
        return sublime.active_window().active_view() is not None


class ReadOnlyEventListener(sublime_plugin.EventListener):
    def on_window_command(self, window, command, args):
        if command in ("prompt_open_file", "prompt_open"):
            readonly = False if args is None else args.get("readonly", False)
            window.settings().set("_open_read_only",readonly)

    def on_load(self, view):
        if view.window() is not None:
            readonly = view.window().settings().get("_open_read_only", False)
            view.window().settings().erase("_open_read_only")
            if readonly:
                _toggle_read_only(view)

You can bind the command to a key easily. If you want an option in the context menu to toggle a file to be read only, create a file named Context.sublime-menu in your User package with this content in it (or add this command to an existing file, if you have one).

[
    { "command": "toggle_read_only", "caption": "Read-Only", "mnemonic": "R", "checkbox": true },
]

The menu item will have a checkmark next to it when the current file is read only, as an extra validation.

You can also create a ReadOnly.sublime-commands file in your User package with the following content (or choose any other filename; only the extension is important) to add the command to the command palette:

[
  { "caption": "Toggle Read Only", "command": "toggle_read_only" },
]

If you want to be able to open a file directly as a read-only file, create a file named Main.sublime-menu in your User package with this content (if you have such a file, you need to merge this in with your existing file):

[
    {
        "id": "file",
        "children":
        [
            { "caption": "-" },
            { "command": "prompt_open_file", "caption": "Open File (Read Only)…","platform": "!OSX", "args": {"readonly": true} },
            { "command": "prompt_open", "caption": "Open (Read Only)…", "platform": "OSX", "args": {"readonly": true} },
        ]
    },
]

This will add a entry to the File menu named Open File (Read Only)... that will prompt you for a file, which will trigger the event listener in the plugin to toggle the read-only state directly.

As noted above, if you start to open a file and then cancel, followed by dragging a file into the window to open it, the dragged file will open read-only. The simplest expedient is to use the context menu or command palette entry (or key binding, if you made one) to flip the state. This probably won’t happen very often.

1 Like

#7

@OdatNurd
Thank you very much.

1 Like