zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    PHP 使用 GET 传递数组变量
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 数据交换
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 景点游览
    Java实现 蓝桥杯 算法训练 二进制数数
    Java实现 蓝桥杯 算法训练 二进制数数
    Java实现 蓝桥杯 算法训练 二进制数数
  • 原文地址:https://www.cnblogs.com/hangj/p/13551440.html
Copyright © 2011-2022 走看看