怎么写一个Sublime的插件(3)
现场直播, 和大家一起写一个Sublime的插件.
[TOC]
插件设计思路
我希望这个插件不用太多的快捷键, 就一个F1就可以了.
- F1, 启动插件, 显示时间进度.
- 在番茄时间内, F1切换(显示/隐藏)时间进度.
- 时间到了, 提示一下.
- 启动Sublime的时候, 判断上一个番茄时间是否结束.
- Yes, Pass.
- No, 继续计时.
什么是quick panel?
举个例子:
- super + shift + p # Command Palette
- super + r # Goto Symbol
安装插件, 设置格式, 定位函数, 行数跳转. . .
这些时候, 会出现一个黑色的框, 这个就是quick panel
.sublime-commands
- 在
../packages/Example/
新建一个文件Example.sublime-commands
[
{ "command": "new_tomato", "caption": "Example: New Pomodoro Time" },
{ "command": "show_tomato_progress", "caption": "Example: Show Status" },
{ "command": "hide_tomato_progress", "caption": "Example: Hide Status" },
]
- 修改快捷键.
[
{ "keys": ["f1"], "command": "show_overlay", "args": {"overlay": "command_palette", "text": "Example: "} },
]
通过.sublime-commands
文件, 添加自定义的command命令.
按F1, 打开quick panel, 默认输入文字Example:
.
则会显示上面3条可选项.
super + shift + p, 再输入
Example:
, 效果一样.
插件中对应的写法
class NewTomatoCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.start()
def is_visible(self):
return not tomato.is_actived()
class ShowTomatoProgressCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.set_status_visiable(True)
def is_visible(self):
return tomato.is_actived() and not tomato.get_status_visiable()
class HideTomatoProgressCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.set_status_visiable(False)
def is_visible(self):
return tomato.is_actived() and tomato.get_status_visiable()
Methods: is_visible
Return Value: bool
Description: Returns true if the command should be shown in the menu at this time. The default implementation always returns True.
代码全文
import sublime
import sublime_plugin
import os
import time
DELAY_TIME = 1
DEFAULT_TOMATO_TIME = 25
TICK_INTERVAL = 1
ENDING_WORDS = '快乐的时间总是过得特别快, 又到时间讲bye bye!'
CACHE_FILE_PATH = "/WorkTime.cache"
WORKTIME_SETTINGS = "WorkTime.sublime-settings"
TASK_FILE = "Floyda.wkt"
# ------------------------------------------------------------------------------
# Setting
# ------------------------------------------------------------------------------
class WorkTimeDo():
def __init__(self):
self.settings = sublime.load_settings(WORKTIME_SETTINGS)
self.filename = sublime.packages_path() + CACHE_FILE_PATH
def get_config(self, key, default):
return self.settings.get(key,default)
def say_ending(self):
if sublime.platform() == "osx":
os.popen('say ' + ENDING_WORDS)
def save_time(self, time = None):
try:
fp = open(self.filename, "w+")
fp.write(time)
fp.close()
except:
sublime.error_message("Cann't save current time to local.")
def load_time(self):
try:
fp = open(self.filename)
time = fp.read()
fp.close()
return time
except:
fp = open(self.filename, "w+")
fp.close()
return None
def clear_time(self):
self.save_time('')
# ------------------------------------------------------------------------------
# Tomato
# ------------------------------------------------------------------------------
class Tomato(WorkTimeDo):
def __init__(self):
super(Tomato, self).__init__()
self.total_time = self.get_config("tomato_time", DEFAULT_TOMATO_TIME) * 60
self.counter = 0
self.actived = False
self.status_visiable = True
self.check_last_time()
def start(self, start_time = 0):
self.counter = start_time
self.actived = True
# self.total_time = self.get_config("tomato_time", DEFAULT_TOMATO_TIME) * 60
# self.total_time = 10
self.save_time(str(time.time()))
def stop(self):
self.counter = 0
self.actived = False
self.clear_time()
self.say_ending()
sublime.message_dialog("Have a rest!")
def update(self):
self.counter += 1
self.show_progress()
if self.counter >= self.total_time:
self.stop()
def is_actived(self):
return self.actived
def set_status_visiable(self, flag):
self.status_visiable = flag
self.show_progress()
def get_status_visiable(self):
return self.status_visiable
def show_progress(self):
if self.status_visiable is False:
sublime.status_message('')
return
progress = int(self.counter / self.total_time * 100)
msg = "|" + \
progress * "-" + \
"o" + \
(100 - progress) * "-" + \
"|"
sublime.status_message(msg)
def check_last_time(self):
last_time = self.load_time()
try:
last_time = float(last_time)
except:
self.clear_time()
return
cur_time = time.time()
result = cur_time - last_time
if result >= self.total_time:
self.clear_time()
else:
self.start(int(result))
class Tick():
def __init__(self):
self.thread_flag = False
def callback(self):
if not self.thread_flag: return
if tomato.is_actived():
tomato.update()
sublime.set_timeout_async(self.callback, 1000)
def start(self):
self.thread_flag = True
self.callback()
def stop(self):
self.thread_flag = False
def delay():
global tomato
global tick
tomato = Tomato()
tick = Tick()
tick.start()
sublime.set_timeout_async(lambda:delay(), DELAY_TIME * 1000)
# ------------------------------------------------------------------------------
# Sublime Plugin
# ------------------------------------------------------------------------------
class NewTomatoCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.start()
def is_visible(self):
return not tomato.is_actived()
class ShowTomatoProgressCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.set_status_visiable(True)
def is_visible(self):
return tomato.is_actived() and not tomato.get_status_visiable()
class HideTomatoProgressCommand(sublime_plugin.TextCommand):
def run(self, edit):
tomato.set_status_visiable(False)
def is_visible(self):
return tomato.is_actived() and tomato.get_status_visiable()
-- Floyda --
因为边写插件, 边写Blog, 进度不一样, 很难把Blog中的代码精简.
将就着看吧-_-!!!