From c23c26595a4a40ee638f6cdc28d68ac2d520270f Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:54:41 +0300 Subject: [PATCH 01/15] add onboarding syntax --- syntax/Onboarding.sublime-syntax | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 syntax/Onboarding.sublime-syntax diff --git a/syntax/Onboarding.sublime-syntax b/syntax/Onboarding.sublime-syntax new file mode 100644 index 0000000..6df9468 --- /dev/null +++ b/syntax/Onboarding.sublime-syntax @@ -0,0 +1,37 @@ +%YAML 1.2 +--- +name: Onboarding +scope: source.onboarding +hidden: true + +contexts: + main: + - match: '\[Success\]' + push: success + - match: '\[Failed\]' + push: fail + - match: '\[In Progress\]' + push: progress + + success: + - meta_scope: pieces.onboarding.success + - match: '\n' + pop: true + - match: '.+' + scope: pieces.onboarding.success + + fail: + - meta_scope: pieces.onboarding.fail + - match: '\n' + pop: true + - match: '.+' + scope: pieces.onboarding.fail + + + progress: + - meta_scope: pieces.onboarding.progress + - match: '\n' + pop: true + - match: '.+' + scope: pieces.onboarding.progress + From de932b283f26156656993f44aa3c2c6cf2ee86c6 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:55:36 +0300 Subject: [PATCH 02/15] add the color scheme generator --- misc/on_boarding/generate_color_scheme.py | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 misc/on_boarding/generate_color_scheme.py diff --git a/misc/on_boarding/generate_color_scheme.py b/misc/on_boarding/generate_color_scheme.py new file mode 100644 index 0000000..2666f91 --- /dev/null +++ b/misc/on_boarding/generate_color_scheme.py @@ -0,0 +1,88 @@ +import json +import os +import sublime +import ast + +from ...settings import PiecesSettings + + +class ColorSchemeGenerator: + resolved_value = None + + @staticmethod + def load_resource(resource_str, color_scheme): + try: + # Attempt to load the resource as JSON + resource = json.loads(resource_str) + globals_ = resource["globals"] + variables = resource["variables"] + except json.decoder.JSONDecodeError: + try: + # If JSON loading fails, attempt to evaluate the resource string as a Python literal + resource = ast.literal_eval(resource_str) + globals_ = resource["globals"] + variables = resource["variables"] + except (ValueError, SyntaxError): + # If both methods fail, fall back to default values + globals_ = { + "background": "var(background)", + "foreground": "var(foreground)" + } + variables = { + "background": color_scheme["palette"]["background"], + "foreground": color_scheme["palette"]["foreground"] + } + + return globals_, variables + + + @staticmethod + def get_color_scheme(globals_,variables): + return { + "name": "Pieces color scheme", + "globals": globals_, + "variables": variables, + "rules": [ + { + "scope": "pieces.onboarding.success", + "foreground": "#99c794" + }, + { + "scope": "pieces.onboarding.fail", + "foreground": "#ec5f66" + }, + { + "scope":"pieces.onboarding.progress", + "foreground": "#808080" + }, + ] + } + + @classmethod + def generate_color_scheme(cls): + color_scheme = sublime.ui_info()["color_scheme"] + resolved_value = color_scheme["resolved_value"] + + if resolved_value == cls.resolved_value: + return # No change in the color scheme + + # Theme changed! + cls.resolved_value = resolved_value + resource_str = sublime.load_resource(sublime.find_resources(resolved_value)[0]) + + globals_,variables = cls.load_resource(resource_str,color_scheme) + + path = os.path.join( + sublime.packages_path(), + PiecesSettings.ONBOARDING_COLOR_SCHEME + ) + + directory = os.path.dirname(path) + + if not os.path.exists(directory): + os.makedirs(directory) + + + with open(path, 'w') as f: + json.dump(cls.get_color_scheme(globals_,variables), f,indent=4) + From 1ff27e15f712df5ff40c3057dcf2624bb403afe4 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:56:14 +0300 Subject: [PATCH 03/15] add onboarding command --- api.py | 6 +- main.py | 11 ++-- misc/__init__.py | 2 +- misc/on_boarding/__init__.py | 4 ++ misc/on_boarding/onboarding_command.py | 22 +++++++ misc/on_boarding/onboarding_handler.py | 84 ++++++++++++++++++++++++++ misc/onboarding.py | 27 +++++++++ 7 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 misc/on_boarding/__init__.py create mode 100644 misc/on_boarding/onboarding_command.py create mode 100644 misc/on_boarding/onboarding_handler.py create mode 100644 misc/onboarding.py diff --git a/api.py b/api.py index 15c04d0..930acae 100644 --- a/api.py +++ b/api.py @@ -64,13 +64,13 @@ def version_check(): print("Please update your Pieces Sublime Package is up-to-date. It is not compatible with the current Pieces OS version") print() print_version_details(pieces_os_version, __version__) - return False + return False,"Pieces OS" elif os_version_parsed < min_version_parsed: print("Please update your Pieces OS. It is not compatible with the current cli-agent version") print() print_version_details(pieces_os_version, __version__) - return False - return True + return False,"The Pieces sublime package" + return True,None def print_version_details(pieces_os_version, __version__): print(f"Pieces os version: {pieces_os_version}\nPlugin version: {__version__}") \ No newline at end of file diff --git a/main.py b/main.py index 6956ea5..1ceaea8 100644 --- a/main.py +++ b/main.py @@ -22,18 +22,17 @@ def startup(): if not pieces_version: print("Couldn't start pieces os\nPlease run pieces os and restart the editor to ensure everything is running properly") else: - if version_check(): + if version_check()[0]: PiecesSettings.is_loaded = True PiecesSettings.models_init() # initilize the models PiecesSettings.get_application() print_version_details(pieces_version, __version__) - settings = sublime.load_settings('Pieces.sublime-settings') - - settings.add_on_change("PIECES_SETTINGS",PiecesSettings.on_settings_change) - - + # Preferences settings + preferences_settings = sublime.load_settings('Preferences.sublime-settings') + preferences_settings.add_on_change("PREFERENCES_SETTINGS",ColorSchemeGenerator.generate_color_scheme) + ColorSchemeGenerator.generate_color_scheme() # WEBSOCKETS: # Assets Identifiers Websocket diff --git a/misc/__init__.py b/misc/__init__.py index ad060a5..f054eed 100644 --- a/misc/__init__.py +++ b/misc/__init__.py @@ -1,3 +1,3 @@ from .support_command import PiecesSupportCommand from .reload_command import PiecesReloadCommand - +from .on_boarding import * \ No newline at end of file diff --git a/misc/on_boarding/__init__.py b/misc/on_boarding/__init__.py new file mode 100644 index 0000000..ce23630 --- /dev/null +++ b/misc/on_boarding/__init__.py @@ -0,0 +1,4 @@ +from .generate_color_scheme import ColorSchemeGenerator +from .onboarding_command import PiecesOnboardingCommand +from .onboarding_handler import PiecesOnBoardingHandlerCommand + \ No newline at end of file diff --git a/misc/on_boarding/onboarding_command.py b/misc/on_boarding/onboarding_command.py new file mode 100644 index 0000000..d3f12b7 --- /dev/null +++ b/misc/on_boarding/onboarding_command.py @@ -0,0 +1,22 @@ +import sublime_plugin + +from ...settings import PiecesSettings +from .onboarding_handler import PiecesOnBoardingHandlerCommand +class PiecesOnboardingCommand(sublime_plugin.WindowCommand): + + def run(self): + self.view = self.window.new_file(syntax = PiecesSettings.ONBOARDING_SYNTAX) + # append the on_boarding_views + PiecesOnBoardingHandlerCommand.on_boarding_views[self.view.id()] = [] + # Set the name + self.view.set_name("Welcome to Pieces!") + # Set it to scratch to avoid the default saving menu + self.view.set_scratch(True) + # set the color scheme + self.view.settings().set("color_scheme",PiecesSettings.ONBOARDING_COLOR_SCHEME) + # Remove lines numbers from the gutter + self.view.settings().set("line_numbers", False) + # reload the view + self.view.run_command("pieces_on_boarding_handler") + + diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py new file mode 100644 index 0000000..69fa390 --- /dev/null +++ b/misc/on_boarding/onboarding_handler.py @@ -0,0 +1,84 @@ +import sublime_plugin +import sublime +import textwrap +import re + +from ...settings import PiecesSettings +from ...api import version_check +from ... import PiecesDependencies + + + +class PiecesOnBoardingHandlerCommand(sublime_plugin.TextCommand): + on_boarding_views = {} # Store the view id : some meta data + def run(self,edit,mode="reload",point = None): + self.edit = edit + if mode == "reload": + self.reload() + elif mode == "hover": + self.show_popup(point=point) + + def show_popup(point): + popup_details = on_boarding_views[self.view.id()] + for popup in popup_details: + if point in popup["region"]: + print(popup["url"]) + + + def reload(self): + text = f"{self.pieces_os_status()}\n{self.dependencies_status()}" + text = self.store_text_url(text) + + # Get the entire region of the view + entire_region = sublime.Region(0, self.view.size()) + # set read only false + self.view.set_read_only(False) + # Erase the entire region + self.view.erase(self.edit, entire_region) + self.view.run_command('append', {'characters': text}) + # Set readonly + self.view.set_read_only(True) + + @staticmethod + def pieces_os_status(): + if PiecesSettings().get_health(): + check_version,update = version_check() + if not check_version: + return f"[Failed] You need to update {update}" + return '[Success] Installed Pieces OS' + return "[Failed] Please install Pieces OS" + + @staticmethod + def dependencies_status(): + if PiecesDependencies.downloading: + return "[In Progress] Downloading some dependencies" + return "[Success] Downloaded some dependencies successfully" + + + + def store_text_url(self,text): + # Regular expression to find command tags + command_pattern = re.compile(r'(.*?)') + + new_text = text + offset = 0 + + for match in command_pattern.finditer(text): + # Get the span of the command text + start, end = match.span(2) + region = (start + offset, end + offset) + + # Replace the command text with something else + replacement = match.group(2) + new_text = new_text[:region[0]] + replacement + new_text[region[1]:] + + # Calculate the new offset + offset += len(replacement) - (end - start) + + # Update the region after replacement + new_region = sublime.Region(region[0], region[0] + len(replacement)) + + # Store the region and the command + self.on_boarding_views[self.view.id()].append({"region":new_region,"url":match.group(1)}) + + return new_text \ No newline at end of file diff --git a/misc/onboarding.py b/misc/onboarding.py new file mode 100644 index 0000000..d1b1882 --- /dev/null +++ b/misc/onboarding.py @@ -0,0 +1,27 @@ +import sublime_plugin +from ..settings import PiecesSettings + + +class PiecesOnboardingCommand(sublime_plugin.WindowCommand): + def run(self): + view = self.window.new_file(syntax=PiecesSettings.ONBOARDING_SYNTAX) + + text = """ +[Success] Installed pieces +[Failed] Downloading dependencies +[In Progress] Run your first command + """.strip() + + + # Insert the text + view.run_command('append', {'characters': text}) + # Set the name + view.set_name("Welcome to Pieces!") + # Set it to scratch to avoid the default saving menu + view.set_scratch(True) + # Set readonly + view.set_read_only(True) + # set the color scheme + view.settings().set("color_scheme",PiecesSettings.ONBOARDING_COLOR_SCHEME) + + view.settings().set("line_numbers", False) \ No newline at end of file From 8edb9e99e2b187041e27d42a437a45e530fa264c Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:56:46 +0300 Subject: [PATCH 04/15] fix onboarding settings --- settings.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/settings.py b/settings.py index 989090f..ba87784 100644 --- a/settings.py +++ b/settings.py @@ -16,9 +16,10 @@ class PiecesSettings: model_name = "" api_client = None _is_loaded = False # is the plugin loaded + _color_scheme = None # default color scheme - # Load the settings from 'pieces.sublime-settings' file using Sublime Text API - settings = sublime.load_settings('Pieces.sublime-settings') + ONBOARDING_SYNTAX = "Packages/Pieces/syntax/Onboarding.sublime-syntax" + ONBOARDING_COLOR_SCHEME = "User/Pieces/Pieces.hidden-color-scheme" @property @@ -33,6 +34,7 @@ def is_loaded(self,is_loaded): self._is_loaded = is_loaded + @classmethod def get_health(cls): """ @@ -58,7 +60,7 @@ def host_init(cls): This method sets the host URL based on the configuration settings. If the host URL is not provided in the settings, it defaults to a specific URL based on the platform. It then creates the WebSocket base URL and defines the WebSocket URLs for different API endpoints. """ - cls.host = cls.settings.get('host') + cls.host = cls.pieces_settings.get('host') if not cls.host: if 'linux' == sublime.platform(): cls.host = "http://localhost:5323" @@ -88,7 +90,7 @@ def models_init(cls): """ models = cls.get_models_ids() - cls.model_name = cls.settings.get("model") + cls.model_name = cls.pieces_settings.get("model") cls.model_id = models.get(cls.model_name,None) if not cls.model_id: @@ -97,9 +99,9 @@ def models_init(cls): @classmethod def on_settings_change(cls): - if cls.host != cls.settings.get('host'): + if cls.host != cls.pieces_settings.get('host'): cls.host_init() - if cls.model_name != cls.settings.get("model"): + if cls.model_name != cls.pieces_settings.get("model"): cls.models_init() @@ -143,3 +145,9 @@ def create_auth_output_panel(cls): cls.output_panel.settings().set("gutter", False) cls.output_panel.set_read_only(True) + + + # Load the settings from 'Pieces.sublime-settings' file using Sublime Text API + pieces_settings = sublime.load_settings('Pieces.sublime-settings') + pieces_settings.add_on_change("PIECES_SETTINGS",on_settings_change) + From 349b34367bb79b1bea0a25ac19f558c008193bdc Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:57:00 +0300 Subject: [PATCH 05/15] add onboarding event listener --- event_listener.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/event_listener.py b/event_listener.py index 2a2fae2..0f5e803 100644 --- a/event_listener.py +++ b/event_listener.py @@ -5,10 +5,12 @@ from .assets.list_assets import PiecesListAssetsCommand from .settings import PiecesSettings from .base_websocket import BaseWebsocket +from .misc import PiecesOnBoardingHandlerCommand class PiecesEventListener(sublime_plugin.EventListener): - commands_to_exclude = ["pieces_handle_markdown","pieces_reload","pieces_support"] + commands_to_exclude = ["pieces_handle_markdown","pieces_reload" + ,"pieces_support","pieces_onboarding"] def on_window_command(self, window, command_name, args): self.check(command_name) @@ -36,3 +38,11 @@ def on_pre_close(self,view): view.window().run_command("pieces_handle_markdown",{"mode": "save"}) return view.window().run_command("pieces_list_assets",{"pieces_asset_id":asset_id}) + + def on_activated(self,view): + if view in PiecesOnBoardingHandlerCommand.on_boarding_views: + view.run_command("pieces_on_boarding_handler",args={"mode":"reload"}) + + def on_hover(self,view, point, hover_zone): + if view in PiecesOnBoardingHandlerCommand.on_boarding_views and hover_zone == 1: # Text is selected + view.run_command("pieces_on_boarding_handler",args={"mode":"hover","point":point}) \ No newline at end of file From 8888f6211cc00f43c08824b8ac44f43e254da8b7 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 12:57:16 +0300 Subject: [PATCH 06/15] add onboarding to the commands --- Pieces.sublime-commands | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Pieces.sublime-commands b/Pieces.sublime-commands index 52edbd2..3044c9c 100644 --- a/Pieces.sublime-commands +++ b/Pieces.sublime-commands @@ -31,5 +31,9 @@ { "caption": "Pieces: Reload Plugin", "command": "pieces_reload" + }, + { + "caption": "Pieces: Launch Onboarding", + "command": "pieces_onboarding" } ] \ No newline at end of file From e615314cb09cfd9b3043c41f6f8914c7cc494688 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 27 May 2024 13:01:43 +0300 Subject: [PATCH 07/15] fix the version check --- api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api.py b/api.py index 930acae..34cde00 100644 --- a/api.py +++ b/api.py @@ -64,12 +64,12 @@ def version_check(): print("Please update your Pieces Sublime Package is up-to-date. It is not compatible with the current Pieces OS version") print() print_version_details(pieces_os_version, __version__) - return False,"Pieces OS" + return False,"the Pieces Sublime Package" elif os_version_parsed < min_version_parsed: print("Please update your Pieces OS. It is not compatible with the current cli-agent version") print() print_version_details(pieces_os_version, __version__) - return False,"The Pieces sublime package" + return False,"Pieces OS" return True,None def print_version_details(pieces_os_version, __version__): From 09f1f226126eaf196ed7d3f57abd61ed91761cd8 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Mon, 3 Jun 2024 20:00:29 +0300 Subject: [PATCH 08/15] add more onboarding steps --- event_listener.py | 8 +- misc/on_boarding/onboarding_command.py | 4 +- misc/on_boarding/onboarding_handler.py | 149 ++++++++++++++++++------- 3 files changed, 110 insertions(+), 51 deletions(-) diff --git a/event_listener.py b/event_listener.py index 0f5e803..a9cf45d 100644 --- a/event_listener.py +++ b/event_listener.py @@ -40,9 +40,5 @@ def on_pre_close(self,view): view.window().run_command("pieces_list_assets",{"pieces_asset_id":asset_id}) def on_activated(self,view): - if view in PiecesOnBoardingHandlerCommand.on_boarding_views: - view.run_command("pieces_on_boarding_handler",args={"mode":"reload"}) - - def on_hover(self,view, point, hover_zone): - if view in PiecesOnBoardingHandlerCommand.on_boarding_views and hover_zone == 1: # Text is selected - view.run_command("pieces_on_boarding_handler",args={"mode":"hover","point":point}) \ No newline at end of file + if view.settings().to_dict().get("pieces_onboarding",False): + view.run_command("pieces_on_boarding_handler") diff --git a/misc/on_boarding/onboarding_command.py b/misc/on_boarding/onboarding_command.py index d3f12b7..7a31938 100644 --- a/misc/on_boarding/onboarding_command.py +++ b/misc/on_boarding/onboarding_command.py @@ -6,8 +6,6 @@ class PiecesOnboardingCommand(sublime_plugin.WindowCommand): def run(self): self.view = self.window.new_file(syntax = PiecesSettings.ONBOARDING_SYNTAX) - # append the on_boarding_views - PiecesOnBoardingHandlerCommand.on_boarding_views[self.view.id()] = [] # Set the name self.view.set_name("Welcome to Pieces!") # Set it to scratch to avoid the default saving menu @@ -16,6 +14,8 @@ def run(self): self.view.settings().set("color_scheme",PiecesSettings.ONBOARDING_COLOR_SCHEME) # Remove lines numbers from the gutter self.view.settings().set("line_numbers", False) + # Set this view to be a onboarding view + self.view.settings().set("pieces_onboarding",True) # reload the view self.view.run_command("pieces_on_boarding_handler") diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py index 69fa390..ec38de0 100644 --- a/misc/on_boarding/onboarding_handler.py +++ b/misc/on_boarding/onboarding_handler.py @@ -2,51 +2,74 @@ import sublime import textwrap import re +import time from ...settings import PiecesSettings -from ...api import version_check +from ...api import version_check,open_pieces_os from ... import PiecesDependencies + + class PiecesOnBoardingHandlerCommand(sublime_plugin.TextCommand): - on_boarding_views = {} # Store the view id : some meta data - def run(self,edit,mode="reload",point = None): - self.edit = edit - if mode == "reload": - self.reload() - elif mode == "hover": - self.show_popup(point=point) + calls = {} + clearing_time = time.time() - def show_popup(point): - popup_details = on_boarding_views[self.view.id()] - for popup in popup_details: - if point in popup["region"]: - print(popup["url"]) + lazy_load_status = { + "pieces_os_status":"[Loading] Checking Pieces OS", + } # Maps a function name to the status to be displayed when it is loading - def reload(self): - text = f"{self.pieces_os_status()}\n{self.dependencies_status()}" - text = self.store_text_url(text) + def run(self,_): + self.reload() - # Get the entire region of the view - entire_region = sublime.Region(0, self.view.size()) + + def reload(self): + text = f"{self.pieces_os_status()}\n{self.dependencies_status()}\n{self.create_command_status()}" # set read only false self.view.set_read_only(False) # Erase the entire region - self.view.erase(self.edit, entire_region) - self.view.run_command('append', {'characters': text}) + self.view.run_command("select_all") + self.view.run_command("right_delete") + # Appending + self.append_view(text) + # Set readonly self.view.set_read_only(True) - - @staticmethod + + + def _lazy_load(func): + def wrapper(self,*args, **kwargs): + """ + Wrapper will be used on the function that takes time to load + it will return a placeholder with loading utill it is loaded + """ + if self.clearing_time < time.time(): + self.clearing_time = time.time() + 20 + self.calls = {} + + def load_function(): + self.calls[func.__name__] = func(*args, **kwargs) + self.reload() + + if self.calls.get(func.__name__): + return self.calls[func.__name__] + else: + sublime.set_timeout_async(load_function,0) + return self.lazy_load_status.get(func.__name__,"[Loading]") + return wrapper + + + @_lazy_load def pieces_os_status(): if PiecesSettings().get_health(): check_version,update = version_check() if not check_version: - return f"[Failed] You need to update {update}" + return f'[Failed] You need to update {update}' return '[Success] Installed Pieces OS' - return "[Failed] Please install Pieces OS" + return '[Failed] Pieces OS is not running open Pieces OS' + @staticmethod def dependencies_status(): @@ -54,31 +77,71 @@ def dependencies_status(): return "[In Progress] Downloading some dependencies" return "[Success] Downloaded some dependencies successfully" + @staticmethod + def create_command_status(): + return '[In Progress] Create your firstasset' + def append_view(self, text): + """This will replace any "a" tag by a phantom in the same place""" + # Regular expression to find anchor tags + anchor_pattern = re.compile(r'(.*?)') - def store_text_url(self,text): - # Regular expression to find command tags - command_pattern = re.compile(r'(.*?)') - - new_text = text + phantoms = [] + new_text = "" + last_end = 0 offset = 0 - for match in command_pattern.finditer(text): - # Get the span of the command text - start, end = match.span(2) - region = (start + offset, end + offset) + for match in anchor_pattern.finditer(text): + # Extract URL and text from anchor tag + url = match.group(1) + anchor_text = match.group(2) + + # Create phantom HTML + phantom_html = f'{anchor_text}' + + # Find the start and end positions of the match in the original text + start_pos = match.start() + end_pos = match.end() + + # Calculate the position in the new text without the anchor tags + adjusted_start_pos = start_pos - offset + adjusted_end_pos = adjusted_start_pos + len(anchor_text) + + # Add phantom + phantoms.append({"region": sublime.Region(adjusted_start_pos, adjusted_end_pos), "html": phantom_html}) + + # Append the text before the match and the anchor text (without tags) to the new text + new_text += text[last_end:start_pos] + last_end = end_pos + + # Update the offset to account for the removed anchor tags + offset += len(match.group(0)) - len(anchor_text) + + # Append the remaining text after the last match + new_text += text[last_end:] + + self.view.erase_phantoms("pieces") + # Append the modified text to the view + self.view.run_command('append', {'characters': new_text}) - # Replace the command text with something else - replacement = match.group(2) - new_text = new_text[:region[0]] + replacement + new_text[region[1]:] + # Add phantoms after append command + for phantom in phantoms: + self.view.add_phantom("pieces", phantom["region"], phantom["html"], sublime.LAYOUT_INLINE, on_navigate=self.on_nav) - # Calculate the new offset - offset += len(replacement) - (end - start) - # Update the region after replacement - new_region = sublime.Region(region[0], region[0] + len(replacement)) + def on_nav(self,href): + if href == "open_pieces": + def run_async(): + version = open_pieces_os() + if version: + self.calls = {} # Clear the cache + self.reload() + sublime.set_timeout_async(run_async) - # Store the region and the command - self.on_boarding_views[self.view.id()].append({"region":new_region,"url":match.group(1)}) - return new_text \ No newline at end of file + elif href == "create_asset": + new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") + new_file.run_command("append",{"characters":"print('I love Pieces')"}) + new_file.run_command("select_all") + new_file.set_scratch(True) + new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Save to Pieces'") From 4fa8871c23d664efbbe682142a4bd358ec75e542 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Fri, 7 Jun 2024 22:32:42 +0300 Subject: [PATCH 09/15] fix onboarding in create_asset --- event_listener.py | 2 ++ main.py | 4 +-- misc/on_boarding/generate_color_scheme.py | 10 ++------ misc/on_boarding/onboarding_handler.py | 31 ++++++++++++++++++++--- misc/onboarding.py | 27 -------------------- settings.py | 7 ++++- 6 files changed, 38 insertions(+), 43 deletions(-) delete mode 100644 misc/onboarding.py diff --git a/event_listener.py b/event_listener.py index a9cf45d..66880e4 100644 --- a/event_listener.py +++ b/event_listener.py @@ -17,6 +17,8 @@ def on_window_command(self, window, command_name, args): def on_text_command(self,view,command_name,args): self.check(command_name) + if command_name == "pieces_create_asset": + PiecesOnBoardingHandlerCommand.add_onboarding_settings(create_asset=True) def check(self,command_name): if command_name.startswith("pieces_") and command_name not in PiecesEventListener.commands_to_exclude: # Check any command diff --git a/main.py b/main.py index 1ceaea8..5be13fb 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,6 @@ from .settings import PiecesSettings import sublime -import asyncio # load the commands from .assets import * @@ -40,8 +39,7 @@ def startup(): # User Weboscket PiecesSettings.create_auth_output_panel() - AuthWebsocket(AuthUser.on_user_callback).start() # Load the stream user websocket - + AuthWebsocket(AuthUser.on_user_callback).start() # Load the stream user websocket def plugin_loaded(): sublime.set_timeout_async(startup,0) diff --git a/misc/on_boarding/generate_color_scheme.py b/misc/on_boarding/generate_color_scheme.py index 2666f91..316e6e4 100644 --- a/misc/on_boarding/generate_color_scheme.py +++ b/misc/on_boarding/generate_color_scheme.py @@ -73,16 +73,10 @@ def generate_color_scheme(cls): globals_,variables = cls.load_resource(resource_str,color_scheme) path = os.path.join( - sublime.packages_path(), - PiecesSettings.ONBOARDING_COLOR_SCHEME + PiecesSettings.PIECES_USER_DIRECTORY, + PiecesSettings.ONBOARDING_COLOR_SCHEME.split("/")[-1] # The name of the color scheme ) - directory = os.path.dirname(path) - - if not os.path.exists(directory): - os.makedirs(directory) - - with open(path, 'w') as f: json.dump(cls.get_color_scheme(globals_,variables), f,indent=4) diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py index ec38de0..c5440da 100644 --- a/misc/on_boarding/onboarding_handler.py +++ b/misc/on_boarding/onboarding_handler.py @@ -1,8 +1,9 @@ import sublime_plugin import sublime -import textwrap import re import time +import os +import json from ...settings import PiecesSettings from ...api import version_check,open_pieces_os @@ -11,7 +12,6 @@ - class PiecesOnBoardingHandlerCommand(sublime_plugin.TextCommand): calls = {} clearing_time = time.time() @@ -20,6 +20,7 @@ class PiecesOnBoardingHandlerCommand(sublime_plugin.TextCommand): "pieces_os_status":"[Loading] Checking Pieces OS", } # Maps a function name to the status to be displayed when it is loading + ONBOARDING_SETTINGS_PATH = os.path.join(PiecesSettings.PIECES_USER_DIRECTORY, "onboarding_settings.json") def run(self,_): self.reload() @@ -77,8 +78,10 @@ def dependencies_status(): return "[In Progress] Downloading some dependencies" return "[Success] Downloaded some dependencies successfully" - @staticmethod - def create_command_status(): + def create_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("create_asset"): + return '[Success] Asset created successfully' return '[In Progress] Create your firstasset' def append_view(self, text): @@ -143,5 +146,25 @@ def run_async(): new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") new_file.run_command("append",{"characters":"print('I love Pieces')"}) new_file.run_command("select_all") + new_file.set_name("Create your first asset!") new_file.set_scratch(True) new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Save to Pieces'") + + @classmethod + def get_onboarding_settings(cls): + if not os.path.exists(cls.ONBOARDING_SETTINGS_PATH): + return {} + with open(cls.ONBOARDING_SETTINGS_PATH,"r") as f: + return json.load(f) + + @classmethod + def add_onboarding_settings(cls, **kwargs): + # Load existing settings + data = cls.get_onboarding_settings() + + # Update the settings with the new kwargs + data.update(kwargs) + + + with open(cls.ONBOARDING_SETTINGS_PATH, "w") as f: + json.dump(data, f, indent=4) \ No newline at end of file diff --git a/misc/onboarding.py b/misc/onboarding.py deleted file mode 100644 index d1b1882..0000000 --- a/misc/onboarding.py +++ /dev/null @@ -1,27 +0,0 @@ -import sublime_plugin -from ..settings import PiecesSettings - - -class PiecesOnboardingCommand(sublime_plugin.WindowCommand): - def run(self): - view = self.window.new_file(syntax=PiecesSettings.ONBOARDING_SYNTAX) - - text = """ -[Success] Installed pieces -[Failed] Downloading dependencies -[In Progress] Run your first command - """.strip() - - - # Insert the text - view.run_command('append', {'characters': text}) - # Set the name - view.set_name("Welcome to Pieces!") - # Set it to scratch to avoid the default saving menu - view.set_scratch(True) - # Set readonly - view.set_read_only(True) - # set the color scheme - view.settings().set("color_scheme",PiecesSettings.ONBOARDING_COLOR_SCHEME) - - view.settings().set("line_numbers", False) \ No newline at end of file diff --git a/settings.py b/settings.py index ba87784..ee21c3d 100644 --- a/settings.py +++ b/settings.py @@ -3,6 +3,7 @@ from typing import Optional,Dict,Union import urllib import json +import os from . import __version__ @@ -20,7 +21,11 @@ class PiecesSettings: ONBOARDING_SYNTAX = "Packages/Pieces/syntax/Onboarding.sublime-syntax" ONBOARDING_COLOR_SCHEME = "User/Pieces/Pieces.hidden-color-scheme" - + PIECES_USER_DIRECTORY = os.path.join(sublime.packages_path(),"User","Pieces") + + # Create the pieces directory to store the data if it does not exists + if not os.path.exists(PIECES_USER_DIRECTORY): + os.makedirs(PIECES_USER_DIRECTORY) @property def is_loaded(self): From 7c543177a1e816d2d1dad594837655979c397e1d Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Fri, 7 Jun 2024 22:54:52 +0300 Subject: [PATCH 10/15] add the search for snippet --- event_listener.py | 16 ++++++++++++---- misc/on_boarding/onboarding_handler.py | 20 +++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/event_listener.py b/event_listener.py index 66880e4..07ca95a 100644 --- a/event_listener.py +++ b/event_listener.py @@ -4,7 +4,6 @@ from .assets.markdown_handler import PiecesHandleMarkdownCommand from .assets.list_assets import PiecesListAssetsCommand from .settings import PiecesSettings -from .base_websocket import BaseWebsocket from .misc import PiecesOnBoardingHandlerCommand @@ -12,13 +11,19 @@ class PiecesEventListener(sublime_plugin.EventListener): commands_to_exclude = ["pieces_handle_markdown","pieces_reload" ,"pieces_support","pieces_onboarding"] + onboarding_commands_dict = { + "pieces_search":"create_asset", + "pieces_serach":"search" + } + def on_window_command(self, window, command_name, args): self.check(command_name) + self.check_onboarding(command_name) def on_text_command(self,view,command_name,args): self.check(command_name) - if command_name == "pieces_create_asset": - PiecesOnBoardingHandlerCommand.add_onboarding_settings(create_asset=True) + self.check_onboarding(command_name) + def check(self,command_name): if command_name.startswith("pieces_") and command_name not in PiecesEventListener.commands_to_exclude: # Check any command @@ -29,7 +34,10 @@ def check(self,command_name): return False return None - + def check_onboarding(self,command_name): + if command_name not in self.onboarding_commands_dict: + return + PiecesOnBoardingHandlerCommand.add_onboarding_settings(**{self.onboarding_commands_dict[command_name] : True}) def on_pre_close(self,view): asset_id = PiecesHandleMarkdownCommand.views_to_handle.get(view.id()) diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py index c5440da..a53b193 100644 --- a/misc/on_boarding/onboarding_handler.py +++ b/misc/on_boarding/onboarding_handler.py @@ -27,7 +27,7 @@ def run(self,_): def reload(self): - text = f"{self.pieces_os_status()}\n{self.dependencies_status()}\n{self.create_command_status()}" + text = f"{self.pieces_os_status()}\n{self.dependencies_status()}\n{self.create_command_status()}\n{self.search_command_status()}" # set read only false self.view.set_read_only(False) # Erase the entire region @@ -81,9 +81,16 @@ def dependencies_status(): def create_command_status(self): settings = self.get_onboarding_settings() if settings.get("create_asset"): - return '[Success] Asset created successfully' + return '[Success] Asset created successfully!' return '[In Progress] Create your firstasset' + def search_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("search"): + return '[Success] You searched an asset!' + return '[In Progress]Searchan asset' + + def append_view(self, text): """This will replace any "a" tag by a phantom in the same place""" # Regular expression to find anchor tags @@ -149,7 +156,14 @@ def run_async(): new_file.set_name("Create your first asset!") new_file.set_scratch(True) new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Save to Pieces'") - + + elif href == "search": + self.view.window().run_command("show_overlay",{"overlay": "command_palette"}) + clipboard = sublime.get_clipboard() + sublime.set_clipboard("Pieces: Search") + self.view.window().run_command("paste") + sublime.set_clipboard(clipboard) # To avoid overighting the user clipboard + @classmethod def get_onboarding_settings(cls): if not os.path.exists(cls.ONBOARDING_SETTINGS_PATH): From 6fcd6ee1be21b2b5e88e18fc60ae406e73944860 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Wed, 12 Jun 2024 23:40:15 +0300 Subject: [PATCH 11/15] add new command --- event_listener.py | 5 ++- misc/on_boarding/onboarding_command.py | 4 +- misc/on_boarding/onboarding_handler.py | 60 ++++++++++++++++---------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/event_listener.py b/event_listener.py index 07ca95a..0227292 100644 --- a/event_listener.py +++ b/event_listener.py @@ -12,8 +12,9 @@ class PiecesEventListener(sublime_plugin.EventListener): ,"pieces_support","pieces_onboarding"] onboarding_commands_dict = { - "pieces_search":"create_asset", - "pieces_serach":"search" + "pieces_create_asset":"create_asset", + "pieces_list_assets":"open", + "pieces_ask_question":"ask_question" } def on_window_command(self, window, command_name, args): diff --git a/misc/on_boarding/onboarding_command.py b/misc/on_boarding/onboarding_command.py index 7a31938..47f26af 100644 --- a/misc/on_boarding/onboarding_command.py +++ b/misc/on_boarding/onboarding_command.py @@ -2,12 +2,12 @@ from ...settings import PiecesSettings from .onboarding_handler import PiecesOnBoardingHandlerCommand + class PiecesOnboardingCommand(sublime_plugin.WindowCommand): - def run(self): self.view = self.window.new_file(syntax = PiecesSettings.ONBOARDING_SYNTAX) # Set the name - self.view.set_name("Welcome to Pieces!") + self.view.set_name("Welcome to Pieces 🎉🎉!") # Set it to scratch to avoid the default saving menu self.view.set_scratch(True) # set the color scheme diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py index a53b193..1f41e37 100644 --- a/misc/on_boarding/onboarding_handler.py +++ b/misc/on_boarding/onboarding_handler.py @@ -27,7 +27,10 @@ def run(self,_): def reload(self): - text = f"{self.pieces_os_status()}\n{self.dependencies_status()}\n{self.create_command_status()}\n{self.search_command_status()}" + text = "\n".join( + [self.pieces_os_status(),self.dependencies_status(), + self.create_command_status(),self.open_asset_command_status(),self.ask_question_command_status()] + ) # set read only false self.view.set_read_only(False) # Erase the entire region @@ -38,7 +41,7 @@ def reload(self): # Set readonly self.view.set_read_only(True) - + def _lazy_load(func): def wrapper(self,*args, **kwargs): @@ -84,12 +87,17 @@ def create_command_status(self): return '[Success] Asset created successfully!' return '[In Progress] Create your firstasset' - def search_command_status(self): + def open_asset_command_status(self): settings = self.get_onboarding_settings() - if settings.get("search"): - return '[Success] You searched an asset!' - return '[In Progress]Searchan asset' + if settings.get("open"): + return '[Success] You opened an asset' + return '[In Progress] Openan asset' + def ask_question_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("ask_question"): + return '[Success] Bug solved!' + return '[In Progress] Askfor help and bug fixes' def append_view(self, text): """This will replace any "a" tag by a phantom in the same place""" @@ -115,30 +123,29 @@ def append_view(self, text): # Calculate the position in the new text without the anchor tags adjusted_start_pos = start_pos - offset - adjusted_end_pos = adjusted_start_pos + len(anchor_text) + adjusted_end_pos = adjusted_start_pos # Add phantom phantoms.append({"region": sublime.Region(adjusted_start_pos, adjusted_end_pos), "html": phantom_html}) - # Append the text before the match and the anchor text (without tags) to the new text + # Append the text before the match to the new text new_text += text[last_end:start_pos] last_end = end_pos # Update the offset to account for the removed anchor tags - offset += len(match.group(0)) - len(anchor_text) + offset += len(match.group(0)) + self.view.erase_phantoms("pieces_phantom") # Append the remaining text after the last match new_text += text[last_end:] - self.view.erase_phantoms("pieces") # Append the modified text to the view self.view.run_command('append', {'characters': new_text}) # Add phantoms after append command for phantom in phantoms: - self.view.add_phantom("pieces", phantom["region"], phantom["html"], sublime.LAYOUT_INLINE, on_navigate=self.on_nav) - - + self.view.add_phantom("pieces_phantom",phantom["region"], phantom["html"], sublime.LAYOUT_INLINE, on_navigate=self.on_nav) + def on_nav(self,href): if href == "open_pieces": def run_async(): @@ -153,16 +160,19 @@ def run_async(): new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") new_file.run_command("append",{"characters":"print('I love Pieces')"}) new_file.run_command("select_all") - new_file.set_name("Create your first asset!") + new_file.set_name("Create your first asset 🆕") new_file.set_scratch(True) new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Save to Pieces'") - - elif href == "search": - self.view.window().run_command("show_overlay",{"overlay": "command_palette"}) - clipboard = sublime.get_clipboard() - sublime.set_clipboard("Pieces: Search") - self.view.window().run_command("paste") - sublime.set_clipboard(clipboard) # To avoid overighting the user clipboard + elif href == "ask_question": + new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") + new_file.run_command("append",{"characters":"I Love Pieces.upper()"}) + new_file.run_command("select_all") + new_file.set_name("Ask for bug fix 🤔") + new_file.set_scratch(True) + new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Ask Copilot > Fix Bug'") + + elif href == "open": + self.view.window().run_command("pieces_list_assets") @classmethod def get_onboarding_settings(cls): @@ -179,6 +189,10 @@ def add_onboarding_settings(cls, **kwargs): # Update the settings with the new kwargs data.update(kwargs) - + print(data) with open(cls.ONBOARDING_SETTINGS_PATH, "w") as f: - json.dump(data, f, indent=4) \ No newline at end of file + json.dump(data, f, indent=4) + +if not PiecesOnBoardingHandlerCommand.get_onboarding_settings().get("lunch_onboarding",False): + sublime.active_window().run_command("pieces_onboarding") + PiecesOnBoardingHandlerCommand.add_onboarding_settings(lunch_onboarding=True) \ No newline at end of file From 4fbbb0ceb94773d6560ab78f06619ca2bb030b5f Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Wed, 26 Jun 2024 11:46:38 +0300 Subject: [PATCH 12/15] merge into main --- misc/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/misc/__init__.py b/misc/__init__.py index eb031f4..6870e51 100644 --- a/misc/__init__.py +++ b/misc/__init__.py @@ -1,8 +1,5 @@ from .support_command import PiecesSupportCommand from .reload_command import PiecesReloadCommand -<<<<<<< HEAD from .on_boarding import * -======= from .open_pieces_command import PiecesOpenPiecesCommand from .about_command import PiecesOpenNotesCommand,PiecesAboutCommand ->>>>>>> main From 45a6e808a49cb9c1f0264cbc28d9af5ba9d69bfa Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Wed, 26 Jun 2024 16:14:31 +0300 Subject: [PATCH 13/15] convert to mini html and added more commands --- Context.sublime-menu | 2 +- ask/index.css | 1 - copilot/ask_websocket.py | 2 +- event_listener.py | 19 +- main.py | 10 +- misc/__init__.py | 2 +- misc/on_boarding/__init__.py | 4 - misc/on_boarding/generate_color_scheme.py | 82 ------ misc/on_boarding/onboarding_command.py | 22 -- misc/on_boarding/onboarding_handler.py | 198 -------------- misc/onboarding_command.py | 303 ++++++++++++++++++++++ streamed_identifiers.py | 3 +- syntax/Onboarding.sublime-syntax | 37 --- 13 files changed, 319 insertions(+), 366 deletions(-) delete mode 100644 misc/on_boarding/__init__.py delete mode 100644 misc/on_boarding/generate_color_scheme.py delete mode 100644 misc/on_boarding/onboarding_command.py delete mode 100644 misc/on_boarding/onboarding_handler.py create mode 100644 misc/onboarding_command.py delete mode 100644 syntax/Onboarding.sublime-syntax diff --git a/Context.sublime-menu b/Context.sublime-menu index 1bed4ae..e2a23f1 100644 --- a/Context.sublime-menu +++ b/Context.sublime-menu @@ -8,7 +8,7 @@ "command": "pieces_create_asset", }, { - "caption": "Generate Shareable link", + "caption": "Generate Shareable Link", "command": "pieces_generate_shareable_link", }, { diff --git a/ask/index.css b/ask/index.css index 9a004f0..b8ff833 100644 --- a/ask/index.css +++ b/ask/index.css @@ -1,4 +1,3 @@ -/* Many thanks to gitgutter! */ html.dark { --popup-background: color(var(--background) blend(white 95%)); --pieces-toolbar-bg: color(var(--popup-background) blend(white 95%)); diff --git a/copilot/ask_websocket.py b/copilot/ask_websocket.py index 49b0ae0..466b03b 100644 --- a/copilot/ask_websocket.py +++ b/copilot/ask_websocket.py @@ -1,5 +1,5 @@ from .._pieces_lib.pieces_os_client import QGPTStreamOutput,QGPTStreamInput -from websocket import WebSocketConnectionClosedException +from .._pieces_lib.websocket import WebSocketConnectionClosedException from ..settings import PiecesSettings from ..base_websocket import BaseWebsocket diff --git a/event_listener.py b/event_listener.py index e78be75..068f1b2 100644 --- a/event_listener.py +++ b/event_listener.py @@ -3,18 +3,20 @@ from .assets.list_assets import PiecesListAssetsCommand from .settings import PiecesSettings -from .misc import PiecesOnBoardingHandlerCommand +from .misc import PiecesOnboardingCommand from .copilot.ask_command import copilot class PiecesEventListener(sublime_plugin.EventListener): - commands_to_exclude = ["pieces_handle_markdown","pieces_reload" - ,"pieces_support","pieces_onboarding"] + commands_to_exclude = ["pieces_onboarding","pieces_reload","pieces_support"] onboarding_commands_dict = { - "pieces_create_asset":"create_asset", + "pieces_create_asset":"create", "pieces_list_assets":"open", - "pieces_ask_question":"ask_question" + "pieces_ask_question":"ask", + "pieces_search":"search", + "pieces_ask_stream":"copilot", + "pieces_share_asset":"share" } def on_window_command(self, window, command_name, args): @@ -42,7 +44,7 @@ def check(self,command_name): def check_onboarding(self,command_name): if command_name not in self.onboarding_commands_dict: return - PiecesOnBoardingHandlerCommand.add_onboarding_settings(**{self.onboarding_commands_dict[command_name] : True}) + PiecesOnboardingCommand.add_onboarding_settings(**{self.onboarding_commands_dict[command_name] : True}) def on_pre_close(self,view): sheet_id = view.settings().get("pieces_sheet_id") @@ -60,11 +62,6 @@ def on_pre_close(self,view): return sublime.active_window().run_command("pieces_list_assets",{"pieces_asset_id":asset_id}) - - def on_activated(self,view): - if view.settings().to_dict().get("pieces_onboarding",False): - view.run_command("pieces_on_boarding_handler") - def on_query_context(self,view,key, operator, operand, match_all): diff --git a/main.py b/main.py index 8cf77bd..3e349ce 100644 --- a/main.py +++ b/main.py @@ -28,11 +28,6 @@ def startup(settings_model): print_version_details(pieces_version, __version__) PiecesSettings.models_init(settings_model) # Intilize the models - # Preferences settings - preferences_settings = sublime.load_settings('Preferences.sublime-settings') - preferences_settings.add_on_change("PREFERENCES_SETTINGS",ColorSchemeGenerator.generate_color_scheme) - ColorSchemeGenerator.generate_color_scheme() - # WEBSOCKETS: # Assets Identifiers Websocket AssetsIdentifiersWS(AssetSnapshot.streamed_identifiers_callback).start() # Load the assets ws at the startup @@ -45,7 +40,10 @@ def startup(settings_model): # Conversation Websocket ConversationWS(ConversationsSnapshot.streamed_identifiers_callback).start() - + # Lunch Onboarding if it is the first time + if not PiecesOnboardingCommand.get_onboarding_settings().get("lunch_onboarding",False): + sublime.active_window().run_command("pieces_onboarding") + PiecesOnboardingCommand.add_onboarding_settings(lunch_onboarding=True) def plugin_loaded(): global settings # Set it to global to use diff --git a/misc/__init__.py b/misc/__init__.py index 6870e51..91cac2b 100644 --- a/misc/__init__.py +++ b/misc/__init__.py @@ -1,5 +1,5 @@ from .support_command import PiecesSupportCommand from .reload_command import PiecesReloadCommand -from .on_boarding import * from .open_pieces_command import PiecesOpenPiecesCommand from .about_command import PiecesOpenNotesCommand,PiecesAboutCommand +from .onboarding_command import PiecesOnboardingCommand,PiecesOnboardingCommandsCommand,PiecesResetOnboardingCommand diff --git a/misc/on_boarding/__init__.py b/misc/on_boarding/__init__.py deleted file mode 100644 index ce23630..0000000 --- a/misc/on_boarding/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .generate_color_scheme import ColorSchemeGenerator -from .onboarding_command import PiecesOnboardingCommand -from .onboarding_handler import PiecesOnBoardingHandlerCommand - \ No newline at end of file diff --git a/misc/on_boarding/generate_color_scheme.py b/misc/on_boarding/generate_color_scheme.py deleted file mode 100644 index 316e6e4..0000000 --- a/misc/on_boarding/generate_color_scheme.py +++ /dev/null @@ -1,82 +0,0 @@ -import json -import os -import sublime -import ast - -from ...settings import PiecesSettings - - -class ColorSchemeGenerator: - resolved_value = None - - @staticmethod - def load_resource(resource_str, color_scheme): - try: - # Attempt to load the resource as JSON - resource = json.loads(resource_str) - globals_ = resource["globals"] - variables = resource["variables"] - except json.decoder.JSONDecodeError: - try: - # If JSON loading fails, attempt to evaluate the resource string as a Python literal - resource = ast.literal_eval(resource_str) - globals_ = resource["globals"] - variables = resource["variables"] - except (ValueError, SyntaxError): - # If both methods fail, fall back to default values - globals_ = { - "background": "var(background)", - "foreground": "var(foreground)" - } - variables = { - "background": color_scheme["palette"]["background"], - "foreground": color_scheme["palette"]["foreground"] - } - - return globals_, variables - - - @staticmethod - def get_color_scheme(globals_,variables): - return { - "name": "Pieces color scheme", - "globals": globals_, - "variables": variables, - "rules": [ - { - "scope": "pieces.onboarding.success", - "foreground": "#99c794" - }, - { - "scope": "pieces.onboarding.fail", - "foreground": "#ec5f66" - }, - { - "scope":"pieces.onboarding.progress", - "foreground": "#808080" - }, - ] - } - - @classmethod - def generate_color_scheme(cls): - color_scheme = sublime.ui_info()["color_scheme"] - resolved_value = color_scheme["resolved_value"] - - if resolved_value == cls.resolved_value: - return # No change in the color scheme - - # Theme changed! - cls.resolved_value = resolved_value - resource_str = sublime.load_resource(sublime.find_resources(resolved_value)[0]) - - globals_,variables = cls.load_resource(resource_str,color_scheme) - - path = os.path.join( - PiecesSettings.PIECES_USER_DIRECTORY, - PiecesSettings.ONBOARDING_COLOR_SCHEME.split("/")[-1] # The name of the color scheme - ) - - with open(path, 'w') as f: - json.dump(cls.get_color_scheme(globals_,variables), f,indent=4) - diff --git a/misc/on_boarding/onboarding_command.py b/misc/on_boarding/onboarding_command.py deleted file mode 100644 index 47f26af..0000000 --- a/misc/on_boarding/onboarding_command.py +++ /dev/null @@ -1,22 +0,0 @@ -import sublime_plugin - -from ...settings import PiecesSettings -from .onboarding_handler import PiecesOnBoardingHandlerCommand - -class PiecesOnboardingCommand(sublime_plugin.WindowCommand): - def run(self): - self.view = self.window.new_file(syntax = PiecesSettings.ONBOARDING_SYNTAX) - # Set the name - self.view.set_name("Welcome to Pieces 🎉🎉!") - # Set it to scratch to avoid the default saving menu - self.view.set_scratch(True) - # set the color scheme - self.view.settings().set("color_scheme",PiecesSettings.ONBOARDING_COLOR_SCHEME) - # Remove lines numbers from the gutter - self.view.settings().set("line_numbers", False) - # Set this view to be a onboarding view - self.view.settings().set("pieces_onboarding",True) - # reload the view - self.view.run_command("pieces_on_boarding_handler") - - diff --git a/misc/on_boarding/onboarding_handler.py b/misc/on_boarding/onboarding_handler.py deleted file mode 100644 index 1f41e37..0000000 --- a/misc/on_boarding/onboarding_handler.py +++ /dev/null @@ -1,198 +0,0 @@ -import sublime_plugin -import sublime -import re -import time -import os -import json - -from ...settings import PiecesSettings -from ...api import version_check,open_pieces_os -from ... import PiecesDependencies - - - - -class PiecesOnBoardingHandlerCommand(sublime_plugin.TextCommand): - calls = {} - clearing_time = time.time() - - lazy_load_status = { - "pieces_os_status":"[Loading] Checking Pieces OS", - } # Maps a function name to the status to be displayed when it is loading - - ONBOARDING_SETTINGS_PATH = os.path.join(PiecesSettings.PIECES_USER_DIRECTORY, "onboarding_settings.json") - - def run(self,_): - self.reload() - - - def reload(self): - text = "\n".join( - [self.pieces_os_status(),self.dependencies_status(), - self.create_command_status(),self.open_asset_command_status(),self.ask_question_command_status()] - ) - # set read only false - self.view.set_read_only(False) - # Erase the entire region - self.view.run_command("select_all") - self.view.run_command("right_delete") - # Appending - self.append_view(text) - - # Set readonly - self.view.set_read_only(True) - - - def _lazy_load(func): - def wrapper(self,*args, **kwargs): - """ - Wrapper will be used on the function that takes time to load - it will return a placeholder with loading utill it is loaded - """ - if self.clearing_time < time.time(): - self.clearing_time = time.time() + 20 - self.calls = {} - - def load_function(): - self.calls[func.__name__] = func(*args, **kwargs) - self.reload() - - if self.calls.get(func.__name__): - return self.calls[func.__name__] - else: - sublime.set_timeout_async(load_function,0) - return self.lazy_load_status.get(func.__name__,"[Loading]") - return wrapper - - - @_lazy_load - def pieces_os_status(): - if PiecesSettings().get_health(): - check_version,update = version_check() - if not check_version: - return f'[Failed] You need to update {update}' - return '[Success] Installed Pieces OS' - return '[Failed] Pieces OS is not running open Pieces OS' - - - @staticmethod - def dependencies_status(): - if PiecesDependencies.downloading: - return "[In Progress] Downloading some dependencies" - return "[Success] Downloaded some dependencies successfully" - - def create_command_status(self): - settings = self.get_onboarding_settings() - if settings.get("create_asset"): - return '[Success] Asset created successfully!' - return '[In Progress] Create your firstasset' - - def open_asset_command_status(self): - settings = self.get_onboarding_settings() - if settings.get("open"): - return '[Success] You opened an asset' - return '[In Progress] Openan asset' - - def ask_question_command_status(self): - settings = self.get_onboarding_settings() - if settings.get("ask_question"): - return '[Success] Bug solved!' - return '[In Progress] Askfor help and bug fixes' - - def append_view(self, text): - """This will replace any "a" tag by a phantom in the same place""" - # Regular expression to find anchor tags - anchor_pattern = re.compile(r'(.*?)') - - phantoms = [] - new_text = "" - last_end = 0 - offset = 0 - - for match in anchor_pattern.finditer(text): - # Extract URL and text from anchor tag - url = match.group(1) - anchor_text = match.group(2) - - # Create phantom HTML - phantom_html = f'{anchor_text}' - - # Find the start and end positions of the match in the original text - start_pos = match.start() - end_pos = match.end() - - # Calculate the position in the new text without the anchor tags - adjusted_start_pos = start_pos - offset - adjusted_end_pos = adjusted_start_pos - - # Add phantom - phantoms.append({"region": sublime.Region(adjusted_start_pos, adjusted_end_pos), "html": phantom_html}) - - # Append the text before the match to the new text - new_text += text[last_end:start_pos] - last_end = end_pos - - # Update the offset to account for the removed anchor tags - offset += len(match.group(0)) - - self.view.erase_phantoms("pieces_phantom") - # Append the remaining text after the last match - new_text += text[last_end:] - - # Append the modified text to the view - self.view.run_command('append', {'characters': new_text}) - - # Add phantoms after append command - for phantom in phantoms: - self.view.add_phantom("pieces_phantom",phantom["region"], phantom["html"], sublime.LAYOUT_INLINE, on_navigate=self.on_nav) - - def on_nav(self,href): - if href == "open_pieces": - def run_async(): - version = open_pieces_os() - if version: - self.calls = {} # Clear the cache - self.reload() - sublime.set_timeout_async(run_async) - - - elif href == "create_asset": - new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") - new_file.run_command("append",{"characters":"print('I love Pieces')"}) - new_file.run_command("select_all") - new_file.set_name("Create your first asset 🆕") - new_file.set_scratch(True) - new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Save to Pieces'") - elif href == "ask_question": - new_file = self.view.window().new_file(syntax="Packages/Python/Python.sublime-syntax") - new_file.run_command("append",{"characters":"I Love Pieces.upper()"}) - new_file.run_command("select_all") - new_file.set_name("Ask for bug fix 🤔") - new_file.set_scratch(True) - new_file.show_popup("Right click to open your context menu Then go to 'Pieces > Ask Copilot > Fix Bug'") - - elif href == "open": - self.view.window().run_command("pieces_list_assets") - - @classmethod - def get_onboarding_settings(cls): - if not os.path.exists(cls.ONBOARDING_SETTINGS_PATH): - return {} - with open(cls.ONBOARDING_SETTINGS_PATH,"r") as f: - return json.load(f) - - @classmethod - def add_onboarding_settings(cls, **kwargs): - # Load existing settings - data = cls.get_onboarding_settings() - - # Update the settings with the new kwargs - data.update(kwargs) - - print(data) - with open(cls.ONBOARDING_SETTINGS_PATH, "w") as f: - json.dump(data, f, indent=4) - -if not PiecesOnBoardingHandlerCommand.get_onboarding_settings().get("lunch_onboarding",False): - sublime.active_window().run_command("pieces_onboarding") - PiecesOnBoardingHandlerCommand.add_onboarding_settings(lunch_onboarding=True) \ No newline at end of file diff --git a/misc/onboarding_command.py b/misc/onboarding_command.py new file mode 100644 index 0000000..27f913a --- /dev/null +++ b/misc/onboarding_command.py @@ -0,0 +1,303 @@ +from typing import List +import sublime_plugin +import sublime +import time +import os +import json + +from ..settings import PiecesSettings +from ..api import version_check + +CSS = """ +html.dark { + --pieces-forground: color(var(--forground) blend(white 95%)); + --pieces-h1: color(var(--greenish) blend(white 90%)); +} +html.light { + --pieces-forground: color(var(--forground) blend(black 95%)); + --pieces-h1: color(var(--greenish) blend(black 90%)); +} +.container { + padding: 20px; +} +h1 { + color: var(--pieces-h1); +} +p { + font-size: 14px; +} +ul { + list-style-type: disc; + margin-left: 20px; +} +.step { + margin-bottom: 15px; +} +.step-title { + font-weight: bold; + color: var(--pieces-forground); +} +.step-description { + margin-left: 20px; +} +""" + +html_template = """ + + +
+

Welcome to Pieces For Deveopers!

+

Follow these steps to get started:

+
+
Step 1: Pieces OS Installation
+
+ {os_status} +
+
+
+
Step 2: Create your first Snippet
+
+ {create_status} +
+
+
+
Step 3: View your saved snippets
+
+ {open_status} +
+
+
+
Step 4: Search for your saved snippet
+
+ {search_status} +
+
+
+
Step 5: Ask for help
+
+ {ask_status} +
+
+
+
Step 6: Pieces Copilot
+
+ {copilot_status} +
+
+
+
Step 7: Explore the Features
+
+ Check out the documentation to learn about all the features and how to use them effectively. +
+
+
+
Step 8: Get Support
+
+ Feeling stuck or encountering bugs? No worries! Head over to your command palette and select Pieces: Get Support. You'll discover a treasure trove of useful resources to help you out! +
+
+
+
Step 9: Join the Community
+
+ Don't forget to join our community
+ Don't forget also to check the Pieces: About command for your command palette. +
+
+

Enjoy using the Package! :)

+ Reload the view + Rest Onboarding +
+ +""" +def green(text:str) -> str: + return f'{text}' + +def red(text:str) -> str: + return f'{text}' + +def subl_onboarding_commands(title,cmd): + return f"""{title}""" + +class PiecesOnboardingCommand(sublime_plugin.WindowCommand): + SHEET_NAME = "Welcome to Pieces 🎉🎉!" + calls = {} + clearing_time = time.time() + sheet_id = None + + lazy_load_status = { + "pieces_os_status":"Checking Pieces OS", + } # Maps a function name to the status to be displayed when it is loading + + ONBOARDING_SETTINGS_PATH = os.path.join(PiecesSettings.PIECES_USER_DIRECTORY, "onboarding_settings.json") + + def run(self): + sheet = sublime.HtmlSheet(self.sheet_id) if self.sheet_id in self.get_html_sheet_ids() else self.window.new_html_sheet(self.SHEET_NAME,"") + self.sheet_id = sheet.id() + self.reload(sheet) + + @staticmethod + def get_html_sheet_ids() -> List[int]: + ids = [] + for window in sublime.windows(): + for sheet in window.sheets(): + if isinstance(sheet,sublime.HtmlSheet): + ids.append(sheet.id()) + return ids + + def reload(self,sheet): + kwargs = { + "os_status":self.pieces_os_status(), + "create_status":self.create_command_status(), + "open_status":self.open_asset_command_status(), + "search_status":self.search_command_status(), + "ask_status":self.ask_question_command_status(), + "copilot_status":self.copilot_status(), + "css":CSS, + } + sheet.set_contents(html_template.format(**kwargs)) + + + def _lazy_load(func): + def wrapper(self,*args, **kwargs): + """ + Wrapper will be used on the function that takes time to load + it will return a placeholder with loading utill it is loaded + """ + if self.clearing_time < time.time(): + self.clearing_time = time.time() + 20 + self.calls = {} + + def load_function(): + self.calls[func.__name__] = func(*args, **kwargs) + self.reload(sublime.HtmlSheet(self.sheet_id)) + + if self.calls.get(func.__name__): + return self.calls[func.__name__] + else: + sublime.set_timeout_async(load_function,0) + return self.lazy_load_status.get(func.__name__,"[Loading]") + return wrapper + + + @_lazy_load + def pieces_os_status(): + if PiecesSettings().get_health(): + check_version,update = version_check() + if not check_version: + return red(f'You need to update {update}') + return green('Installed Pieces OS is installed successfully') + + return red("Oops! Pieces OS is not running.") + """ +
+ Don't worry, you can easily open Pieces OS and get started right away!
+ Curious to learn more? Click here to explore the full documentation and discover all the amazing features of Pieces OS. + """ + + def create_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("create"): + return green('Congratulations on creating your first snippet! Keep exploring and creating more to enhance your coding experience') + return f"""Snippets {subl_onboarding_commands("creation","create")} are like little treasures of code! Save them, and you'll have a goldmine of solutions. Plus, with a quick search, you can uncover exactly what you need in no time!""" + + def open_asset_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("open"): + return green('Great job! You viewed your saved snippet.') + return 'Click here to explore all your snippets and keep the creativity flowing!' + + def ask_question_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("ask"): + return green('Bug solved! Great job!') + return subl_onboarding_commands("Ask for help and get those bugs fixed!",'ask') + + def search_command_status(self): + settings = self.get_onboarding_settings() + if settings.get("search"): + return green('Seached for snippet successfully!') + return """Ever lost your code snippet and spent hours searching for it? Discover our cutting-edge searching technology that makes finding your snippets a breeze!""" + + + def copilot_status(self): + settings = self.get_onboarding_settings() + if settings.get("copilot"): + return green('Chatted with the copilot successfully!') + return """Looking for your personal Assistant? Ask it any question! Open the copilot and dive into an exciting conversation with it. Discover the possibilities!""" + + def share_status(self): + settings = self.get_onboarding_settings() + if settings.get("share"): + return green("Shared your Snippet successfully") + return f"{subl_onboarding_commands('Generate a shareable link','share')} to share it with others" + + @classmethod + def get_onboarding_settings(cls): + if not os.path.exists(cls.ONBOARDING_SETTINGS_PATH): + return {} + with open(cls.ONBOARDING_SETTINGS_PATH,"r") as f: + return json.load(f) + + @classmethod + def add_onboarding_settings(cls, **kwargs): + # Load existing settings + data = cls.get_onboarding_settings() + + # Update the settings with the new kwargs + data.update(kwargs) + + with open(cls.ONBOARDING_SETTINGS_PATH, "w") as f: + json.dump(data, f, indent=4) + if cls.sheet_id in cls.get_html_sheet_ids(): + sublime.active_window().run_command("pieces_onboarding") # Reload the onboarding command + + + +snippet_create = """ +# Gettings string size in bytes! +str1 = "hello" +str2 = "?" + +def str_size(s): + return len(s.encode('utf-8')) + +str_size(str1) +str_size(str2) +""" + +snippet_ask = """ +def is_palindrome(s): + return s == s[-1] + +print(is_palindrome("A man a plan a canal Panama")) +""" +class PiecesOnboardingCommandsCommand(sublime_plugin.WindowCommand): + def run(self,cmd): + if cmd == "create": + self.create_onboarding_view(snippet_create, + "Create your first asset 🆕", + "Right click to open your context menu Then go to 'Pieces > Save to Pieces'" + ) + elif cmd == "ask": + self.create_onboarding_view(snippet_ask, + "Ask for bug fix 🤔", + "Right click to open your context menu Then go to 'Pieces > Ask Copilot > Fix Bug'" + ) + elif cmd == "share": + self.create_onboarding_view(snippet_create, + "Share a Snippet ✉", + "Right click to open your context menu Then go to 'Pieces > Generate Shareable Link'" + ) + def create_onboarding_view(self,snippet,name,popup_text): + new_file = self.window.new_file(syntax="Packages/Python/Python.sublime-syntax") + new_file.run_command("append",{"characters":snippet}) + new_file.run_command("select_all") + new_file.set_name(name) + new_file.set_scratch(True) + new_file.show_popup(popup_text) + +class PiecesResetOnboardingCommand(sublime_plugin.WindowCommand): + def run(self): + if sublime.yes_no_cancel_dialog("Are you sure you want to rest your onboarding progress"): + os.rmdir(PiecesOnboardingCommand.ONBOARDING_SETTINGS_PATH) \ No newline at end of file diff --git a/streamed_identifiers.py b/streamed_identifiers.py index f40a8ea..8261fa4 100644 --- a/streamed_identifiers.py +++ b/streamed_identifiers.py @@ -22,9 +22,8 @@ class AssetSnapshot(StreamedIdentifiersCache,api_call=AssetApi(PiecesSettings.ap """ import queue -import threading from typing import Dict, Union, Callable -from pieces_os_client import Conversation, StreamedIdentifiers, Asset +from ._pieces_lib.pieces_os_client import Conversation, StreamedIdentifiers, Asset import sublime from abc import ABC,abstractmethod diff --git a/syntax/Onboarding.sublime-syntax b/syntax/Onboarding.sublime-syntax deleted file mode 100644 index 6df9468..0000000 --- a/syntax/Onboarding.sublime-syntax +++ /dev/null @@ -1,37 +0,0 @@ -%YAML 1.2 ---- -name: Onboarding -scope: source.onboarding -hidden: true - -contexts: - main: - - match: '\[Success\]' - push: success - - match: '\[Failed\]' - push: fail - - match: '\[In Progress\]' - push: progress - - success: - - meta_scope: pieces.onboarding.success - - match: '\n' - pop: true - - match: '.+' - scope: pieces.onboarding.success - - fail: - - meta_scope: pieces.onboarding.fail - - match: '\n' - pop: true - - match: '.+' - scope: pieces.onboarding.fail - - - progress: - - meta_scope: pieces.onboarding.progress - - match: '\n' - pop: true - - match: '.+' - scope: pieces.onboarding.progress - From 1a8a3d90baea92e76172860c4b58005efd618bbf Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Wed, 26 Jun 2024 16:18:10 +0300 Subject: [PATCH 14/15] add --- misc/onboarding_command.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/onboarding_command.py b/misc/onboarding_command.py index 27f913a..b182cd2 100644 --- a/misc/onboarding_command.py +++ b/misc/onboarding_command.py @@ -300,4 +300,5 @@ def create_onboarding_view(self,snippet,name,popup_text): class PiecesResetOnboardingCommand(sublime_plugin.WindowCommand): def run(self): if sublime.yes_no_cancel_dialog("Are you sure you want to rest your onboarding progress"): - os.rmdir(PiecesOnboardingCommand.ONBOARDING_SETTINGS_PATH) \ No newline at end of file + os.remove(PiecesOnboardingCommand.ONBOARDING_SETTINGS_PATH) + self.window.run_command("pieces_onboarding") \ No newline at end of file From b74119e5715372769644de4d7979f1b8b6122ea7 Mon Sep 17 00:00:00 2001 From: Bishoy-at-pieces Date: Wed, 26 Jun 2024 16:20:34 +0300 Subject: [PATCH 15/15] capitalized the C in Copilot --- misc/onboarding_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/onboarding_command.py b/misc/onboarding_command.py index b182cd2..92af0ad 100644 --- a/misc/onboarding_command.py +++ b/misc/onboarding_command.py @@ -224,7 +224,7 @@ def copilot_status(self): settings = self.get_onboarding_settings() if settings.get("copilot"): return green('Chatted with the copilot successfully!') - return """Looking for your personal Assistant? Ask it any question! Open the copilot and dive into an exciting conversation with it. Discover the possibilities!""" + return """Looking for your personal Assistant? Ask it any question! Open the Copilot and dive into an exciting conversation with it. Discover the possibilities!""" def share_status(self): settings = self.get_onboarding_settings()