• sublime text build system automatic ctrl/cmd+B自动选择 python2 或 python3


    背景

    我同时安装了 python2 和 python3 时,python 指向 python2,python3 才是 python3
    默认情况下,在 Sublime 内 Ctrl/Cmd + B 运行 python 文件时,调用的是环境变量 PATH 中的 python
    所以当我想用 python3 执行文件时,传统方法是先 new 一个 build system 专门运行 python3,每次还都得手动指定。极其繁琐!

    需求

    我希望 Sublime 可以根据 py 文件开头第一行注释 #!/usr/bin/env python3 来确定是执行 python2 还是 python3

    解决方案

    需要一个脚本,在 Sublime 调进 build system 时调用这个脚本
    写一个新的 Python.sublime-build 文件,在这个文件中调用前面的脚本
    用自己写的 Python.sublime-build 覆盖默认的 Python.sublime-build

    具体步骤

    1. 找到 Python.sublime-package 文件,Mac 系统下在 /Applications/Sublime Text.app/Contents/MacOS/Packages/Python.sublime-package
    2. 把它复制一份到 ~/Library/Application Support/Sublime Text 3/Packages/User/ 下面,并把后缀改成 .zip
    3. 解压得到一个 Python 目录,进到这个目录,找到 Python.sublime-build 文件,装盘备用,一会下锅。
    4. 新建一个文件随便给个名字,保存在 ~/Library/Application Support/Sublime Text 3/Packages/User/ 下面,文件内容如下:
    import sublime
    import sublime_plugin
    
    import subprocess
    import threading
    import os
    
    
    class MyPyBuildCommand(sublime_plugin.WindowCommand):
    
        encoding = 'utf-8'
        killed = False
        proc = None
        panel = None
        panel_lock = threading.Lock()
    
        def is_enabled(self, kill=False):
            # The Cancel build option should only be available
            # when the process is still running
            if kill:
                return self.proc is not None and self.proc.poll() is None
            return True
    
        def detect_version(self):
            fname = self.window.active_view ().file_name()
            with open(fname, 'r', encoding='utf-8') as f:
                line = f.readline()
            m = re.search(r'(python[0-9.]*)', line)
            if m and line.startswith("#"):
                return m.group(1)
            return "python"
    
        def run(self, kill=False):
            if kill:
                if self.proc is not None and self.proc.poll() is None:
                    self.killed = True
                    self.proc.terminate()
                    self.proc = None
                return
    
            vars = self.window.extract_variables()
            working_dir = vars['file_path']
    
            # A lock is used to ensure only one thread is
            # touching the output panel at a time
            with self.panel_lock:
                # Creating the panel implicitly clears any previous contents
                self.panel = self.window.create_output_panel('exec')
    
                # Enable result navigation. The result_file_regex does
                # the primary matching, but result_line_regex is used
                # when build output includes some entries that only
                # contain line/column info beneath a previous line
                # listing the file info. The result_base_dir sets the
                # path to resolve relative file names against.
                settings = self.panel.settings()
                settings.set(
                    'result_file_regex',
                    r'^File "([^"]+)" line (d+) col (d+)'
                )
                settings.set(
                    'result_line_regex',
                    r'^s+line (d+) col (d+)'
                )
                settings.set('result_base_dir', working_dir)
    
                self.window.run_command('show_panel', {'panel': 'output.exec'})
    
            if self.proc is not None and self.proc.poll() is None:
                self.proc.terminate()
                self.proc = None
    
            args = [ self.detect_version() ]
            # sublime.message_dialog(vars['file_name'])
            args.append(vars['file_name'])
            env = os.environ.copy()
            env["PYTHONUNBUFFERED"] = "1" # 及时 print
            self.proc = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                cwd=working_dir,
                env=env,
            )
            self.killed = False
    
            threading.Thread(
                target=self.read_handle,
                args=(self.proc.stdout,)
            ).start()
    
        def read_handle(self, handle):
            # for line in iter(handle.readline, b''):
                # self.queue_write(line.decode(self.encoding))
                # handle.close()
            # return
    
            chunk_size = 2 ** 13
            out = b''
            while True:
                try:
                    data = os.read(handle.fileno(), chunk_size)
                    # If exactly the requested number of bytes was
                    # read, there may be more data, and the current
                    # data may contain part of a multibyte char
                    out += data
                    if len(data) == chunk_size:
                        continue
                    if data == b'' and out == b'':
                        raise IOError('EOF')
                    # We pass out to a function to ensure the
                    # timeout gets the value of out right now,
                    # rather than a future (mutated) version
                    self.queue_write(out.decode(self.encoding))
                    if data == b'':
                        raise IOError('EOF')
                    out = b''
                except (UnicodeDecodeError) as e:
                    msg = 'Error decoding output using %s - %s'
                    self.queue_write(msg  % (self.encoding, str(e)))
                    break
                except (IOError):
                    if self.killed:
                        msg = 'Cancelled'
                    else:
                        msg = 'Finished'
                    self.queue_write('
    [%s]' % msg)
                    break
    
        def queue_write(self, text):
            sublime.set_timeout(lambda: self.do_write(text), 1)
    
        def do_write(self, text):
            with self.panel_lock:
                self.panel.run_command('append', {'characters': text})
    
    1. 修改第 3 步的那个 Python.sublime-build 文件:
    {
    	"target": "my_py_build",
    	"selector": "source.python",
    	"cancel": {"kill": true}
    }
    
    1. 随便测试一下
      python2
      and
      python3

    2. done!

    3. 有问题请留言

    参考链接:

    1. https://stackoverflow.com/questions/51744019/how-to-open-sublime-package-file
    2. https://stackoverflow.com/questions/41768673/let-sublime-choose-among-two-similar-build-systems
    3. https://www.sublimetext.com/docs/3/build_systems.html
    4. 关于 PYTHONUNBUFFERED
  • 相关阅读:
    protobuf使用遇到的坑
    嵌入式开发入门心得记录
    vim编辑模式下黑色背景,下来过程中出现白条的问题
    linux中awk的应用
    ntp时间同步
    mysql5.5适配
    centos 安装 epel
    ubuntu jdk安装
    add_header Access-Control-Allow-Origin $http_Origin always;
    111
  • 原文地址:https://www.cnblogs.com/hangj/p/13551440.html
Copyright © 2020-2023  润新知