├── README.md └── fmz.py /README.md: -------------------------------------------------------------------------------- 1 | FMZ - Sublime Plugin 2 | ================== 3 | 4 | 使用此插件Sublime可以同步本地编辑的策略到FMZ服务器上 5 | 6 | ### 安装方法 7 | 8 | > 第一种方法: 9 | 10 | 直接克隆当前仓库到 Sublime Text 2/3 packages directory. 11 | 12 | ```bash 13 | git clone https://github.com/fmzquant/SublimeFMZ.git 14 | ``` 15 | 16 | > 第二种方法: 17 | 18 | 下载zip文件并直接解压到 Sublime Text 2/3 packages directory. 19 | 20 | > 说明 21 | 22 | 插件目录在这里打开: Preferences > Browse Packages. 23 | 24 | ### 使用方法 25 | 26 | 当你用Sublime保存带有token标识的策略源文件时, 该源文件会自动同步上传到FMZ服务器 27 | 28 | -------------------------------------------------------------------------------- /fmz.py: -------------------------------------------------------------------------------- 1 | 2 | # -*- coding:utf-8 -*- 3 | import sys 4 | 5 | import socket 6 | socket.setdefaulttimeout(20) 7 | 8 | import sublime, sublime_plugin 9 | import time, os, re 10 | import json 11 | 12 | try: 13 | from urllib import urlencode 14 | from urllib2 import Request, urlopen 15 | reload(sys) 16 | sys.setdefaultencoding('utf8') 17 | except ImportError: 18 | from urllib.request import Request, urlopen 19 | from urllib.parse import urlencode 20 | 21 | pattern = re.compile(r'fmz@([a-zA-Z0-9]{32})') 22 | 23 | token_region = 'fmz_token' 24 | __version__ = '0.0.2' 25 | buf_cache = {} 26 | 27 | def getToken(view): 28 | syntax = view.settings().get("syntax") 29 | if 'JavaScript' not in syntax and 'Python' not in syntax and 'C++' not in syntax and 'Text' not in syntax and 'Pine' not in syntax: 30 | return (None, None) 31 | view.erase_regions(token_region) 32 | content = view.substr(sublime.Region(0, view.size())) 33 | pos = view.find("^[ \t]*(//|#)\s*fmz@[a-zA-Z0-9]{32}[ \t]*$", 0) 34 | if pos: 35 | match = pattern.search(view.substr(pos)) 36 | if not match: 37 | sublime.error_message("Invalid sync token !") 38 | else: 39 | view.add_regions(token_region, [pos], 'keyword', 'dot', sublime.HIDDEN) 40 | view.set_status("quant", "sync plugin loaded") 41 | content, number = re.subn("(//|#)\s*fmz@[a-zA-Z0-9]{32}\s*",'',content) 42 | return (match.group(1), content) 43 | 44 | 45 | view.erase_status("fmz") 46 | return (None, None) 47 | 48 | def SyncFile(filename, token, content): 49 | success = False 50 | errCode = 0 51 | rsync_url = "https://www.fmz.com/rsync" 52 | name = 'FMZ' 53 | if token[0] == 'n': 54 | rsync_url = "https://www.youquant.com/rsync" 55 | name = 'YouQuant' 56 | sublime.status_message(name + " is Sync changed ....") 57 | msg = "" 58 | try: 59 | data = {'token': token, 'method':'push', 'content': content, 'version': __version__, 'client': 'sublime ' + sublime.version()} 60 | req = Request(rsync_url) 61 | req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0') 62 | resp = json.loads(urlopen(req, urlencode(data).encode('utf8')).read().decode('utf8')) 63 | errCode = resp["code"] 64 | if errCode < 100: 65 | success = True 66 | msg = 'Hi ' + resp['user'] + ", sync success !\n\n[" + filename + "] saved to [" + resp['name'] + "]" 67 | sublime.status_message(msg) 68 | sublime.message_dialog(msg) 69 | else: 70 | if errCode == 405: 71 | msg = 'Sorry, ' + resp['user'] + ", sync failed !\n\nRenew the token of [" + resp['name'] + "]" 72 | elif errCode == 406: 73 | msg = 'plugin for sublime need update !' 74 | else: 75 | msg = "sync [" + filename + " ] failed, errCode: %d\n\nMay be the token is not correct !" % errCode 76 | 77 | except: 78 | msg = str(sys.exc_info()[1]) + "\n\sync failed, please retry again !" 79 | 80 | if not success: 81 | sublime.status_message(msg) 82 | sublime.error_message(msg) 83 | return success 84 | 85 | class SaveOnModifiedListener(sublime_plugin.EventListener): 86 | def on_load(self, view): 87 | self.token = '' 88 | if getToken(view): 89 | sublime.status_message("sync plugin ready .") 90 | 91 | def on_post_save(self, view): 92 | token, content = getToken(view) 93 | if not token: 94 | return 95 | rawContent = view.substr(sublime.Region(0, view.size())) 96 | if buf_cache.get(token) == rawContent: 97 | sublime.error_message("sync abort because file not changed !") 98 | return 99 | 100 | file_name = os.path.basename(view.file_name()) 101 | if SyncFile(file_name, token, content): 102 | buf_cache[token] = rawContent 103 | --------------------------------------------------------------------------------