diff --git a/Sublime/fl0w/CompileHighlight.sublime-syntax b/Sublime/fl0w/CompileHighlight.sublime-syntax deleted file mode 100644 index 3e997dc..0000000 --- a/Sublime/fl0w/CompileHighlight.sublime-syntax +++ /dev/null @@ -1,11 +0,0 @@ -%YAML 1.2 ---- -# http://www.sublimetext.com/docs/3/syntax.html -name: Compile Highlight -file_extensions: [] -hidden: true -scope: source.inspect -contexts: - main: - - match: \b(warning|error)\b - scope: keyword.control.c \ No newline at end of file diff --git a/Sublime/fl0w/Default (Linux).sublime-keymap b/Sublime/fl0w/Default (Linux).sublime-keymap deleted file mode 100644 index 00b52dc..0000000 --- a/Sublime/fl0w/Default (Linux).sublime-keymap +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "keys" : ["f8"], - "command" : "run" - }, - { - "keys" : ["f9"], - "command" : "stop" - }, - { - "keys" : ["f10"], - "command" : "sensor" - } -] \ No newline at end of file diff --git a/Sublime/fl0w/Default (OSX).sublime-keymap b/Sublime/fl0w/Default (OSX).sublime-keymap deleted file mode 100644 index 00b52dc..0000000 --- a/Sublime/fl0w/Default (OSX).sublime-keymap +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "keys" : ["f8"], - "command" : "run" - }, - { - "keys" : ["f9"], - "command" : "stop" - }, - { - "keys" : ["f10"], - "command" : "sensor" - } -] \ No newline at end of file diff --git a/Sublime/fl0w/Default (Windows).sublime-keymap b/Sublime/fl0w/Default (Windows).sublime-keymap deleted file mode 100644 index 00b52dc..0000000 --- a/Sublime/fl0w/Default (Windows).sublime-keymap +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "keys" : ["f8"], - "command" : "run" - }, - { - "keys" : ["f9"], - "command" : "stop" - }, - { - "keys" : ["f10"], - "command" : "sensor" - } -] \ No newline at end of file diff --git a/Sublime/fl0w/Shared b/Sublime/fl0w/Shared deleted file mode 120000 index 8c1ab6a..0000000 --- a/Sublime/fl0w/Shared +++ /dev/null @@ -1 +0,0 @@ -../../Shared \ No newline at end of file diff --git a/Sublime/fl0w/SublimeMenu.py b/Sublime/fl0w/SublimeMenu.py deleted file mode 100644 index 8ff2c59..0000000 --- a/Sublime/fl0w/SublimeMenu.py +++ /dev/null @@ -1,140 +0,0 @@ -FUNCTION = type(lambda: 1) - -class Input: - def __init__(self, caption, initial_text="", on_done=None, on_change=None, - on_cancel=None, kwargs={}): - self.caption = caption - self.initial_text = initial_text - self.on_done = on_done - self.on_change = on_change - self.on_cancel = on_cancel - self.kwargs = kwargs - - - def wrapped_on_done(self, input_): - if not self.on_done == None: - self.on_done(input_, **self.kwargs) - - - def wrapped_on_change(self, input_): - if not self.on_change == None: - self.on_change(input_, **self.kwargs) - - - def wrapped_on_cancel(self): - if not self.on_cancel == None: - self.on_cancel(**self.kwargs) - - - def invoke(self, window): - window.show_input_panel(self.caption, self.initial_text, - self.wrapped_on_done, self.wrapped_on_change, - self.wrapped_on_cancel) - - -class Entry: - def __init__(self, name, description="", action=None, kwargs={}, - sub_menu=None, input=None): - self.name = name - self.description = description - self.action = action - self.kwargs = kwargs - self.sub_menu = sub_menu - self.input = input - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - -class Menu: - def __init__(self, selected_index=-1, on_highlight=None, subtitles=True): - self.selected_index = selected_index - self.on_highlight = on_highlight - self.subtitles = subtitles - self.entries = {} - self.window = None - self.back = None - - def invoke(self, window, back=None): - self.window = window - self.back = back - entries = self.menu_entries - if back: - entries.insert(0, ["Back", - "Back to previous menu"] if self.subtitles else ["Back"]) - window.show_quick_panel(entries, self._action, - flags=0, selected_index=self.selected_index, - on_highlight=self.on_highlight) - - def _action(self, entry_id): - if entry_id != -1: - if self.back: - if entry_id != 0: - entry = self.entries[entry_id - 1] - else: - self.back.invoke(self.window, back=self.back.back) - return - else: - entry = self.entries[entry_id] - if entry.action != None: - entry.action(**entry.kwargs) - if entry.input != None: - entry.input.invoke(self.window) - if type(entry.sub_menu) is FUNCTION: - entry.sub_menu(entry).invoke(self.window, back=self) - elif entry.sub_menu != None: - entry.sub_menu.invoke(self.window, back=self) - - - @property - def menu_entries(self): - entries = [] - for entry_id in self.entries: - if self.subtitles: - entries.append([self.entries[entry_id].name, self.entries[entry_id].description]) - else: - entries.append([self.entries[entry_id].name]) - return entries - - - def __add__(self, other): - try: - self.add(other) - except TypeError: - return NotImplemented - return self - - - def __sub__(self, other): - try: - self.remove(other) - except TypeError: - return NotImplemented - return self - - - def add(self, entry): - if entry.__class__ == Entry: - if len(self.entries) > 0: - entry_id = tuple(self.entries.keys())[-1] + 1 - else: - entry_id = 0 - self.entries[entry_id] = entry - else: - raise TypeError("invalid type supplied") - - - def remove(self, entry): - if entry.__class__ == Entry: - if entry in self.entries.values(): - found_entry_id = None - for entry_id in self.entries: - if self.entries[entry_id] == entry: - found_entry_id = entry_id - if found_entry_id != None: - del self.entries[entry_id] - else: - raise TypeError("invalid type supplied") - - def clear(self): - self.entries = {} diff --git a/Sublime/fl0w/fl0w.py b/Sublime/fl0w/fl0w.py deleted file mode 100644 index 1250eef..0000000 --- a/Sublime/fl0w/fl0w.py +++ /dev/null @@ -1,756 +0,0 @@ -from sys import path -import os -from time import strftime -from functools import partial -import re - -fl0w_path = os.path.dirname(os.path.realpath(__file__)) -shared_path = os.path.dirname(os.path.realpath(__file__)) + "/Shared/" -if fl0w_path not in path: - path.append(fl0w_path) -if shared_path not in path: - path.append(shared_path) - - -import sublime -import sublime_plugin - -from Highway import Client, Route, Pipe, DummyPipe -from Utils import get_hostname, get_ip_from_url - -import behem0th - -from SublimeMenu import * -import Logging - -import webbrowser -import threading -from time import sleep -import os - -CHANNEL = 1 -FL0W_STATUS = "fl0w" - -def plugin_unloaded(): - for window in windows: - if hasattr(window, "fl0w") and window.fl0w.connected: - window.fl0w.invoke_disconnect() - for sensor_type in ("analog", "digital"): - window.active_view().erase_phantoms(sensor_type) - - -PARENTHESES_REGEX = re.compile("\((.*?)\)") -STYLE_OPEN = "
"
-STYLE_CLOSE = "
"
-
-ERROR_OPEN = ""
-ERROR_CLOSE = "
"
-
-windows = []
-views = []
-sensor_phantoms = []
-
-def set_status(status, window):
- window.active_view().set_status(FL0W_STATUS,
- "fl0w: %s" % status)
-
-class Target:
- def __init__(self, id_, name):
- self.id = id_
- self.name = name
-
-
-class Fl0wClient(Client):
- def setup(self, routes, fl0w, debug=False):
- super().setup(routes, debug=debug)
- self.fl0w = fl0w
-
-
- def ready(self):
- self.fl0w.connected = True
- if self.fl0w.debug:
- Logging.info("Connection ready!")
- # Enlist on editor channel
- self.send({"channel" : CHANNEL, "name" : get_hostname()}, "subscribe")
- # Subscribe to controller channel
- self.send({"subscribe" : [2]}, "peers")
-
-
- def closed(self, code, reason):
- self.fl0w.invoke_disconnect()
- if self.fl0w.debug:
- Logging.info("Connection closed: %s (%s)" % (reason, code))
-
-
- def peer_unavaliable(self, peer):
- sublime.error_message("The specifed controller is not connected anymore.")
- if self.fl0w.target.id == peer:
- self.fl0w.target = None
-
-
- class Info(Route):
- def run(self, data, handler):
- info = ""
- for key in data:
- info += "%s: %s\n" % (key.capitalize(), ", ".join(data[key]))
- sublime.message_dialog(info)
- handler.fl0w.meta.invoke(handler.fl0w.window, back=handler.fl0w.main_menu)
-
-
- class Sensor(Pipe):
- def run(self, data, peer, handler):
- handler.fl0w.subscriptions_lock.acquire()
- for sensor_phantom in handler.fl0w.subscriptions:
- sensor_phantom.update_sensor_values(data)
- handler.fl0w.subscriptions_lock.release()
-
-
- class Peers(Route):
- def start(self, handler):
- self.selected_action_menu = None
-
- def run(self, data, handler):
- handler.fl0w.controller_menu.clear()
- if handler.fl0w.target != None:
- if not handler.fl0w.target.id in data:
- handler.fl0w.target = None
- for id_ in data:
- action_menu = Menu()
- power_menu = Menu()
- utilities_menu = Menu()
- action_menu.id_ = id_
- action_menu.name = data[id_]["name"]
- action_menu += Entry("Set Target",
- "Set controller as target for program execution and sensor readouts",
- action=partial(self.set_target,
- handler, id_, data[id_]["name"]))
- action_menu += Entry("Run program",
- "Run a botball program on the controller",
- action=partial(handler.pipe, None, "list_programs", id_))
- action_menu += Entry("Stop programs",
- "Stop all currently running botball programs",
- action=partial(handler.pipe, None, "stop_programs", id_))
- utilities_menu += Entry("Set Name",
- "Sets the hostname of the selected controller",
- action=partial(lambda handler, id_: Input("New Hostname:",
- initial_text=data[id_]["name"],
- on_done=lambda hostname: handler.pipe(
- {"set" : hostname},
- "hostname", id_)).invoke(handler.fl0w.window), handler, id_))
- utilities_menu += Entry("Processes",
- "Lists processes currently running on controller",
- action=partial(handler.pipe, None, "processes", id_))
- utilities_menu += Entry("Identify",
- "Plays an identification sound on the controller.",
- action=partial(handler.pipe, None, "identify", id_))
- action_menu += Entry("Utilities", "Stuff you might need but probably won't",
- sub_menu=utilities_menu)
- power_menu += Entry("Shutdown",
- "Shutdown the controller",
- action=partial(handler.pipe, None, "shutdown", id_))
- power_menu += Entry("Reboot",
- "Reboot the controller",
- action=partial(handler.pipe, None, "reboot", id_))
- action_menu += Entry("Power", "Power related actions", sub_menu=power_menu)
- action_menu.back = handler.fl0w.controller_menu
- handler.fl0w.controller_menu += Entry(data[id_]["name"], id_, sub_menu=action_menu,
- action=self.set_selected_action_menu,
- kwargs={"selected_action_menu" : action_menu})
-
-
- def set_target(self, handler, peer, name):
- handler.fl0w.target = Target(peer, name)
- if handler.fl0w.debug:
- set_status("Target: %s" % peer, handler.fl0w.window)
-
-
- def set_selected_action_menu(self, selected_action_menu):
- self.selected_action_menu = selected_action_menu
-
-
- class Processes(Pipe):
- def run(self, data, peer, handler):
- view = handler.fl0w.window.new_file()
- view.set_name("Processes")
- view.settings().set("draw_indent_guides", False)
- for line in data:
- view.run_command("append", {"characters": line + "\n"})
- view.set_read_only(True)
-
-
- class ListPrograms(Pipe):
- def run(self, data, peer, handler):
- program_menu = Menu(subtitles=False)
- for program in data:
- program_menu += Entry(program,
- action=partial(self.run_program,
- handler, handler.routes["peers"].selected_action_menu.id_,
- program))
- program_menu.invoke(handler.fl0w.window,
- back=handler.routes["peers"].selected_action_menu)
-
- def run_program(self, handler, id_, program):
- handler.pipe(program, "run_program", id_)
-
-
- class RunProgram(Pipe):
- PROGRAM_NOT_FOUND = 1
-
- def run(self, data, peer, handler):
- if data == self.__class__.PROGRAM_NOT_FOUND:
- sublime.error_message("Program not found.")
-
-
- class StopPrograms(Pipe):
- NO_PROGRAMS_RUNNING = 1
-
- def run(self, data, peer, handler):
- if data == self.__class__.NO_PROGRAMS_RUNNING:
- sublime.error_message("No programs running.")
-
-
- class StdStream(Pipe):
- def start(self, handler):
- self.output_panels = {}
-
- self.lock = threading.RLock()
- self.buffer = {}
-
- self.handler = None
-
- self.fetcher = self.Fetcher(self.buffer, self.write_to_panel,
- self.lock)
- self.fetcher.start()
-
-
- def create_output_panel(self, window, peer):
- view = window.create_output_panel(peer)
- view.settings().set("draw_white_space", False)
- view.settings().set("draw_indent_guides", False)
- view.settings().set("gutter", False)
- view.settings().set("line_numbers", False)
- view.set_read_only(True)
- return view
-
-
- def run(self, data, peer, handler):
- self.handler = handler
- if type(data) is str:
- self.lock.acquire()
- # try/except is faster than an explicit if as long as the
- # condition is not met
- try:
- self.buffer[peer].append(data)
- except KeyError:
- self.buffer[peer] = []
- self.create_output_panel(handler.fl0w.window, peer)
- self.output_panels[peer] = self.create_output_panel(handler.fl0w.window, peer)
- self.buffer[peer].append(data)
- self.lock.release()
- # Meta info comes in so infrequently that the conditional logic would
- # slow down the regular output streaming
- elif type(data) is dict:
- meta_text = ""
- if "exit_code" in data:
- meta_text += "Program finished with exit code: %d\n" % data["exit_code"]
- self.lock.acquire()
- # try/except is faster than an explicit if as long as the
- # condition is not met
- # function call is also slower
- try:
- self.buffer[peer].append(meta_text)
- except KeyError:
- self.buffer[peer] = []
- self.create_output_panel(handler.fl0w.window, peer)
- self.output_panels[peer] = self.create_output_panel(handler.fl0w.window, peer)
- self.buffer[peer].append(meta_text)
- self.lock.release()
-
-
-
- def write_to_panel(self, text, peer):
- self.output_panels[peer].set_read_only(False)
- self.output_panels[peer].run_command("append", {"characters": text, "scroll_to_end" : True})
- self.output_panels[peer].set_read_only(True)
- self.handler.fl0w.window.run_command("show_panel", {"panel": "output.%s" % peer})
-
-
- # Sublime gets quite overwhelmed when faced with typical
- # "while (1) { printf(...)}" output.
- # That's why instead of directly writing to the view all received text
- # is bundled together after a fixed period of time.
- class Fetcher(threading.Thread):
- def __init__(self, buffer, write_to_panel, lock, push_rate=0.2):
- threading.Thread.__init__(self)
- self.buffer = buffer
- self.write_to_panel = write_to_panel
- self.lock = lock
- self.push_rate = push_rate
- self.daemon = True
-
- def run(self):
- while True:
- self.lock.acquire()
- for peer in self.buffer:
- if len(self.buffer[peer]) > 0:
- self.write_to_panel(
- "".join(self.buffer[peer]),
- peer)
- self.buffer[peer] = []
- self.lock.release()
- sleep(self.push_rate)
-
-
-class Fl0w:
- def __init__(self, window, debug=False):
- self.settings = sublime.load_settings("fl0w.sublime-settings")
- self.window = window
- self.folder = window.folders()[0]
- if self.folder != "/":
- self.folder = self.folder + "/"
-
- self.connected = False
-
- self.subscriptions = {}
- self.subscriptions_lock = threading.Lock()
- self._combined_subscriptions = {"analog" : [], "digital" : []}
-
- self._target = None
- self._debug = debug
-
-
- self.start_menu = Menu()
- self.start_menu += Entry("Connect", "Connect to a fl0w server",
- action=partial(Input("Address:Port (auto-connect nyi)",
- initial_text=self.settings.get("address", "127.0.0.1:3077"),
- on_done=self.invoke_connect).invoke, self.window))
- self.start_menu += Entry("About", "Information about fl0w",
- action=self.invoke_about)
-
- self.debug_menu = Menu(subtitles=False)
- self.debug_menu += Entry("On",
- action=lambda: self.set_debug(True))
- self.debug_menu += Entry("Off",
- action=lambda: self.set_debug(False))
-
-
- self.settings_menu = Menu()
- self.settings_menu += Entry("Debug", "Toggle debug mode",
- sub_menu=self.debug_menu)
-
-
- self.meta = Menu()
- self.meta += Entry("Info", "Server info",
- action=lambda: self.ws.send(None, "info"))
- self.meta_entry = Entry("Meta", "Debug information about fl0w",
- sub_menu=self.meta)
- if self.debug:
- self.main_menu += self.meta_entry
-
-
- self.main_menu = Menu()
- self.controller_menu = Menu()
- self.main_menu += Entry("Controllers", "All connected controllers",
- sub_menu=self.controller_menu)
- self.main_menu += Entry("Settings", "General purpose settings",
- sub_menu=self.settings_menu)
- self.main_menu += Entry("Disconnect", "Disconnect from server",
- action=self.invoke_disconnect)
-
- self.sync_client = behem0th.Client(path=self.folder, verbose_log=True)
-
- # Patch all sensor phantom that have been created before a fl0w instance
- # was attached to the window
- for sensor_phantom in sensor_phantoms:
- if sensor_phantom.window.id() == self.window.id():
- sensor_phantom.fl0w = self
- if self.debug:
- Logging.info("Patched sensor phantom '%s'" % str(sensor_phatom))
-
-
- @property
- def target(self):
- return self._target
-
-
- @target.setter
- def target(self, target):
- if self.target != None:
- self.ws.pipe("unsubscribe", "sensor", self.target.id)
- self._target = target
- if target != None:
- set_status("Target: %s (%s)" % (target.name, target.id), self.window)
- if self.combined_subscriptions != {"analog" : [], "digital" : []}:
- self.ws.pipe({"subscribe" : self.combined_subscriptions}, "sensor", target.id)
- else:
- set_status("The target has become unavaliable.", self.window)
-
-
- @property
- def debug(self):
- return self._debug
-
-
- def set_debug(self, debug):
- self.debug = debug
-
-
- @debug.setter
- def debug(self, debug):
- if debug:
- self._debug = True
- if not self.meta_entry in self.main_menu.entries.values():
- self.main_menu += self.meta_entry
- else:
- self._debug = False
- self.main_menu -= self.meta_entry
- set_status("Debug set to %s" % self._debug, self.window)
-
-
- # Could be simplified because only one view can be active at any time.
- # This would definetly lead to some major performace improvements on
- # view switching and less unnecessary unsubscribes.
-
- # On the other hand it might be a good idea to leave it in and provide
- # an option to disable aggressive unsubscribes
- @property
- def combined_subscriptions(self):
- return self._combined_subscriptions
-
-
- @combined_subscriptions.setter
- def combined_subscriptions(self, combined_subscriptions_):
- if self.combined_subscriptions != combined_subscriptions_:
- self._combined_subscriptions = combined_subscriptions_
- if self.connected and self.target != None:
- self.ws.pipe("unsubscribe", "sensor", self.target.id)
- if combined_subscriptions_ != {"analog" : [], "digital" : []}:
- self.ws.pipe({"subscribe" : combined_subscriptions_}, "sensor",
- self.target.id)
-
-
- def subscribe(self, sensor_phatom, subscriptions):
- self.subscriptions_lock.acquire()
- self.subscriptions[sensor_phatom] = subscriptions
- self.subscriptions_lock.release()
- self.make_subscriptions()
-
-
-
- def unsubscribe(self, sensor_phantom):
- if sensor_phantom in self.subscriptions:
- """
- print("Lock will be aquired.")
- self.subscriptions_lock.acquire()
- print("Lock was aquired.")
- del self.subscriptions[sensor_phantom]
- print("Lock will be released.")
- self.subscriptions_lock.release()
- print("Lock was released.")
- """
- # Temporary solution, locking caused sublime to freeze
- # Could cause problems if lots (> 100) views are open.
- self.subscriptions[sensor_phantom] = {"analog" : [], "digital" : []}
- self.make_subscriptions()
-
-
- def make_subscriptions(self):
- combined_subscriptions = {"analog" : [], "digital" : []}
- for sensor_phantom in self.subscriptions:
- for sensor_type in ("analog", "digital"):
- combined_subscriptions[sensor_type] = list(
- set(combined_subscriptions[sensor_type]) |
- set(self.subscriptions[sensor_phantom][sensor_type])
- )
- self.combined_subscriptions = combined_subscriptions
-
-
- def run_program(self, path):
- if self.connected and self.target != None:
- relpath = os.path.relpath(path, self.folder)
- if os.path.isfile(self.folder + relpath):
- if self.debug:
- Logging.info("Running program '%s'" % relpath)
- self.ws.pipe(relpath.rstrip(".c"), "run_program", self.target.id)
-
-
- def stop_programs(self):
- if self.connected and self.target != None:
- self.ws.pipe(None, "stop_programs", self.target.id)
-
-
- def invoke_start_menu(self):
- self.start_menu.invoke(self.window)
-
-
- def invoke_main_menu(self):
- self.main_menu.invoke(self.window)
-
-
- def invoke_about(self):
- if sublime.ok_cancel_dialog("fl0w by @robot0nfire", "robot0nfire.com"):
- webbrowser.open("http://robot0nfire.com")
-
-
- def connect(self, address):
- try:
- self.ws = Fl0wClient(address)
- self.ws.setup({"info" : Fl0wClient.Info(), "peers" : Fl0wClient.Peers(),
- "processes" : Fl0wClient.Processes(),
- "list_programs" : Fl0wClient.ListPrograms(), "sensor" : Fl0wClient.Sensor(),
- "std_stream" : Fl0wClient.StdStream(), "run_program" : Fl0wClient.RunProgram(),
- "stop_programs" : Fl0wClient.StopPrograms()},
- self, debug=True)
- self.ws.connect()
- sublime.set_timeout_async(self.ws.run_forever, 0)
- set_status("Connection opened '%s'" % self.folder, self.window)
- self.connected = True
- self.settings.set("address", address)
- self.sync_client.connect(get_ip_from_url(address))
-
- except (OSError, ConnectionRefusedError) as e:
- sublime.error_message("Error during connection creation:\n %s" % str(e))
-
-
-
- def invoke_connect(self, address):
- # Will be removed once autoconnect works
- self.connect("ws://%s" % address)
-
-
- def invoke_disconnect(self):
- if self.connected:
- for sensor_phantom in sensor_phantoms:
- if sensor_phantom.window.id() == self.window.id():
- sensor_phantom.enabled = False
- self.target = None
- self.ws.close()
- set_status("Connection closed '%s'" % self.folder, self.window)
- self.connected = False
-
- self.sync_client.close()
-
-
-class Fl0wCommand(sublime_plugin.WindowCommand):
- def run(self):
- valid_window_setup = True
- folder_count = len(self.window.folders())
- if folder_count > 1:
- sublime.error_message("Only one open folder per window is allowed.")
- valid_window_setup = False
- elif folder_count == 0:
- sublime.error_message("No folder open in window.")
- valid_window_setup = False
- if valid_window_setup:
- if not hasattr(self.window, "fl0w"):
- folder = self.window.folders()[0]
- files = os.listdir(folder)
- if not ".no-fl0w" in files:
- if not ".fl0w" in files:
- open(folder + "/.fl0w", 'a').close()
- self.window.fl0w = Fl0w(self.window)
- windows.append(self.window)
- self.window.fl0w.start_menu.invoke(self.window)
- else:
- self.window.fl0w = Fl0w(self.window)
- windows.append(self.window)
- self.window.fl0w.start_menu.invoke(self.window)
- else:
- sublime.error_message("fl0w can't be opened in your current directory (.no-fl0w file exists)")
- else:
- if not self.window.fl0w.connected:
- self.window.fl0w.invoke_start_menu()
- else:
- self.window.fl0w.invoke_main_menu()
- else:
- if hasattr(self.window, "fl0w"):
- sublime.error_message("Window setup was invalidated (Don't close or open any additional folders in a fl0w window)")
- self.window.fl0w.invoke_disconnect()
-
-
-class RunCommand(sublime_plugin.WindowCommand):
- def run(self):
- if hasattr(self.window, "fl0w"):
- if self.window.fl0w.connected:
- if self.window.fl0w.target == None:
- sublime.error_message("A target controller has to be set to "
- "run programs.")
- else:
- file_name = self.window.active_view().file_name()
- if file_name != None and file_name.endswith(".c"):
- self.window.fl0w.run_program(file_name)
- else:
- sublime.error_message("fl0w is not connected.")
- else:
- sublime.error_message("fl0w is not running in your current window.")
-
-class StopCommand(sublime_plugin.WindowCommand):
- def run(self):
- if hasattr(self.window, "fl0w"):
- if self.window.fl0w.connected:
- if self.window.fl0w.target == None:
- sublime.error_message("A target controller has to be set to "
- "stop programs.")
- else:
- self.window.fl0w.stop_programs()
- else:
- sublime.error_message("fl0w is not connected.")
- else:
- sublime.error_message("fl0w is not running in your current window.")
-
-
-class SensorCommand(sublime_plugin.WindowCommand):
- def run(self):
- if hasattr(self.window, "fl0w"):
- if self.window.fl0w.connected:
- if self.window.fl0w.target == None:
- sublime.error_message("A target controller has to be set to "
- "enable inline sensor readouts.")
- else:
- view_id = self.window.active_view().id()
- for view in views:
- if view.id() == view_id:
- view.sensor_phantom.enabled = not view.sensor_phantom.enabled
- view_file_name = view.file_name()
- if view_file_name == None:
- view_file_name = "untitled"
- set_status("%s sensor phantoms for '%s'." % (
- "Enabled" if view.sensor_phantom.enabled else "Disabled",
- view_file_name),
- self.window)
- else:
- sublime.error_message("fl0w is not connected.")
- else:
- sublime.error_message("fl0w is not running in your current window.")
-
-
-
-class SensorPhantom(sublime_plugin.ViewEventListener):
- def __init__(self, view):
- self.view = view
- self.view.sensor_phantom = self
- if not view in views:
- views.append(view)
- self.window = view.window()
-
- # Is patched by the fl0w instance that is in control of the same window
- self.fl0w = None
- self._enabled = False
-
- self.previously_enabled = False
-
- self._matches = {"analog" : [], "digital" : []}
-
- self.timeout_scheduled = False
- self.needs_update = False
-
- for window in windows:
- if hasattr(window, "fl0w"):
- self.fl0w = window.fl0w
- if not self in sensor_phantoms:
- sensor_phantoms.append(self)
-
-
- @property
- def enabled(self):
- return self._enabled
-
-
- @enabled.setter
- def enabled(self, enabled_):
- if enabled_:
- if self.fl0w != None:
- self.find_matches()
- self.fl0w.subscribe(self, self.subscriptions)
- self._enabled = True
- else:
- if self.fl0w != None:
- self.fl0w.unsubscribe(self)
- for sensor_type in ("analog", "digital"):
- self.view.erase_phantoms(sensor_type)
- self._enabled = False
-
-
- @property
- def matches(self):
- return self._matches
-
- @matches.setter
- def matches(self, matches_):
- if not matches_ == self.matches:
- self._matches = matches_
- self.fl0w.subscribe(self, self.subscriptions)
-
-
- @property
- def subscriptions(self):
- subscriptions_ = {"analog" : [], "digital" : []}
- for sensor_type in ("analog", "digital"):
- subscriptions_[sensor_type] = [sensor[0] for sensor in self.matches[sensor_type]]
- return subscriptions_
-
-
- def find_matches(self):
- matches = {"analog" : [], "digital" : []}
- # Don't do any calculations on 1MB or larger files
- if self.view.size() < 2**20:
- for method_name in ("analog", "digital"):
- candidates = self.view.find_all("%s\(\d*\)" % method_name)
- for candidate in candidates:
- line = self.view.substr(candidate)
- port_candidates = re.findall(PARENTHESES_REGEX, line)
- if len(port_candidates) == 1:
- if port_candidates[0].isnumeric():
- matches[method_name].append(
- (
- int(port_candidates[0]),
- sublime.Region(self.view.line(candidate.a).b)
- ))
- self.matches = matches
-
- # Called by fl0w instance
- def update_sensor_values(self, readouts):
- for sensor_type in ("analog", "digital"):
- self.view.erase_phantoms(sensor_type)
- for match in self.matches[sensor_type]:
- try:
- self.view.add_phantom(sensor_type, match[1],
- STYLE_OPEN + str(readouts[sensor_type][str(match[0])]) + STYLE_CLOSE,
- sublime.LAYOUT_INLINE)
- except KeyError:
- self.view.add_phantom(sensor_type, match[1],
- ERROR_OPEN + "!" + ERROR_CLOSE,
- sublime.LAYOUT_INLINE)
-
-
- def handle_timeout(self):
- self.timeout_scheduled = False
- if self.needs_update:
- self.needs_update = False
- self.find_matches()
-
-
- def on_modified(self):
- if self.enabled:
- if self.timeout_scheduled:
- self.needs_update = True
- else:
- sublime.set_timeout(lambda: self.handle_timeout(), 500)
- self.find_matches()
-
-
-
- def on_deactivated(self):
- self.previously_enabled = self.enabled
- if self.enabled:
- self.enabled = False
-
- def on_activated(self):
- if not self.enabled and self.previously_enabled:
- self.enabled = True
-
-
- def __del__(self):
- self.enabled = False
- if self in sensor_phantoms:
- del sensor_phantoms[sensor_phantoms.index(self)]
diff --git a/Sublime/fl0w/fl0w.sublime-commands b/Sublime/fl0w/fl0w.sublime-commands
deleted file mode 100644
index a2b89be..0000000
--- a/Sublime/fl0w/fl0w.sublime-commands
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- {
- "caption": "fl0w: Menu",
- "command": "fl0w"
- }
-]
\ No newline at end of file
diff --git a/Sublime/fl0w/fl0w.sublime-settings b/Sublime/fl0w/fl0w.sublime-settings
deleted file mode 100644
index 51a7f3b..0000000
--- a/Sublime/fl0w/fl0w.sublime-settings
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "server_address": "", // Last server address
- "compression_level": 2
-}