Search code examples
sublimetext3sublime-text-plugin

How to copy current file full path without filename using right click menu?


import sublime
import sublime_plugin
import os
class copypathCommand(sublime_plugin.WindowCommand):
    def run(self,edit):
        # view = sublime.active_window().active_view()
            vars = self.window.extract_variables()
            working_dir = vars['file_path']
            base_name=os.path.basename(working_dir)
            sublime.set_clipboard(base_name)
            print ("get clipboard" + sublime.get_clipboard())

Context.sublime-menu

[
    { "caption": "copypath",  "command": "copypath"},
]

This script doesn't work. When I use ctrl-v,it pastes "working_dir". I think the problem is sublime_plugin.WindowCommand parameter or the self.window.extract_variables() because I only change this two line from other working fine copyfilename script. menu button turns grey when add if statement


Solution

  • Your plugin contains several errors and places where the code can be improved.

    1. The os.path class is not automatically imported using import os. You need to use import os.path.

    2. Your class name class copypathCommand must begin with a capital C to create the copypath command, i.e. class CopypathCommand, see How to set or find the command name of a Sublime Text plugin.

    3. You have inherited from sublime_plugin.WindowCommand but then used the edit parameter in the run() method which can only be used in classes that inherit from sublime_plugin.TextCommand. It is best to use a TextCommand for this plugin since it will already have the active view set as self.view. So that gives class CopypathCommand(sublime_plugin.TextCommand).

    4. There is no need to use extract_variables() to get the file path. The Sublime Text API provides the file_name() method in the view class which returns the full file path or None if the view / buffer is unsaved (i.e. no file path to return). So the full path can be retrieved with one call file_path = self.view.file_name().

    5. You use os.path.basename() but your question title says you want the "current file full path without filename" which would require the use of os.path.dirname(). This is how those 2 methods differ in what is returned:

    os.path.basename("/full/path/to/folder/filename") --> "filename"
    os.path.dirname("/full/path/to/folder/filename")  --> "/full/path/to/folder"
    

    Putting it all together for a working plugin gives the following code:

    # Save in ST config folder: ../Packages/User/CopypathToClipboard.py
    
    import os.path, sublime, sublime_plugin
    
    class CopypathCommand(sublime_plugin.TextCommand):
    
        def run(self, edit):
            file_path = self.view.file_name()
            if not file_path:
                sublime.status_message("The current buffer is not saved")
                return
            dir_path = os.path.dirname(file_path)
            sublime.set_clipboard(dir_path)
            sublime.status_message("Copied folder to the clipboard: " + dir_path)
    
        # is_enabled() enables the plugin only if the view contains a saved file.
        # If this returns false the 'copypath' command will not be available,
        # e.g. command palette captions hidden, context menu captions greyed out.
        def is_enabled(self):
            return True if self.view.file_name() else False
    

    There is nothing wrong with your Context.sublime-menu code — although adding the id line, as I have done below, means that the command's caption Copy Folder Path will be displayed in the same menu section as Copy File Path in the right-click context menu.

    // Save in ST config folder: ../Packages/User/Context.sublime-menu
    [
        { "caption": "-", "id": "file" },
        { "caption": "Copy Folder Path",  "command": "copypath"}
    ]