From 63bd79bbac79bf188fdddb5f338c8145434ec58e Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 10:58:08 +0200 Subject: [PATCH 01/44] Compile and execute Oz code from python --- oz-plugin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 oz-plugin.py diff --git a/oz-plugin.py b/oz-plugin.py new file mode 100644 index 0000000..26ba568 --- /dev/null +++ b/oz-plugin.py @@ -0,0 +1,18 @@ +import subprocess +from subprocess import PIPE, Popen + +def compile_mozart(file): + process = Popen(['ozc', '-c', file], stdout=PIPE, stderr=PIPE) + stdout, stderr = process.communicate() + process.wait() + outs = stdout.decode('utf-8') + errs = stderr.decode('utf-8') + return [outs, errs] + +def execute_mozart(file): + process = Popen(['ozengine', file], stdout=PIPE, stderr=PIPE) + stdout, stderr = process.communicate() + process.wait() + outs = stdout.decode('utf-8') + errs = stderr.decode('utf-8') + return [outs, errs] From 48f783cf52678c81def4601296839433e14cf953 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 11:22:06 +0200 Subject: [PATCH 02/44] Init structure plugin Command --- oz-plugin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oz-plugin.py b/oz-plugin.py index 26ba568..f4bccc5 100644 --- a/oz-plugin.py +++ b/oz-plugin.py @@ -1,5 +1,7 @@ import subprocess from subprocess import PIPE, Popen +import sublime +import sublime_plugin def compile_mozart(file): process = Popen(['ozc', '-c', file], stdout=PIPE, stderr=PIPE) @@ -16,3 +18,6 @@ def execute_mozart(file): outs = stdout.decode('utf-8') errs = stderr.decode('utf-8') return [outs, errs] + +class OzRunCommand(sublime_plugin.TextCommand): + def run(self, edit): \ No newline at end of file From c799b311b0eedaa075e6238b521e0a8c95dffaa9 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 11:44:55 +0200 Subject: [PATCH 03/44] Enable Compilation and Execution of current file This compilation and execution can be run through view.run_command("oz_run") in Sublime Text Shell --- oz-plugin.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/oz-plugin.py b/oz-plugin.py index f4bccc5..97daf04 100644 --- a/oz-plugin.py +++ b/oz-plugin.py @@ -20,4 +20,13 @@ def execute_mozart(file): return [outs, errs] class OzRunCommand(sublime_plugin.TextCommand): - def run(self, edit): \ No newline at end of file + def run(self, edit): + file = self.view.file_name() + [out_comp, err_comp] = compile_mozart(file) + [out_exec, err_exec] = execute_mozart(file+'f') + print("Compilation Output :") + print(out_comp) + print(err_comp) + print("\nExecution Output : ") + print(out_exec) + print(err_exec) \ No newline at end of file From d613c3122ddebbde9033e15bc1511c022c160b62 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 13:58:17 +0200 Subject: [PATCH 04/44] Show compilation/execution on new panel --- oz-plugin.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/oz-plugin.py b/oz-plugin.py index 97daf04..cdfd60a 100644 --- a/oz-plugin.py +++ b/oz-plugin.py @@ -24,9 +24,17 @@ def run(self, edit): file = self.view.file_name() [out_comp, err_comp] = compile_mozart(file) [out_exec, err_exec] = execute_mozart(file+'f') - print("Compilation Output :") - print(out_comp) - print(err_comp) - print("\nExecution Output : ") - print(out_exec) - print(err_exec) \ No newline at end of file + window = sublime.active_window() + panel = window.find_output_panel('oz_panel') + if(panel == None): + panel = window.create_output_panel('oz_panel') + panel.set_read_only(False) + panel.run_command("append", {"characters": "Compilation output :\n"}) + panel.run_command("append", {"characters": out_comp+"\n"+err_comp+"\n"}) + panel.run_command("append", {"characters": "Execution output:\n"}) + panel.run_command("append", {"characters": out_exec+"\n"+err_exec+"\n"}) + panel.set_read_only(True) + window.run_command('show_panel', {'panel':'output.oz_panel'}) + def is_visible(self): + print(self.view.window().active_panel()) + return True \ No newline at end of file From 6f52d19c9e5aed4c96d835070ebeef71d7f50605 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 14:47:28 +0200 Subject: [PATCH 05/44] Check if compilation fails --- oz-plugin.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/oz-plugin.py b/oz-plugin.py index cdfd60a..1f95128 100644 --- a/oz-plugin.py +++ b/oz-plugin.py @@ -7,9 +7,10 @@ def compile_mozart(file): process = Popen(['ozc', '-c', file], stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() process.wait() + return_code = process.poll() outs = stdout.decode('utf-8') errs = stderr.decode('utf-8') - return [outs, errs] + return [outs, errs, return_code] def execute_mozart(file): process = Popen(['ozengine', file], stdout=PIPE, stderr=PIPE) @@ -22,19 +23,21 @@ def execute_mozart(file): class OzRunCommand(sublime_plugin.TextCommand): def run(self, edit): file = self.view.file_name() - [out_comp, err_comp] = compile_mozart(file) - [out_exec, err_exec] = execute_mozart(file+'f') + co = compile_mozart(file) + [out_comp, err_comp, code_comp] = compile_mozart(file) window = sublime.active_window() panel = window.find_output_panel('oz_panel') if(panel == None): panel = window.create_output_panel('oz_panel') + window.run_command('show_panel', {'panel':'output.oz_panel'}) panel.set_read_only(False) panel.run_command("append", {"characters": "Compilation output :\n"}) panel.run_command("append", {"characters": out_comp+"\n"+err_comp+"\n"}) - panel.run_command("append", {"characters": "Execution output:\n"}) - panel.run_command("append", {"characters": out_exec+"\n"+err_exec+"\n"}) + if(code_comp == 0): + [out_exec, err_exec] = execute_mozart(file+'f') + panel.run_command("append", {"characters": "Execution output:\n"}) + panel.run_command("append", {"characters": out_exec+"\n"+err_exec+"\n"}) panel.set_read_only(True) - window.run_command('show_panel', {'panel':'output.oz_panel'}) def is_visible(self): print(self.view.window().active_panel()) return True \ No newline at end of file From 8b255804a489ce8dfcbb4b3a057abdf929c899ee Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 27 Aug 2018 15:33:37 +0200 Subject: [PATCH 06/44] Create Shortcut to oz_run --- Default.sublime-keymap | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Default.sublime-keymap diff --git a/Default.sublime-keymap b/Default.sublime-keymap new file mode 100644 index 0000000..242fdf4 --- /dev/null +++ b/Default.sublime-keymap @@ -0,0 +1,3 @@ +[ + { "keys": ["ctrl+b", "b"], "command": "oz_run"} +] From 8e082ad23256730b2846ee1a14e204120d69f907 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 12:54:44 +0200 Subject: [PATCH 07/44] Rename command OzRun->OzCompile --- oz-plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oz-plugin.py b/oz-plugin.py index 1f95128..a34831c 100644 --- a/oz-plugin.py +++ b/oz-plugin.py @@ -20,7 +20,7 @@ def execute_mozart(file): errs = stderr.decode('utf-8') return [outs, errs] -class OzRunCommand(sublime_plugin.TextCommand): +class OzCompileCommand(sublime_plugin.TextCommand): def run(self, edit): file = self.view.file_name() co = compile_mozart(file) @@ -40,4 +40,4 @@ def run(self, edit): panel.set_read_only(True) def is_visible(self): print(self.view.window().active_panel()) - return True \ No newline at end of file + return True From c3b4bb1cedf2254df18131b6591951928ec84a22 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 13:13:18 +0200 Subject: [PATCH 08/44] Adding SocketPipe from Nassar github --- socket_pipe.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 socket_pipe.py diff --git a/socket_pipe.py b/socket_pipe.py new file mode 100644 index 0000000..cf6ad4c --- /dev/null +++ b/socket_pipe.py @@ -0,0 +1,96 @@ +# Copyright : +# Ramsey Nasser 2016. Provided under the MIT License +# see https://github.com/nassar/Socket +# +# Last Change : +# Andres Zarza 2018 + +import threading +import socket +import sublime, sublime_plugin + +class SocketPipe(threading.Thread): + def __init__(self, view, port): + threading.Thread.__init__(self) + self.runnning = True + self.view = view + self.writtent_characters = 0 + self.buffer = [] + self.prompt = 0 + self.history = [] + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.connect('localhost', port) + self.sock.settimeout(1) + print("Connected SocketPipe to port : %s" % (port)) + + def go(self): + self.setup_view() + self.update_view() + self.start() + + def setup_view(self): + self.view.settings().set("scope_name", "source.clojure") + self.view.settings().set("line_numbers", False) + self.view.settings().set("gutter", False) + self.view.settings().set("word_wrap", False) + + def update_view(self): + # prevent editing repl view if a selection is before the prompt + oob = False + self.view.settings().set("noback", False) + for region in self.view.sel(): + # backspace is a special case, a sublime-keymap binding checks the 'noback' setting + if region.a == self.prompt and region.b == region.a: + self.view.settings().set("noback", True) + if region.a < self.prompt or region.b < self.prompt: + oob = True + if oob: + self.view.set_read_only(True) + else: + self.view.set_read_only(False) + for b in self.buffer: + self.view.run_command("socket_insert_text", {"content": b}) + self.buffer = [] + if self.running: + sublime.set_timeout(self.update_view, 100) + + def on_close(self): + self.running = False + self.view.set_name(self.view.name() + " [CLOSED]") + try: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + except: + pass + + def record_history(self, s): + rx = re.search("[\\n]*$", s) + if rx: + s = s[:len(rx.group()) * -1] + hlen = len(self.history) + if s != "" and (hlen == 0 or (hlen > 0 and s != self.history[hlen-1])): + self.history.append(s) + self.hist = 0 + + def send(self, s): + self.record_history(s) + self.sock.send(s.encode('utf-8')) + + def write(self, s): + self.buffer.append(s) + + def bump(self, s): + self.written_characters += len(s) + + def run(self): + while self.running: + try: + read = self.sock.recv(8012) + if(len(read) == 0): + self.on_close() + else: + self.buffer.append(read.decode('utf8')) + except socket.timeout as e: + continue + except socket.error as e: + print(e) From a88848c35d659cafa028a4d0c9a24270c10986f4 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 13:15:10 +0200 Subject: [PATCH 09/44] Rename oz-plugin -> oz-compile.py --- oz-plugin.py => oz-compile.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename oz-plugin.py => oz-compile.py (100%) diff --git a/oz-plugin.py b/oz-compile.py similarity index 100% rename from oz-plugin.py rename to oz-compile.py From f5b5f4f712bd96a274a92adae1813c1da7c2c8c3 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 14:21:33 +0200 Subject: [PATCH 10/44] Rename oz-compile.py -> oz_compile.py --- oz-compile.py => oz_compile.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename oz-compile.py => oz_compile.py (100%) diff --git a/oz-compile.py b/oz_compile.py similarity index 100% rename from oz-compile.py rename to oz_compile.py From 42a52eb3c32649adf3a3843021271c098b10012d Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 15:33:07 +0200 Subject: [PATCH 11/44] Enable ozengine in parallel thread in console --- oz_plugin.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 oz_plugin.py diff --git a/oz_plugin.py b/oz_plugin.py new file mode 100644 index 0000000..dde7376 --- /dev/null +++ b/oz_plugin.py @@ -0,0 +1,31 @@ +import subprocess +from subprocess import PIPE, Popen +import sublime +import sublime_plugin +import threading + +oz_proc = None + +class SubOz(threading.Thread): + def __init__(self): + threading.Thread.__init__(self) + self.running = True + self.process = None + + def run(self): + self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) + print("ozengine pid : %s", self.process.pid) + while self.running: + output = self.process.stdout.readline() + outerr= self.process.stderr.readline() + if output == '' and outerr == '' and self.process.poll() is not None: + running = False + else: + print(output.decode('utf-8')) + print(outerr.decode('utf-8')) + +class OzRunCommand(sublime_plugin.TextCommand): + def run(self, edit): + global oz_proc + oz_proc = SubOz() + oz_proc.start() From e8ce6221417b9a729c57eb31fbb90711632a67db Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Wed, 29 Aug 2018 15:54:06 +0200 Subject: [PATCH 12/44] Retrieving socket number from output This commit does not allow to retrieve correctly the socket number from the output. Indeed, it contains undefined behavior. --- oz_plugin.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/oz_plugin.py b/oz_plugin.py index dde7376..243c26a 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -6,15 +6,24 @@ oz_proc = None +def get_socket(s): + sp_s = str.split(s) + return sp_s[1] + + class SubOz(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.running = True self.process = None + self.socket = None def run(self): self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) print("ozengine pid : %s", self.process.pid) + socket_output = self.process.stdout.readline().decode('utf-8') + self.socket = get_socket(socket_output) + print("Oz Socket : %s" % self.socket) while self.running: output = self.process.stdout.readline() outerr= self.process.stderr.readline() From ed9313e0a3d4ae1dbf4495f87a9879c6e8656ada Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 14:17:14 +0200 Subject: [PATCH 13/44] Start ozengine at init SubOz to retrieve socket --- oz_plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index 243c26a..aabe691 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -3,7 +3,7 @@ import sublime import sublime_plugin import threading - +from User.socket_pipe import SocketPipe oz_proc = None def get_socket(s): @@ -17,13 +17,13 @@ def __init__(self): self.running = True self.process = None self.socket = None - - def run(self): self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) print("ozengine pid : %s", self.process.pid) socket_output = self.process.stdout.readline().decode('utf-8') self.socket = get_socket(socket_output) print("Oz Socket : %s" % self.socket) + + def run(self): while self.running: output = self.process.stdout.readline() outerr= self.process.stderr.readline() From ac45247b8eeb5a8c88a58e0bb24c6c25a559577c Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 14:35:32 +0200 Subject: [PATCH 14/44] fixup socket_pipe, import, attribute --- socket_pipe.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/socket_pipe.py b/socket_pipe.py index cf6ad4c..e31c9c0 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -8,6 +8,7 @@ import threading import socket import sublime, sublime_plugin +import re class SocketPipe(threading.Thread): def __init__(self, view, port): @@ -19,8 +20,9 @@ def __init__(self, view, port): self.prompt = 0 self.history = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.connect('localhost', port) + self.sock.connect(('localhost', port)) self.sock.settimeout(1) + self.running = True print("Connected SocketPipe to port : %s" % (port)) def go(self): @@ -73,6 +75,7 @@ def record_history(self, s): self.hist = 0 def send(self, s): + print("sending: %s" % s) self.record_history(s) self.sock.send(s.encode('utf-8')) From 7c7ee8c899cb97ce660d8077989e3d956e8bee85 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 14:37:32 +0200 Subject: [PATCH 15/44] Connect new socket --- oz_plugin.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index aabe691..f83ee4c 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -5,11 +5,11 @@ import threading from User.socket_pipe import SocketPipe oz_proc = None +sp = None def get_socket(s): sp_s = str.split(s) - return sp_s[1] - + return int(sp_s[1]) class SubOz(threading.Thread): def __init__(self): @@ -38,3 +38,6 @@ def run(self, edit): global oz_proc oz_proc = SubOz() oz_proc.start() + global sp + sp = SocketPipe(self.view, oz_proc.socket) + sp.start() From efe8eb5883b096f18542a5b9e369edb7af2af372 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 14:51:13 +0200 Subject: [PATCH 16/44] Enable feed buffer --- oz_plugin.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/oz_plugin.py b/oz_plugin.py index f83ee4c..d56dded 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -41,3 +41,10 @@ def run(self, edit): global sp sp = SocketPipe(self.view, oz_proc.socket) sp.start() + +class OzFeedBufferCommand(sublime_plugin.TextCommand): + def run(self, edit): + global sp + msg = self.view.substr(sublime.Region(0, self.view.size())) + msg = msg + "\n\004\n" + sp.send(msg) From 769b3589f2b79108dab1b1be96905978c9c46995 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 15:39:12 +0200 Subject: [PATCH 17/44] Update LICENCE --- LICENSE.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/LICENSE.txt b/LICENSE.txt index 4448465..4dbea6c 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,9 @@ The MIT License (MIT) Copyright (c) 2017 Robert Koeninger +Copyright (c) 2018 Andres Zarza Davila + +Also, concerning socket_pipe.py : Copyright (c) 2016 Ramsey Nasser 2016 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From bdc7d2c850c90238ea1ab5cdc144dc61f5fb6de0 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 16:38:57 +0200 Subject: [PATCH 18/44] Enable feed/run shortcut --- Default (Linux).sublime-keymap | 4 ++++ Default (OSX).sublime-keymap | 4 ++++ Default (Windows).sublime-keymap | 4 ++++ Default.sublime-keymap | 3 ++- 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 Default (Linux).sublime-keymap create mode 100644 Default (OSX).sublime-keymap create mode 100644 Default (Windows).sublime-keymap diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap new file mode 100644 index 0000000..38f1aeb --- /dev/null +++ b/Default (Linux).sublime-keymap @@ -0,0 +1,4 @@ +[ + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} +] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap new file mode 100644 index 0000000..38f1aeb --- /dev/null +++ b/Default (OSX).sublime-keymap @@ -0,0 +1,4 @@ +[ + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} +] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap new file mode 100644 index 0000000..38f1aeb --- /dev/null +++ b/Default (Windows).sublime-keymap @@ -0,0 +1,4 @@ +[ + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} +] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 242fdf4..38f1aeb 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,3 +1,4 @@ [ - { "keys": ["ctrl+b", "b"], "command": "oz_run"} + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} ] From 6fd92599cfe59af37bf8eda298b73c3063422da5 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Thu, 30 Aug 2018 15:36:47 +0200 Subject: [PATCH 19/44] Update README --- README.md | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 453664d..7d7fdc3 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,60 @@ # Sublime/Oz [Oz language](http://mozart.github.io/) support for [Sublime Text 3](https://www.sublimetext.com/). +This plugin intends to be an alternative to the classic Emacs Oz interface. +It is however still in work. Particularly killing subprocesses is still not +correctly implemented and not automatic. + +## Usage +The main feature that needs input from the user is feed buffer. +In order to do so, you should first start the _ozengine_ subprocess. +Just press **Ctrl-. + Ctrl-s**. Then at any time, you can press **Ctrl-. + +Ctrl-b** to feed the buffer. Please note that once you started the engine +subprocess you will need to kill it even after closing Sublime Text. In Unix +like systems, you can run _pkill ozengine ozemulator ozwish_ to make sure you +cleaned everything after closing Sublime Text. ## Features * Syntax Highlighting - detects files matching the pattern `*.oz`. * Comments - Applies Oz-style single line (%) comments using standard commands/shortcuts. + * Feed Buffer - Feed the current buffer, compile and execute it within ozengine as in the classic OPI ## Automatic Installation Sublime/Oz is available from [Package Control](https://packagecontrol.io/packages/Oz) under the name `Oz`. +This package contains only the syntax Highlighting and Comments. If you wish to +use the build/run features you need to install the plugin manualy. ## Manual Installation -Download this repo as an archive or `git clone` it under the `Packages` directory under your Sublime user path. +Download this repo as an archive or `git clone` it under the `Packages\User` directory under your Sublime user path. On Windows, this is something like `C:\Users\%USER_NAME%\AppData\Roaming\Sublime Text 3\Packages`. +On linux, this is something like `/home/user/.config/sublime-text-3` + Once the `sublime-oz` package is in place, just restart Sublime, and it should be ready to go. +## OPI + +The Oz Programming Interface is started with the plugin command _view.run\_run\_command(oz\_run)_. +This command calls _ozengine x-oz://system/OPI.ozf_. +This creates two sockets to communicate with the process. +The first one, allows to give instruction to the compiler and the second one is used for special instruction, for example start the debugger. +We connect to the first one using [socket\_pipe.py](socket\_pype.py). +Please note that this file is a simple modification of pre-existing Class from this [repository](https://github.com/nasser/Socket) +The message we send to this socket is actually very simple. We just send what +we want to compile and add this \n\004\n. + + ## Future Work * Snippets - * Build/Run + * Feed line/Feed region * Formatting + * Killing at close ozengine/ozemulator(on Unix like)/ozwish(if Browse is used) + * Redirect compilation and emulator output. ## Contributing From 6f2b32b5f540847ffda8a02e885aecba6049b5ef Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Fri, 31 Aug 2018 10:21:52 +0200 Subject: [PATCH 20/44] fixup! Import space --- oz_plugin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/oz_plugin.py b/oz_plugin.py index d56dded..47e2c29 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -4,6 +4,7 @@ import sublime_plugin import threading from User.socket_pipe import SocketPipe + oz_proc = None sp = None From a5032c96865b5627bf19287ddb45c49d68c269d8 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Fri, 31 Aug 2018 10:26:09 +0200 Subject: [PATCH 21/44] Enable oz_kill command with {Application.exit 0} --- oz_plugin.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/oz_plugin.py b/oz_plugin.py index 47e2c29..17c639e 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -12,6 +12,9 @@ def get_socket(s): sp_s = str.split(s) return int(sp_s[1]) +def kill_oz(sock): + sock.send("{Application.exit 0}\n\004\n\n}") + class SubOz(threading.Thread): def __init__(self): threading.Thread.__init__(self) @@ -49,3 +52,8 @@ def run(self, edit): msg = self.view.substr(sublime.Region(0, self.view.size())) msg = msg + "\n\004\n" sp.send(msg) + +class OzKillCommand(sublime_plugin.TextCommand): + def run(self, edit): + global sp + kill_oz(sp) From 85a60ffc6ca5a2c4d0ca4932f55eaf2636a692e1 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Fri, 31 Aug 2018 10:27:27 +0200 Subject: [PATCH 22/44] fixup! self.running in class SubOz --- oz_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oz_plugin.py b/oz_plugin.py index 17c639e..e9c6bdf 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -32,7 +32,7 @@ def run(self): output = self.process.stdout.readline() outerr= self.process.stderr.readline() if output == '' and outerr == '' and self.process.poll() is not None: - running = False + self.running = False else: print(output.decode('utf-8')) print(outerr.decode('utf-8')) From 43a2ab45941065e845602e880cb064d0a71f4137 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Fri, 31 Aug 2018 10:36:38 +0200 Subject: [PATCH 23/44] Add shortcut to kill subprocess ozengine --- Default (Linux).sublime-keymap | 1 + Default (OSX).sublime-keymap | 1 + Default (Windows).sublime-keymap | 1 + Default.sublime-keymap | 1 + 4 files changed, 4 insertions(+) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 38f1aeb..4a6cdf4 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,4 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 38f1aeb..4a6cdf4 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,4 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 38f1aeb..4a6cdf4 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,4 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 38f1aeb..4a6cdf4 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,4 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] From 3ad9c1e9c6f23cbe2d8dc3e1aee43ba632c1fc7c Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Fri, 31 Aug 2018 10:49:02 +0200 Subject: [PATCH 24/44] fixup! shortcut --- Default (Linux).sublime-keymap | 2 +- Default (OSX).sublime-keymap | 2 +- Default (Windows).sublime-keymap | 2 +- Default.sublime-keymap | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 4a6cdf4..06fa3e7 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,5 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 4a6cdf4..06fa3e7 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,5 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 4a6cdf4..06fa3e7 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,5 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 4a6cdf4..06fa3e7 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,5 +1,5 @@ [ { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"} + { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] From 879cdf330e2fb4d0068fcb3c4c6a512b6735a466 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 12:31:15 +0200 Subject: [PATCH 25/44] Merge of thread that treats ozengine and socket This commit merges the two created thread. It removes many unused features from socket_pipe. It also uses the module select to poll both the outputs from ozengine and those from the socket. --- oz_plugin.py | 40 +++++----------------- socket_pipe.py | 91 +++++++++++++++++++++----------------------------- 2 files changed, 46 insertions(+), 85 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index e9c6bdf..5910c2a 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -3,47 +3,23 @@ import sublime import sublime_plugin import threading -from User.socket_pipe import SocketPipe +from .socket_pipe import OzThread -oz_proc = None sp = None -def get_socket(s): - sp_s = str.split(s) - return int(sp_s[1]) - def kill_oz(sock): sock.send("{Application.exit 0}\n\004\n\n}") -class SubOz(threading.Thread): - def __init__(self): - threading.Thread.__init__(self) - self.running = True - self.process = None - self.socket = None - self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) - print("ozengine pid : %s", self.process.pid) - socket_output = self.process.stdout.readline().decode('utf-8') - self.socket = get_socket(socket_output) - print("Oz Socket : %s" % self.socket) - - def run(self): - while self.running: - output = self.process.stdout.readline() - outerr= self.process.stderr.readline() - if output == '' and outerr == '' and self.process.poll() is not None: - self.running = False - else: - print(output.decode('utf-8')) - print(outerr.decode('utf-8')) - class OzRunCommand(sublime_plugin.TextCommand): def run(self, edit): - global oz_proc - oz_proc = SubOz() - oz_proc.start() global sp - sp = SocketPipe(self.view, oz_proc.socket) + #Panel to display compilation and emulator output + window = sublime.active_window() + panel = window.find_output_panel('oz_panel') + if(panel == None): + panel = window.create_output_panel('oz_panel') + window.run_command('show_panel', {'panel':'output.oz_panel'}) + sp = OzThread(panel) sp.start() class OzFeedBufferCommand(sublime_plugin.TextCommand): diff --git a/socket_pipe.py b/socket_pipe.py index e31c9c0..dcc859c 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -1,3 +1,4 @@ +# Inspired from # Copyright : # Ramsey Nasser 2016. Provided under the MIT License # see https://github.com/nassar/Socket @@ -9,25 +10,37 @@ import socket import sublime, sublime_plugin import re +from subprocess import PIPE, Popen +import select -class SocketPipe(threading.Thread): - def __init__(self, view, port): +#The first message from ozengine contains the port on which it opened the +#socket. The format of the message is "oz-socket XXXX XXXX" +def get_port(s): + sp_s = str.split(s) + return int(sp_s[1]) + +#Thread that runs that connects the socket and runs ozengine +class OzThread(threading.Thread): + def __init__(self, view): threading.Thread.__init__(self) - self.runnning = True self.view = view - self.writtent_characters = 0 - self.buffer = [] - self.prompt = 0 + + #ozemulator + self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) + print("ozengine pid : %s", self.process.pid) + port_output = self.process.stdout.readline().decode('utf-8') + port = get_port(port_output) + print("Oz Socket : %s" % port) + + #socket self.history = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(('localhost', port)) self.sock.settimeout(1) self.running = True - print("Connected SocketPipe to port : %s" % (port)) def go(self): self.setup_view() - self.update_view() self.start() def setup_view(self): @@ -36,64 +49,36 @@ def setup_view(self): self.view.settings().set("gutter", False) self.view.settings().set("word_wrap", False) - def update_view(self): - # prevent editing repl view if a selection is before the prompt - oob = False - self.view.settings().set("noback", False) - for region in self.view.sel(): - # backspace is a special case, a sublime-keymap binding checks the 'noback' setting - if region.a == self.prompt and region.b == region.a: - self.view.settings().set("noback", True) - if region.a < self.prompt or region.b < self.prompt: - oob = True - if oob: - self.view.set_read_only(True) - else: - self.view.set_read_only(False) - for b in self.buffer: - self.view.run_command("socket_insert_text", {"content": b}) - self.buffer = [] - if self.running: - sublime.set_timeout(self.update_view, 100) - def on_close(self): self.running = False - self.view.set_name(self.view.name() + " [CLOSED]") try: self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() except: pass - def record_history(self, s): - rx = re.search("[\\n]*$", s) - if rx: - s = s[:len(rx.group()) * -1] - hlen = len(self.history) - if s != "" and (hlen == 0 or (hlen > 0 and s != self.history[hlen-1])): - self.history.append(s) - self.hist = 0 - def send(self, s): - print("sending: %s" % s) - self.record_history(s) self.sock.send(s.encode('utf-8')) - def write(self, s): - self.buffer.append(s) - def bump(self, s): - self.written_characters += len(s) + def insert_text(self, s): + self.view.set_read_only(False) + self.view.run_command("append", {"characters": s}) + self.view.set_read_only(True) def run(self): + inputs = [self.sock, self.process.stdout, self.process.stderr] while self.running: - try: - read = self.sock.recv(8012) - if(len(read) == 0): - self.on_close() + [readable, writable, exceptional] = select.select(inputs, [], []) + for s in readable: + if(s is self.sock): + try: + read = self.sock.recv(8012) + read = read.decode('utf-8') + self.insert_text(read) + except socket.timeout as e: + continue + except socket.error as e: + print(e) else: - self.buffer.append(read.decode('utf8')) - except socket.timeout as e: - continue - except socket.error as e: - print(e) + self.insert_text(s.readline().decode('utf-8')) From 995dbace5a550c88052e913a47df70e0d269b739 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 12:50:36 +0200 Subject: [PATCH 26/44] Start ozengine at feed buffer if necessary --- oz_plugin.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index 5910c2a..249f4e8 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -10,21 +10,26 @@ def kill_oz(sock): sock.send("{Application.exit 0}\n\004\n\n}") +def start_oz(): + global sp + #Panel to display compilation and emulator output + window = sublime.active_window() + panel = window.find_output_panel('oz_panel') + if(panel == None): + panel = window.create_output_panel('oz_panel') + window.run_command('show_panel', {'panel':'output.oz_panel'}) + sp = OzThread(panel) + sp.start() + class OzRunCommand(sublime_plugin.TextCommand): def run(self, edit): - global sp - #Panel to display compilation and emulator output - window = sublime.active_window() - panel = window.find_output_panel('oz_panel') - if(panel == None): - panel = window.create_output_panel('oz_panel') - window.run_command('show_panel', {'panel':'output.oz_panel'}) - sp = OzThread(panel) - sp.start() + start_oz() class OzFeedBufferCommand(sublime_plugin.TextCommand): def run(self, edit): global sp + if(sp == None): + start_oz() msg = self.view.substr(sublime.Region(0, self.view.size())) msg = msg + "\n\004\n" sp.send(msg) From 17a9b4af63132380573556e47d73615cacd9c86c Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 13:59:14 +0200 Subject: [PATCH 27/44] Refactor --- oz_plugin.py | 41 +++++++++++++++++++++++++++-------------- socket_pipe.py | 41 +++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index 249f4e8..bab10f5 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -7,34 +7,47 @@ sp = None -def kill_oz(sock): - sock.send("{Application.exit 0}\n\004\n\n}") +def with_oz(f): + def wrapper(*args, **kwargs): + global sp + if not sp: + start_oz() + f(*args, **kwargs) + return wrapper def start_oz(): global sp - #Panel to display compilation and emulator output - window = sublime.active_window() - panel = window.find_output_panel('oz_panel') - if(panel == None): - panel = window.create_output_panel('oz_panel') - window.run_command('show_panel', {'panel':'output.oz_panel'}) - sp = OzThread(panel) + sp = OzThread() sp.start() class OzRunCommand(sublime_plugin.TextCommand): + @with_oz def run(self, edit): - start_oz() + pass + +class OzFeedLine(sublime_plugin.TextCommand): + @with_oz + def run(self, edit): + global sp + msg = "" + for region in self.view.sel(): + if region.empty: + line = self.view.line(region) + msg += self.view.substr(line) + '\n' + sp.send(msg) class OzFeedBufferCommand(sublime_plugin.TextCommand): + @with_oz def run(self, edit): global sp - if(sp == None): - start_oz() msg = self.view.substr(sublime.Region(0, self.view.size())) - msg = msg + "\n\004\n" sp.send(msg) class OzKillCommand(sublime_plugin.TextCommand): def run(self, edit): global sp - kill_oz(sp) + if sp: + sp.send("{Application.exit 0}\n\004\n\n") + #TODO + #Close the process/socket + sp = None diff --git a/socket_pipe.py b/socket_pipe.py index dcc859c..cd7ec14 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -10,7 +10,7 @@ import socket import sublime, sublime_plugin import re -from subprocess import PIPE, Popen +from subprocess import PIPE, Popen, STDOUT import select #The first message from ozengine contains the port on which it opened the @@ -21,33 +21,35 @@ def get_port(s): #Thread that runs that connects the socket and runs ozengine class OzThread(threading.Thread): - def __init__(self, view): + def __init__(self): threading.Thread.__init__(self) - self.view = view + self.window = sublime.active_window() #ozemulator self.process = Popen(['ozengine', 'x-oz://system/OPI.ozf'], stdout=PIPE, stderr=PIPE) - print("ozengine pid : %s", self.process.pid) port_output = self.process.stdout.readline().decode('utf-8') port = get_port(port_output) - print("Oz Socket : %s" % port) #socket - self.history = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(('localhost', port)) self.sock.settimeout(1) self.running = True - def go(self): - self.setup_view() - self.start() + def write_compiler(self, s): + #Panel to display compilation and emulator output + panel = self.window.find_output_panel('oz_panel') + if not panel: + panel = self.window.create_output_panel('oz_panel') +# panel.settings().set("scope_name", "source.clojure") + panel.settings().set("line_numbers", False) +# panel.settings().set("gutter", False) + panel.settings().set("word_wrap", False) - def setup_view(self): - self.view.settings().set("scope_name", "source.clojure") - self.view.settings().set("line_numbers", False) - self.view.settings().set("gutter", False) - self.view.settings().set("word_wrap", False) + self.window.run_command('show_panel', {'panel':'output.oz_panel'}) + panel.set_read_only(False) + panel.run_command("append", {"characters": s}) + panel.set_read_only(True) def on_close(self): self.running = False @@ -58,14 +60,9 @@ def on_close(self): pass def send(self, s): + s += "\n\004\n" self.sock.send(s.encode('utf-8')) - - def insert_text(self, s): - self.view.set_read_only(False) - self.view.run_command("append", {"characters": s}) - self.view.set_read_only(True) - def run(self): inputs = [self.sock, self.process.stdout, self.process.stderr] while self.running: @@ -75,10 +72,10 @@ def run(self): try: read = self.sock.recv(8012) read = read.decode('utf-8') - self.insert_text(read) + self.write_compiler(read) except socket.timeout as e: continue except socket.error as e: print(e) else: - self.insert_text(s.readline().decode('utf-8')) + self.write_compiler(s.readline().decode('utf-8')) From eb88bad6394a8bf90666a38d2fbe006b0cb506e2 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 15:19:39 +0200 Subject: [PATCH 28/44] [WIP] kill oz --- oz_plugin.py | 17 +++++++++++------ socket_pipe.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/oz_plugin.py b/oz_plugin.py index bab10f5..40b0329 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -43,11 +43,16 @@ def run(self, edit): msg = self.view.substr(sublime.Region(0, self.view.size())) sp.send(msg) +def stop(): + global sp + if sp: + sp.stop() + sp = None + class OzKillCommand(sublime_plugin.TextCommand): def run(self, edit): - global sp - if sp: - sp.send("{Application.exit 0}\n\004\n\n") - #TODO - #Close the process/socket - sp = None + stop() + +class ExitListener(sublime_plugin.EventListener): + def on_pre_close(view): + stop() diff --git a/socket_pipe.py b/socket_pipe.py index cd7ec14..4fa8cdd 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -66,7 +66,8 @@ def send(self, s): def run(self): inputs = [self.sock, self.process.stdout, self.process.stderr] while self.running: - [readable, writable, exceptional] = select.select(inputs, [], []) + [readable, writable, exceptional] = select.select(inputs, [], [], + 10) for s in readable: if(s is self.sock): try: @@ -79,3 +80,11 @@ def run(self): print(e) else: self.write_compiler(s.readline().decode('utf-8')) + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + self.process.wait() + + def stop(self): + exit_msg = "{Application.exit 0}\n\004\n\n" + self.sock.send(exit_msg.encode('utf-8')) + self.running = False From c6fe8e0db23263dc37de0cbb06b69622ea734cb2 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 15:29:05 +0200 Subject: [PATCH 29/44] Feed region --- oz_plugin.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/oz_plugin.py b/oz_plugin.py index 40b0329..43d1655 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -25,6 +25,16 @@ class OzRunCommand(sublime_plugin.TextCommand): def run(self, edit): pass +class OzFeedRegion(sublime_plugin.TextCommand): + @with_oz + def run(self, edit): + global sp + msg = "" + for region in self.view.sel(): + if not region.empty(): + msg += self.view.substr(region) + sp.send(msg) + class OzFeedLine(sublime_plugin.TextCommand): @with_oz def run(self, edit): From 6a2e4415b322b3164748681674c3426bb7b9ae62 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 15:29:39 +0200 Subject: [PATCH 30/44] Update shortcuts --- Default (Linux).sublime-keymap | 4 +++- Default (OSX).sublime-keymap | 4 +++- Default (Windows).sublime-keymap | 4 +++- Default.sublime-keymap | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 06fa3e7..cb5195c 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,5 +1,7 @@ [ - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 06fa3e7..cb5195c 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,5 +1,7 @@ [ - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 06fa3e7..cb5195c 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,5 +1,7 @@ [ - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 06fa3e7..cb5195c 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,5 +1,7 @@ [ - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, + { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, + { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} ] From db2d2bce3e3a22ef9cb1f77e5ed2f59daeb811a9 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 15:39:33 +0200 Subject: [PATCH 31/44] Destroy output panel when oz is killed --- socket_pipe.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/socket_pipe.py b/socket_pipe.py index 4fa8cdd..d749896 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -83,6 +83,9 @@ def run(self): self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() self.process.wait() + panel = self.window.find_output_panel("oz_panel") + if panel is not None: + self.window.destroy_output_panel("oz_panel") def stop(self): exit_msg = "{Application.exit 0}\n\004\n\n" From 6ab373d247612f75a1db608a5dc1ad15e586ee74 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 15:47:40 +0200 Subject: [PATCH 32/44] Update README --- README.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7d7fdc3..91f0971 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,26 @@ It is however still in work. Particularly killing subprocesses is still not correctly implemented and not automatic. ## Usage -The main feature that needs input from the user is feed buffer. -In order to do so, you should first start the _ozengine_ subprocess. -Just press **Ctrl-. + Ctrl-s**. Then at any time, you can press **Ctrl-. + -Ctrl-b** to feed the buffer. Please note that once you started the engine -subprocess you will need to kill it even after closing Sublime Text. In Unix -like systems, you can run _pkill ozengine ozemulator ozwish_ to make sure you -cleaned everything after closing Sublime Text. +The main feature that needs input from the user is feed like commands +When you feed something, it should automatically start *ozengine* subprocess. +The default shortcuts are the following : + + * Feed Line : **Ctrl-. + Ctrl-l** + * Feed Region : **Ctrl-. + Ctrl-r** + * Feed Buffer : **Ctrl-. + Ctrl-b** + * Kill oz : **Ctrl-. + Ctrl-k** + +Please note that once you started the ozengine +subprocess you will need to kill it manually. ## Features * Syntax Highlighting - detects files matching the pattern `*.oz`. * Comments - Applies Oz-style single line (%) comments using standard commands/shortcuts. + * Feed Line - Feed the current line, compile and execute it within ozengine +as in the classic OPI + * Feed Region - Feed the current region, compile and execute it within +ozengine as in the classic OPI * Feed Buffer - Feed the current buffer, compile and execute it within ozengine as in the classic OPI ## Automatic Installation From 9b31a35f879dff66754eb02794292b59d0ae42f0 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Mon, 3 Sep 2018 15:58:27 +0200 Subject: [PATCH 33/44] Use two different panels --- socket_pipe.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/socket_pipe.py b/socket_pipe.py index d749896..93562af 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -37,19 +37,29 @@ def __init__(self): self.running = True def write_compiler(self, s): + self.write_panel(s, "oz_compiler") + + def write_process(self, s): + self.write_panel(s, "oz_output") + + def write_panel(self, s, panel_name): #Panel to display compilation and emulator output - panel = self.window.find_output_panel('oz_panel') + panel = self.window.find_output_panel(panel_name) if not panel: - panel = self.window.create_output_panel('oz_panel') -# panel.settings().set("scope_name", "source.clojure") - panel.settings().set("line_numbers", False) -# panel.settings().set("gutter", False) - panel.settings().set("word_wrap", False) + panel = self.window.create_output_panel(panel_name) + #panel.settings().set("scope_name", "source.clojure") + panel.settings().set("line_numbers", False) + panel.settings().set("gutter", False) + panel.settings().set("word_wrap", False) + panel.set_read_only(True) + + panel.run_command("append", { + 'characters': s, + 'force': True, + 'scroll_to_end': True, + }) + self.window.run_command('show_panel', {'panel': 'output.'+panel_name}) - self.window.run_command('show_panel', {'panel':'output.oz_panel'}) - panel.set_read_only(False) - panel.run_command("append", {"characters": s}) - panel.set_read_only(True) def on_close(self): self.running = False @@ -69,17 +79,16 @@ def run(self): [readable, writable, exceptional] = select.select(inputs, [], [], 10) for s in readable: - if(s is self.sock): + if s is self.sock: try: - read = self.sock.recv(8012) - read = read.decode('utf-8') - self.write_compiler(read) + self.write_compiler(s.recv(8012).decode('utf-8')) except socket.timeout as e: continue except socket.error as e: print(e) else: - self.write_compiler(s.readline().decode('utf-8')) + self.write_process(s.readline().decode('utf-8')) + self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() self.process.wait() From 9d34c32d13fde3dcdac2836a0013a0596b082213 Mon Sep 17 00:00:00 2001 From: azarzadavila <37216245+azarzadavila@users.noreply.github.com> Date: Mon, 3 Sep 2018 16:14:44 +0200 Subject: [PATCH 34/44] Update kill shortcut --- Default (Linux).sublime-keymap | 2 +- Default (OSX).sublime-keymap | 2 +- Default (Windows).sublime-keymap | 2 +- Default.sublime-keymap | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index cb5195c..7856ef1 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -3,5 +3,5 @@ { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} + { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index cb5195c..7856ef1 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -3,5 +3,5 @@ { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} + { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index cb5195c..7856ef1 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -3,5 +3,5 @@ { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} + { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} ] diff --git a/Default.sublime-keymap b/Default.sublime-keymap index cb5195c..7856ef1 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -3,5 +3,5 @@ { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "ctrl+k"], "command": "oz_kill"} + { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} ] From cc7fca6996995c36eae4c70c18a779f5287695ee Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Mon, 3 Sep 2018 16:30:00 +0200 Subject: [PATCH 35/44] Clear panels on restart --- socket_pipe.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/socket_pipe.py b/socket_pipe.py index 93562af..21737a4 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -36,6 +36,15 @@ def __init__(self): self.sock.settimeout(1) self.running = True + self.clear_panel('oz_compiler') + self.clear_panel('oz_output') + + + def clear_panel(self, panel_name): + panel = self.window.find_output_panel(panel_name) + if panel: + self.window.destroy_output_panel(panel_name) + def write_compiler(self, s): self.write_panel(s, "oz_compiler") @@ -92,9 +101,6 @@ def run(self): self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() self.process.wait() - panel = self.window.find_output_panel("oz_panel") - if panel is not None: - self.window.destroy_output_panel("oz_panel") def stop(self): exit_msg = "{Application.exit 0}\n\004\n\n" From 085520b05558f3b785b07298808944549ff996e0 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:14:36 +0200 Subject: [PATCH 36/44] Remove redundant keymap files --- Default (Linux).sublime-keymap | 7 ------- Default (OSX).sublime-keymap | 7 ------- Default (Windows).sublime-keymap | 7 ------- 3 files changed, 21 deletions(-) delete mode 100644 Default (Linux).sublime-keymap delete mode 100644 Default (OSX).sublime-keymap delete mode 100644 Default (Windows).sublime-keymap diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap deleted file mode 100644 index 7856ef1..0000000 --- a/Default (Linux).sublime-keymap +++ /dev/null @@ -1,7 +0,0 @@ -[ - { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} -] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap deleted file mode 100644 index 7856ef1..0000000 --- a/Default (OSX).sublime-keymap +++ /dev/null @@ -1,7 +0,0 @@ -[ - { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} -] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap deleted file mode 100644 index 7856ef1..0000000 --- a/Default (Windows).sublime-keymap +++ /dev/null @@ -1,7 +0,0 @@ -[ - { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, - { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, - { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, - { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, - { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} -] From 24bff13eaf99c6c85cf4abf22b41330b41fd2e14 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:16:11 +0200 Subject: [PATCH 37/44] Add more natural keymap variants, remove useless oz_run --- Default.sublime-keymap | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 7856ef1..a32341d 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -1,7 +1,8 @@ [ - { "keys": ["ctrl+keypad_period", "ctrl+a"], "command": "oz_run"}, { "keys": ["ctrl+keypad_period", "ctrl+l"], "command": "oz_feed_line"}, { "keys": ["ctrl+keypad_period", "ctrl+r"], "command": "oz_feed_region"}, + { "keys": ["ctrl+keypad_period", "ctrl+s"], "command": "oz_feed_region"}, { "keys": ["ctrl+keypad_period", "ctrl+b"], "command": "oz_feed_buffer"}, + { "keys": ["ctrl+keypad_period", "ctrl+f"], "command": "oz_feed_buffer"}, { "keys": ["ctrl+keypad_period", "h"], "command": "oz_kill"} ] From 5dd92b88b9345b7d625524448745d54816015b16 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:17:03 +0200 Subject: [PATCH 38/44] Add menu and context menu entries --- Context.sublime-menu | 8 +++++ Main.sublime-menu | 30 +++++++++++++++++ oz_plugin.py | 76 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 Context.sublime-menu create mode 100644 Main.sublime-menu diff --git a/Context.sublime-menu b/Context.sublime-menu new file mode 100644 index 0000000..feec65f --- /dev/null +++ b/Context.sublime-menu @@ -0,0 +1,8 @@ +[ + { "caption": "-", "id": "Oz feed" }, + { + "caption": "Oz: Feed to Compiler", + "command": "oz_feed_context", + "mnemonic": "F" + } +] diff --git a/Main.sublime-menu b/Main.sublime-menu new file mode 100644 index 0000000..72cc118 --- /dev/null +++ b/Main.sublime-menu @@ -0,0 +1,30 @@ +[ + { + "caption": "Oz", + "mnemonic": "O", + "id": "oz-menu", + "children": + [ + { + "caption": "Halt Oz", + "command": "oz_kill" + }, + { "caption": "-", "id": "feed" }, + { + "caption": "Feed Line", + "command": "oz_feed_line", + "mnemonic": "L" + }, + { + "caption": "Feed Selection", + "command": "oz_feed_region", + "mnemonic": "S" + }, + { + "caption": "Feed File", + "command": "oz_feed_buffer", + "mnemonic": "F" + }, + ] + } +] diff --git a/oz_plugin.py b/oz_plugin.py index 43d1655..eb99c33 100644 --- a/oz_plugin.py +++ b/oz_plugin.py @@ -25,34 +25,80 @@ class OzRunCommand(sublime_plugin.TextCommand): def run(self, edit): pass +@with_oz +def feed_region(view): + global sp + msg = "" + for region in view.sel(): + if not region.empty(): + msg += view.substr(region) + sp.send(msg) + class OzFeedRegion(sublime_plugin.TextCommand): - @with_oz def run(self, edit): - global sp - msg = "" + feed_region(self.view) + + def is_enabled(self): for region in self.view.sel(): if not region.empty(): - msg += self.view.substr(region) - sp.send(msg) + return True + return False + + def description(self): + "Feed the selected text to the Oz compiler" + + +@with_oz +def feed_line(view): + global sp + msg = "" + for region in view.sel(): + if region.empty: + line = view.line(region) + msg += view.substr(line) + '\n' + sp.send(msg) class OzFeedLine(sublime_plugin.TextCommand): - @with_oz def run(self, edit): - global sp - msg = "" + feed_line(self.view) + + def is_enabled(self): for region in self.view.sel(): - if region.empty: - line = self.view.line(region) - msg += self.view.substr(line) + '\n' - sp.send(msg) + if region.empty(): + return True + return False + + def description(self): + "Feed the current line to the Oz compiler" -class OzFeedBufferCommand(sublime_plugin.TextCommand): +class OzFeedBuffer(sublime_plugin.TextCommand): @with_oz def run(self, edit): global sp msg = self.view.substr(sublime.Region(0, self.view.size())) sp.send(msg) + def description(self): + "Feed the current file to the Oz compiler" + +class OzFeedContext(sublime_plugin.TextCommand): + def run(self, edit): + global sp + msg = "" + for region in self.view.sel(): + if not region.empty: + return feed_region(self.view) + return feed_line(self.view) + + def is_enabled(self): + for region in self.view.sel(): + return True + return False + + def description(self): + "Feed text to the Oz compiler" + + def stop(): global sp if sp: @@ -63,6 +109,10 @@ class OzKillCommand(sublime_plugin.TextCommand): def run(self, edit): stop() + def description(self): + "Kill the Oz compiler" + class ExitListener(sublime_plugin.EventListener): def on_pre_close(view): stop() + From 61119298fa2c28637cc45c80855ee40bfa91b285 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:17:47 +0200 Subject: [PATCH 39/44] Add a .sublime-commands to kill oz --- Default.sublime-commands | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Default.sublime-commands diff --git a/Default.sublime-commands b/Default.sublime-commands new file mode 100644 index 0000000..4a3c282 --- /dev/null +++ b/Default.sublime-commands @@ -0,0 +1,6 @@ +[ + { + "caption": "Oz: Halt compiler", + "command": "oz_kill" + } +] From cd12700437c16aaf5679d36a360bd16a6fe4ff19 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:19:18 +0200 Subject: [PATCH 40/44] Add support for multiline comments --- Comment.tmPreferences | 48 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/Comment.tmPreferences b/Comment.tmPreferences index 2c5acb1..2db0633 100644 --- a/Comment.tmPreferences +++ b/Comment.tmPreferences @@ -1,24 +1,34 @@ - + - name - Comment - scope - source.oz - settings - - shellVariables - - - name - TM_COMMENT_START - value - % - - - - uuid - 7c251375-db32-45e7-b216-0fc70b53a6f5 + name + Oz comments + scope + source.oz + settings + + shellVariables + + + name + TM_COMMENT_START + value + % + + + name + TM_COMMENT_START_2 + value + /* + + + name + TM_COMMENT_END_2 + value + */ + + + From 0b4ef50459595611db120f873d3165963fdf57a9 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:25:31 +0200 Subject: [PATCH 41/44] Use a proper condition variable for exit notification --- socket_pipe.py | 52 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/socket_pipe.py b/socket_pipe.py index 21737a4..a8daa3d 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -12,6 +12,7 @@ import re from subprocess import PIPE, Popen, STDOUT import select +import os #The first message from ozengine contains the port on which it opened the #socket. The format of the message is "oz-socket XXXX XXXX" @@ -34,7 +35,7 @@ def __init__(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect(('localhost', port)) self.sock.settimeout(1) - self.running = True + self.stop_condition = WaitableEvent() self.clear_panel('oz_compiler') self.clear_panel('oz_output') @@ -83,10 +84,13 @@ def send(self, s): self.sock.send(s.encode('utf-8')) def run(self): - inputs = [self.sock, self.process.stdout, self.process.stderr] - while self.running: - [readable, writable, exceptional] = select.select(inputs, [], [], - 10) + inputs = [self.sock, self.process.stdout, self.process.stderr, self.stop_condition] + while True: + readable = select.select(inputs, [], [])[0] + + if self.stop_condition.isSet(): + break + for s in readable: if s is self.sock: try: @@ -98,11 +102,41 @@ def run(self): else: self.write_process(s.readline().decode('utf-8')) - self.sock.shutdown(socket.SHUT_RDWR) + self.send('{Application.exit 0}') self.sock.close() self.process.wait() def stop(self): - exit_msg = "{Application.exit 0}\n\004\n\n" - self.sock.send(exit_msg.encode('utf-8')) - self.running = False + self.stop_condition.set() + + +class WaitableEvent: + """Provides an abstract object that can be used to resume select loops with + indefinite waits from another thread or process. This mimics the standard + threading.Event interface.""" + def __init__(self): + self._read_fd, self._write_fd = os.pipe() + + def wait(self, timeout=None): + rfds, wfds, efds = select.select([self._read_fd], [], [], timeout) + return self._read_fd in rfds + + def isSet(self): + return self.wait(0) + + def clear(self): + if self.isSet(): + os.read(self._read_fd, 1) + + def set(self): + if not self.isSet(): + os.write(self._write_fd, bytes('1', 'utf-8')) + + def fileno(self): + """Return the FD number of the read side of the pipe, allows this object to + be used with select.select().""" + return self._read_fd + + def __del__(self): + os.close(self._read_fd) + os.close(self._write_fd) From d9a2d42f0cc787ce4dbb318829ca2043a8770dfc Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:35:19 +0200 Subject: [PATCH 42/44] Notify OPI shutdown with its return value --- socket_pipe.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/socket_pipe.py b/socket_pipe.py index a8daa3d..7923a57 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -68,7 +68,9 @@ def write_panel(self, s, panel_name): 'force': True, 'scroll_to_end': True, }) - self.window.run_command('show_panel', {'panel': 'output.'+panel_name}) + self.window.run_command('show_panel', { + 'panel': 'output.%s' % panel_name + }) def on_close(self): @@ -104,7 +106,9 @@ def run(self): self.send('{Application.exit 0}') self.sock.close() - self.process.wait() + + ret = self.process.wait() + self.write_process("Mozart Engine exited with value %d." % ret) def stop(self): self.stop_condition.set() From 62c7405a01e4af399b671274f462218d87755236 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 01:42:41 +0200 Subject: [PATCH 43/44] Refactor, and improve logging --- socket_pipe.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/socket_pipe.py b/socket_pipe.py index 7923a57..5f3e5f8 100644 --- a/socket_pipe.py +++ b/socket_pipe.py @@ -72,15 +72,6 @@ def write_panel(self, s, panel_name): 'panel': 'output.%s' % panel_name }) - - def on_close(self): - self.running = False - try: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - except: - pass - def send(self, s): s += "\n\004\n" self.sock.send(s.encode('utf-8')) @@ -98,9 +89,9 @@ def run(self): try: self.write_compiler(s.recv(8012).decode('utf-8')) except socket.timeout as e: - continue + self.write_compiler(repr(e)) except socket.error as e: - print(e) + self.write_compiler(repr(e)) else: self.write_process(s.readline().decode('utf-8')) From 02e7da0ad3a4f630c2eb44e81fd8ce87c4fbd8cb Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Wed, 5 Sep 2018 02:32:23 +0200 Subject: [PATCH 44/44] Update Readme for OPI integration --- README.md | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 91f0971..16f638a 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,25 @@ It is however still in work. Particularly killing subprocesses is still not correctly implemented and not automatic. ## Usage -The main feature that needs input from the user is feed like commands -When you feed something, it should automatically start *ozengine* subprocess. -The default shortcuts are the following : + +To evaluate some code, you need to feed it to the Oz compiler. +This can be done from the "Oz" menu, from the context menu or with the following shortcuts. * Feed Line : **Ctrl-. + Ctrl-l** - * Feed Region : **Ctrl-. + Ctrl-r** - * Feed Buffer : **Ctrl-. + Ctrl-b** - * Kill oz : **Ctrl-. + Ctrl-k** + * Feed Region (selected text): **Ctrl-. + Ctrl-r** + * Feed Buffer (the whole file): **Ctrl-. + Ctrl-b** + +It may be useful to kill the running compiler. This is also available in the "Oz" menu, or with a shortcut. +The compiler will be restarted automatically on the next feed command. + + * Kill oz : **Ctrl-. + h** -Please note that once you started the ozengine -subprocess you will need to kill it manually. ## Features + * OPI Integration - Submit current line/selection/file to the Oz compiler (as with the Emacs OPI). * Syntax Highlighting - detects files matching the pattern `*.oz`. - * Comments - Applies Oz-style single line (%) comments using standard commands/shortcuts. - * Feed Line - Feed the current line, compile and execute it within ozengine -as in the classic OPI - * Feed Region - Feed the current region, compile and execute it within -ozengine as in the classic OPI - * Feed Buffer - Feed the current buffer, compile and execute it within ozengine as in the classic OPI + * Comments - Comment/Uncomment Oz code using standard commands/shortcuts. ## Automatic Installation @@ -44,25 +42,10 @@ On linux, this is something like `/home/user/.config/sublime-text-3` Once the `sublime-oz` package is in place, just restart Sublime, and it should be ready to go. -## OPI - -The Oz Programming Interface is started with the plugin command _view.run\_run\_command(oz\_run)_. -This command calls _ozengine x-oz://system/OPI.ozf_. -This creates two sockets to communicate with the process. -The first one, allows to give instruction to the compiler and the second one is used for special instruction, for example start the debugger. -We connect to the first one using [socket\_pipe.py](socket\_pype.py). -Please note that this file is a simple modification of pre-existing Class from this [repository](https://github.com/nasser/Socket) -The message we send to this socket is actually very simple. We just send what -we want to compile and add this \n\004\n. - - ## Future Work * Snippets - * Feed line/Feed region * Formatting - * Killing at close ozengine/ozemulator(on Unix like)/ozwish(if Browse is used) - * Redirect compilation and emulator output. ## Contributing